mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
feat: edit database collation
This commit is contained in:
@ -14,6 +14,18 @@ export default connections => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('update-database', async (event, params) => {
|
||||||
|
try {
|
||||||
|
const query = `ALTER DATABASE \`${params.name}\` COLLATE ${params.collation}`;
|
||||||
|
await connections[params.uid].raw(query);
|
||||||
|
|
||||||
|
return { status: 'success' };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return { status: 'error', response: err.toString() };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.handle('delete-database', async (event, params) => {
|
ipcMain.handle('delete-database', async (event, params) => {
|
||||||
try {
|
try {
|
||||||
const query = `DROP DATABASE \`${params.database}\``;
|
const query = `DROP DATABASE \`${params.database}\``;
|
||||||
@ -26,6 +38,18 @@ export default connections => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('get-database-collation', async (event, params) => {
|
||||||
|
try {
|
||||||
|
const query = `SELECT \`DEFAULT_COLLATION_NAME\` FROM \`information_schema\`.\`SCHEMATA\` WHERE \`SCHEMA_NAME\`='${params.database}'`;
|
||||||
|
const collation = await connections[params.uid].raw(query);
|
||||||
|
|
||||||
|
return { status: 'success', response: collation.rows.length ? collation.rows[0].DEFAULT_COLLATION_NAME : '' };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return { status: 'error', response: err.toString() };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.handle('get-structure', async (event, uid) => {
|
ipcMain.handle('get-structure', async (event, uid) => {
|
||||||
try {
|
try {
|
||||||
const structure = await connections[uid].getStructure();
|
const structure = await connections[uid].getStructure();
|
||||||
|
@ -36,6 +36,7 @@ export class MySQLClient extends AntaresCore {
|
|||||||
*/
|
*/
|
||||||
async getStructure () {
|
async getStructure () {
|
||||||
const { rows: databases } = await this.raw('SHOW DATABASES');
|
const { rows: databases } = await this.raw('SHOW DATABASES');
|
||||||
|
// TODO: SHOW TABLE STATUS FROM `{DATABASE_NAME}`;
|
||||||
|
|
||||||
const { rows: tables } = await this
|
const { rows: tables } = await this
|
||||||
.select('*')
|
.select('*')
|
||||||
@ -44,10 +45,30 @@ export class MySQLClient extends AntaresCore {
|
|||||||
.orderBy({ TABLE_SCHEMA: 'ASC', TABLE_NAME: 'ASC' })
|
.orderBy({ TABLE_SCHEMA: 'ASC', TABLE_NAME: 'ASC' })
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
return databases.map(db => {
|
const { rows: functions } = await this.raw('SHOW FUNCTION STATUS');
|
||||||
|
const { rows: procedures } = await this.raw('SHOW PROCEDURE STATUS');
|
||||||
|
const { rows: schedulers } = await this.raw('SELECT *, EVENT_SCHEMA AS `Db`, EVENT_NAME AS `Name` FROM information_schema.`EVENTS`');
|
||||||
|
|
||||||
|
const triggersArr = [];
|
||||||
|
for (const db of databases) {
|
||||||
|
let { rows: triggers } = await this.raw(`SHOW TRIGGERS FROM \`${db.Database}\``);
|
||||||
|
if (triggers.length) {
|
||||||
|
triggers = triggers.map(trigger => {
|
||||||
|
trigger.Db = db.Database;
|
||||||
|
return trigger;
|
||||||
|
});
|
||||||
|
triggersArr.push(...triggers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return databases.map(db => { // TODO: remap all objects,
|
||||||
return {
|
return {
|
||||||
name: db.Database,
|
name: db.Database,
|
||||||
tables: tables.filter(table => table.TABLE_SCHEMA === db.Database)// TODO: remap tables objects
|
tables: tables.filter(table => table.TABLE_SCHEMA === db.Database),
|
||||||
|
functions: functions.filter(func => func.Db === db.Database),
|
||||||
|
procedures: procedures.filter(procedure => procedure.Db === db.Database),
|
||||||
|
triggers: triggersArr.filter(trigger => trigger.Db === db.Database),
|
||||||
|
schedulers: schedulers.filter(scheduler => scheduler.Db === db.Database)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
151
src/renderer/components/ModalEditDatabase.vue
Normal file
151
src/renderer/components/ModalEditDatabase.vue
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<template>
|
||||||
|
<div class="modal active">
|
||||||
|
<a class="modal-overlay" @click.stop="closeModal" />
|
||||||
|
<div class="modal-container p-0">
|
||||||
|
<div class="modal-header pl-2">
|
||||||
|
<div class="modal-title h6">
|
||||||
|
<div class="d-flex">
|
||||||
|
<i class="mdi mdi-24px mdi-database-edit mr-1" /> {{ $t('message.editDatabase') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||||
|
</div>
|
||||||
|
<div class="modal-body pb-0">
|
||||||
|
<div class="content">
|
||||||
|
<form class="form-horizontal">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-3">
|
||||||
|
<label class="form-label">{{ $t('word.name') }}:</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-9">
|
||||||
|
<input
|
||||||
|
v-model="database.name"
|
||||||
|
class="form-input"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
:placeholder="$t('message.databaseName')"
|
||||||
|
readonly
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-3">
|
||||||
|
<label class="form-label">{{ $t('word.collation') }}:</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-9">
|
||||||
|
<select v-model="database.collation" class="form-select">
|
||||||
|
<option
|
||||||
|
v-for="collation in collations"
|
||||||
|
:key="collation.id"
|
||||||
|
:value="collation.collation"
|
||||||
|
>
|
||||||
|
{{ collation.collation }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer text-light">
|
||||||
|
<button class="btn btn-primary mr-2" @click.stop="updateDatabase">
|
||||||
|
{{ $t('word.update') }}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-link" @click.stop="closeModal">
|
||||||
|
{{ $t('word.close') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters, mapActions } from 'vuex';
|
||||||
|
import Database from '@/ipc-api/Database';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ModalEditDatabase',
|
||||||
|
props: {
|
||||||
|
selectedDatabase: String
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
database: {
|
||||||
|
name: '',
|
||||||
|
prevName: '',
|
||||||
|
collation: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
selectedWorkspace: 'workspaces/getSelected',
|
||||||
|
getWorkspace: 'workspaces/getWorkspace',
|
||||||
|
getDatabaseVariable: 'workspaces/getDatabaseVariable'
|
||||||
|
}),
|
||||||
|
collations () {
|
||||||
|
return this.getWorkspace(this.selectedWorkspace).collations;
|
||||||
|
},
|
||||||
|
defaultCollation () {
|
||||||
|
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server').value || '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async created () {
|
||||||
|
let actualCollation;
|
||||||
|
try {
|
||||||
|
const { status, response } = await Database.getDatabaseCollation({ uid: this.selectedWorkspace, database: this.selectedDatabase });
|
||||||
|
|
||||||
|
if (status === 'success')
|
||||||
|
actualCollation = response;
|
||||||
|
|
||||||
|
else
|
||||||
|
this.addNotification({ status: 'error', message: response });
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.addNotification({ status: 'error', message: err.stack });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.database = {
|
||||||
|
name: this.selectedDatabase,
|
||||||
|
prevName: this.selectedDatabase,
|
||||||
|
collation: actualCollation || this.defaultCollation,
|
||||||
|
prevCollation: actualCollation || this.defaultCollation
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions({
|
||||||
|
addNotification: 'notifications/addNotification'
|
||||||
|
}),
|
||||||
|
async updateDatabase () {
|
||||||
|
if (this.database.collation !== this.database.prevCollation) {
|
||||||
|
try {
|
||||||
|
const { status, response } = await Database.updateDatabase({
|
||||||
|
uid: this.selectedWorkspace,
|
||||||
|
...this.database
|
||||||
|
});
|
||||||
|
|
||||||
|
if (status === 'success')
|
||||||
|
this.closeModal();
|
||||||
|
else
|
||||||
|
this.addNotification({ status: 'error', message: response });
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.addNotification({ status: 'error', message: err.stack });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.closeModal();
|
||||||
|
},
|
||||||
|
closeModal () {
|
||||||
|
this.$emit('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.modal-container {
|
||||||
|
max-width: 360px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -64,7 +64,7 @@ import { mapGetters, mapActions } from 'vuex';
|
|||||||
import Database from '@/ipc-api/Database';
|
import Database from '@/ipc-api/Database';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ModalNewDB',
|
name: 'ModalNewDatabase',
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
database: {
|
database: {
|
@ -42,7 +42,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ModalNewDB
|
<ModalNewDatabase
|
||||||
v-if="isNewDBModal"
|
v-if="isNewDBModal"
|
||||||
@close="hideNewDBModal"
|
@close="hideNewDBModal"
|
||||||
@reload="refresh"
|
@reload="refresh"
|
||||||
@ -63,7 +63,7 @@ import _ from 'lodash';
|
|||||||
import WorkspaceConnectPanel from '@/components/WorkspaceConnectPanel';
|
import WorkspaceConnectPanel from '@/components/WorkspaceConnectPanel';
|
||||||
import WorkspaceExploreBarDatabase from '@/components/WorkspaceExploreBarDatabase';
|
import WorkspaceExploreBarDatabase from '@/components/WorkspaceExploreBarDatabase';
|
||||||
import DatabaseContext from '@/components/WorkspaceExploreBarDatabaseContext';
|
import DatabaseContext from '@/components/WorkspaceExploreBarDatabaseContext';
|
||||||
import ModalNewDB from '@/components/ModalNewDB';
|
import ModalNewDatabase from '@/components/ModalNewDatabase';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'WorkspaceExploreBar',
|
name: 'WorkspaceExploreBar',
|
||||||
@ -71,7 +71,7 @@ export default {
|
|||||||
WorkspaceConnectPanel,
|
WorkspaceConnectPanel,
|
||||||
WorkspaceExploreBarDatabase,
|
WorkspaceExploreBarDatabase,
|
||||||
DatabaseContext,
|
DatabaseContext,
|
||||||
ModalNewDB
|
ModalNewDatabase
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
connection: Object,
|
connection: Object,
|
||||||
@ -131,7 +131,6 @@ export default {
|
|||||||
changeExplorebarSize: 'settings/changeExplorebarSize'
|
changeExplorebarSize: 'settings/changeExplorebarSize'
|
||||||
}),
|
}),
|
||||||
async refresh () {
|
async refresh () {
|
||||||
console.log('refresh');
|
|
||||||
if (!this.isRefreshing) {
|
if (!this.isRefreshing) {
|
||||||
this.isRefreshing = true;
|
this.isRefreshing = true;
|
||||||
await this.refreshStructure(this.connection.uid);
|
await this.refreshStructure(this.connection.uid);
|
||||||
|
@ -7,17 +7,17 @@
|
|||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-plus text-light pr-1" /> {{ $t('word.add') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-plus text-light pr-1" /> {{ $t('word.add') }}</span>
|
||||||
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
|
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="context-element">
|
<div class="context-element" @click="showEditModal">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-pencil text-light pr-1" /> {{ $t('word.edit') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-pencil text-light pr-1" /> {{ $t('word.edit') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-element" @click="showConfirmModal">
|
<div class="context-element" @click="showDeleteModal">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-delete text-light pr-1" /> {{ $t('word.delete') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-delete text-light pr-1" /> {{ $t('word.delete') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
v-if="isConfirmModal"
|
v-if="isDeleteModal"
|
||||||
@confirm="deleteDatabase"
|
@confirm="deleteDatabase"
|
||||||
@hide="hideConfirmModal"
|
@hide="hideDeleteModal"
|
||||||
>
|
>
|
||||||
<template slot="header">
|
<template slot="header">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
@ -30,6 +30,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ConfirmModal>
|
</ConfirmModal>
|
||||||
|
<ModalEditDatabase
|
||||||
|
v-if="isEditModal"
|
||||||
|
:selected-database="selectedDatabase"
|
||||||
|
@close="hideEditModal"
|
||||||
|
/>
|
||||||
</BaseContextMenu>
|
</BaseContextMenu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -37,13 +42,15 @@
|
|||||||
import { mapGetters, mapActions } from 'vuex';
|
import { mapGetters, mapActions } from 'vuex';
|
||||||
import BaseContextMenu from '@/components/BaseContextMenu';
|
import BaseContextMenu from '@/components/BaseContextMenu';
|
||||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||||
|
import ModalEditDatabase from '@/components/ModalEditDatabase';
|
||||||
import Database from '@/ipc-api/Database';
|
import Database from '@/ipc-api/Database';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'WorkspaceExploreBarDatabaseContext',
|
name: 'WorkspaceExploreBarDatabaseContext',
|
||||||
components: {
|
components: {
|
||||||
BaseContextMenu,
|
BaseContextMenu,
|
||||||
ConfirmModal
|
ConfirmModal,
|
||||||
|
ModalEditDatabase
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
contextEvent: MouseEvent,
|
contextEvent: MouseEvent,
|
||||||
@ -51,7 +58,8 @@ export default {
|
|||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
isConfirmModal: false
|
isDeleteModal: false,
|
||||||
|
isEditModal: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -65,11 +73,18 @@ export default {
|
|||||||
showEditModal: 'application/showEditConnModal',
|
showEditModal: 'application/showEditConnModal',
|
||||||
addNotification: 'notifications/addNotification'
|
addNotification: 'notifications/addNotification'
|
||||||
}),
|
}),
|
||||||
showConfirmModal () {
|
showDeleteModal () {
|
||||||
this.isConfirmModal = true;
|
this.isDeleteModal = true;
|
||||||
},
|
},
|
||||||
hideConfirmModal () {
|
hideDeleteModal () {
|
||||||
this.isConfirmModal = false;
|
this.isDeleteModal = false;
|
||||||
|
},
|
||||||
|
showEditModal () {
|
||||||
|
this.isEditModal = true;
|
||||||
|
},
|
||||||
|
hideEditModal () {
|
||||||
|
this.isEditModal = false;
|
||||||
|
this.closeContext();
|
||||||
},
|
},
|
||||||
closeContext () {
|
closeContext () {
|
||||||
this.$emit('close-context');
|
this.$emit('close-context');
|
||||||
|
@ -6,6 +6,14 @@ export default class {
|
|||||||
return ipcRenderer.invoke('create-database', params);
|
return ipcRenderer.invoke('create-database', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static updateDatabase (params) {
|
||||||
|
return ipcRenderer.invoke('update-database', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDatabaseCollation (params) {
|
||||||
|
return ipcRenderer.invoke('get-database-collation', params);
|
||||||
|
}
|
||||||
|
|
||||||
static deleteDatabase (params) {
|
static deleteDatabase (params) {
|
||||||
return ipcRenderer.invoke('delete-database', params);
|
return ipcRenderer.invoke('delete-database', params);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user