diff --git a/resources/assets/scripts/api/server/createDatabase.ts b/resources/assets/scripts/api/server/createDatabase.ts new file mode 100644 index 000000000..c0acd5128 --- /dev/null +++ b/resources/assets/scripts/api/server/createDatabase.ts @@ -0,0 +1,30 @@ +import http from '@/api/http'; +// @ts-ignore +import route from '../../../../../vendor/tightenco/ziggy/src/js/route'; +import {AxiosError} from "axios"; +import {ServerDatabase} from "@/api/server/types"; + +/** + * Creates a new database on the system for the currently active server. + */ +export function createDatabase(server: string, database: string, remote: string): Promise { + return new Promise((resolve, reject) => { + http.post(route('api.client.servers.databases', { server }), {database, remote}) + .then(response => { + const copy: any = response.data.attributes; + copy.password = copy.relationships.password.attributes.password; + copy.showPassword = false; + + delete copy.relationships; + + resolve(copy); + }) + .catch((err: AxiosError) => { + if (err.response && err.response.data && Array.isArray(err.response.data.errors)) { + return reject(err.response.data.errors[0].detail); + } + + return reject(err); + }); + }); +} diff --git a/resources/assets/scripts/api/server/types.ts b/resources/assets/scripts/api/server/types.ts index 7b220c1ef..8294868b9 100644 --- a/resources/assets/scripts/api/server/types.ts +++ b/resources/assets/scripts/api/server/types.ts @@ -3,3 +3,16 @@ export type DirectoryContents = { directories: Array, editable: Array } + +export type ServerDatabase = { + id: string, + name: string, + connections_from: string, + username: string, + host: { + address: string, + port: number, + }, + password: string, + showPassword: boolean, +} diff --git a/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.ts b/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.ts new file mode 100644 index 000000000..a8214a2c0 --- /dev/null +++ b/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.ts @@ -0,0 +1,86 @@ +import Vue from 'vue'; +import MessageBox from "@/components/MessageBox"; +import {createDatabase} from "@/api/server/createDatabase"; + +export default Vue.component('CreateDatabaseModal', { + components: {MessageBox}, + + data: function () { + return { + loading: false, + showSpinner: false, + database: '', + remote: '%', + errorMessage: '', + }; + }, + + computed: { + canSubmit: function () { + return this.database.length && this.remote.length; + }, + }, + + methods: { + submit: function () { + this.showSpinner = true; + this.errorMessage = ''; + this.loading = true; + + createDatabase(this.$route.params.id, this.database, this.remote) + .then((response) => { + this.$emit('database', response); + this.$emit('close'); + }) + .catch((err: Error | string): void => { + if (typeof err === 'string') { + this.errorMessage = err; + return; + } + + console.error('A network error was encountered while processing this request.', { err }); + }) + .then(() => { + this.loading = false; + this.showSpinner = false; + }); + } + }, + + template: ` +
+ +

Create a new database

+
+ + +

{{ errors.first('database_name') }}

+
+
+ + +

{{ errors.first('remote') }}

+
+
+ + +
+
+ ` +}); diff --git a/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.vue b/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.vue deleted file mode 100644 index 343e0f524..000000000 --- a/resources/assets/scripts/components/server/components/database/CreateDatabaseModal.vue +++ /dev/null @@ -1,89 +0,0 @@ - - - - diff --git a/resources/assets/scripts/components/server/components/database/DatabaseRow.ts b/resources/assets/scripts/components/server/components/database/DatabaseRow.ts new file mode 100644 index 000000000..d49bbfa6d --- /dev/null +++ b/resources/assets/scripts/components/server/components/database/DatabaseRow.ts @@ -0,0 +1,70 @@ +import Vue from 'vue'; +import Icon from "@/components/core/Icon"; +import Modal from "@/components/core/Modal"; +import {ServerDatabase} from "@/api/server/types"; +import DeleteDatabaseModal from "@/components/server/components/database/DeleteDatabaseModal"; + +export default Vue.component('DatabaseRow', { + components: {DeleteDatabaseModal, Modal, Icon}, + props: { + database: { + type: Object as () => ServerDatabase, + required: true, + } + }, + + data: function () { + return { + showDeleteModal: false, + }; + }, + + methods: { + revealPassword: function () { + this.database.showPassword = !this.database.showPassword; + }, + }, + + template: ` +
+
+ +
+

Database Name

+

{{database.name}}

+
+
+

Username

+

{{database.username}}

+
+
+

Password

+

+ + + •••••• + + {{database.password}} + +

+
+
+

Server

+

{{database.host.address}}:{{database.host.port}}

+
+
+ +
+
+ + + +
+ `, +}) diff --git a/resources/assets/scripts/components/server/components/database/DatabaseRow.vue b/resources/assets/scripts/components/server/components/database/DatabaseRow.vue deleted file mode 100644 index 221e166de..000000000 --- a/resources/assets/scripts/components/server/components/database/DatabaseRow.vue +++ /dev/null @@ -1,68 +0,0 @@ - - - diff --git a/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.ts b/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.ts new file mode 100644 index 000000000..ae5d3872f --- /dev/null +++ b/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.ts @@ -0,0 +1,84 @@ +import Vue from 'vue'; +import {ServerDatabase} from "@/api/server/types"; + +export default Vue.component('DeleteDatabaseModal', { + props: { + database: { + type: Object as () => ServerDatabase, + required: true + }, + }, + + data: function () { + return { + showSpinner: false, + nameConfirmation: '', + }; + }, + + computed: { + /** + * Determine if the 'Delete' button should be enabled or not. This requires the user + * to enter the database name before actually deleting the DB. + */ + disabled: function () { + const splits: Array = this.database.name.split('_'); + + return ( + this.nameConfirmation !== this.database.name && this.nameConfirmation !== splits.slice(1).join('_') + ); + } + }, + + methods: { + /** + * Handle deleting the database for the server instance. + */ + deleteDatabase: function () { + this.nameConfirmation = ''; + this.showSpinner = true; + + window.axios.delete(this.route('api.client.servers.databases.delete', { + server: this.$route.params.id, + database: this.database.id, + })) + .then(() => { + window.events.$emit('server:deleted-database', this.database.id); + }) + .catch(err => { + this.$flash.clear(); + console.error({ err }); + + const response = err.response; + if (response.data && typeof response.data.errors === 'object') { + response.data.errors.forEach((error: any) => { + this.$flash.error(error.detail); + }); + } + }) + .then(() => { + this.$emit('close'); + }) + }, + }, + + template: ` +
+

Delete this database?

+

This action cannot be undone. This will permanetly delete the {{database.name}} database and remove all associated data.

+
+ + +
+
+ + +
+
+ `, +}); diff --git a/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.vue b/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.vue deleted file mode 100644 index 4281d5dd6..000000000 --- a/resources/assets/scripts/components/server/components/database/DeleteDatabaseModal.vue +++ /dev/null @@ -1,81 +0,0 @@ - - - - diff --git a/resources/assets/scripts/components/server/subpages/Databases.ts b/resources/assets/scripts/components/server/subpages/Databases.ts index 6bfb10fa0..164275fbd 100644 --- a/resources/assets/scripts/components/server/subpages/Databases.ts +++ b/resources/assets/scripts/components/server/subpages/Databases.ts @@ -1,14 +1,15 @@ import Vue from 'vue'; import { map, filter } from 'lodash'; import Modal from '@/components/core/Modal'; -import CreateDatabaseModal from './../components/database/CreateDatabaseModal.vue'; -import DatabaseRow from './../components/database/DatabaseRow.vue'; +import CreateDatabaseModal from './../components/database/CreateDatabaseModal'; import Icon from "@/components/core/Icon"; +import {ServerDatabase} from "@/api/server/types"; +import DatabaseRow from "@/components/server/components/database/DatabaseRow"; type DataStructure = { loading: boolean, showCreateModal: boolean, - databases: Array, + databases: Array, } export default Vue.component('server-databases', { @@ -64,20 +65,14 @@ export default Vue.component('server-databases', { * Add the database to the list of existing databases automatically when the modal * is closed with a successful callback. */ - handleModalCallback: function (object: any) { - const data = object; - data.password = data.relationships.password.attributes.password; - data.showPassword = false; - - delete data.relationships; - + handleModalCallback: function (data: ServerDatabase) { this.databases.push(data); }, /** * Handle event that is removing a database. */ - removeDatabase: function (databaseId: number) { + removeDatabase: function (databaseId: string) { this.databases = filter(this.databases, (database) => { return database.id !== databaseId; }); @@ -99,13 +94,13 @@ export default Vue.component('server-databases', {
- +
-