mirror of https://github.com/Fabio286/antares.git
feat: triggers edit
This commit is contained in:
parent
ab307f82b1
commit
3126625461
|
@ -1,6 +1,7 @@
|
||||||
import connection from './connection';
|
import connection from './connection';
|
||||||
import tables from './tables';
|
import tables from './tables';
|
||||||
import views from './views';
|
import views from './views';
|
||||||
|
import triggers from './triggers';
|
||||||
import updates from './updates';
|
import updates from './updates';
|
||||||
import application from './application';
|
import application from './application';
|
||||||
import database from './database';
|
import database from './database';
|
||||||
|
@ -12,6 +13,7 @@ export default () => {
|
||||||
connection(connections);
|
connection(connections);
|
||||||
tables(connections);
|
tables(connections);
|
||||||
views(connections);
|
views(connections);
|
||||||
|
triggers(connections);
|
||||||
database(connections);
|
database(connections);
|
||||||
users(connections);
|
users(connections);
|
||||||
updates();
|
updates();
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { ipcMain } from 'electron';
|
||||||
|
|
||||||
|
export default (connections) => {
|
||||||
|
ipcMain.handle('get-trigger-informations', async (event, params) => {
|
||||||
|
try {
|
||||||
|
const result = await connections[params.uid].getTriggerInformations(params);
|
||||||
|
return { status: 'success', response: result };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return { status: 'error', response: err.toString() };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('drop-trigger', async (event, params) => {
|
||||||
|
try {
|
||||||
|
await connections[params.uid].dropTrigger(params);
|
||||||
|
return { status: 'success' };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return { status: 'error', response: err.toString() };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('alter-trigger', async (event, params) => {
|
||||||
|
try {
|
||||||
|
await connections[params.uid].alterTrigger(params);
|
||||||
|
return { status: 'success' };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return { status: 'error', response: err.toString() };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('create-trigger', async (event, params) => {
|
||||||
|
try {
|
||||||
|
await connections[params.uid].createTrigger(params);
|
||||||
|
return { status: 'success' };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return { status: 'error', response: err.toString() };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -311,7 +311,7 @@ export class MySQLClient extends AntaresCore {
|
||||||
* @memberof MySQLClient
|
* @memberof MySQLClient
|
||||||
*/
|
*/
|
||||||
async dropView (params) {
|
async dropView (params) {
|
||||||
const sql = `DROP VIEW \`${params.view}\``;// TODO: schema
|
const sql = `DROP VIEW \`${params.view}\``;
|
||||||
return await this.raw(sql);
|
return await this.raw(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +342,72 @@ export class MySQLClient extends AntaresCore {
|
||||||
return await this.raw(sql);
|
return await this.raw(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHOW CREATE TRIGGER
|
||||||
|
*
|
||||||
|
* @returns {Array.<Object>} view informations
|
||||||
|
* @memberof MySQLClient
|
||||||
|
*/
|
||||||
|
async getTriggerInformations ({ schema, trigger }) {
|
||||||
|
const sql = `SHOW CREATE TRIGGER \`${schema}\`.\`${trigger}\``;
|
||||||
|
const results = await this.raw(sql);
|
||||||
|
|
||||||
|
return results.rows.map(row => {
|
||||||
|
return {
|
||||||
|
definer: row['SQL Original Statement'].match(/(?<=DEFINER=).*?(?=\s)/gs)[0],
|
||||||
|
sql: row['SQL Original Statement'].match(/BEGIN(.*)END/gs)[0],
|
||||||
|
name: row.Trigger,
|
||||||
|
table: row['SQL Original Statement'].match(/(?<=ON `).*?(?=`)/gs)[0],
|
||||||
|
event1: row['SQL Original Statement'].match(/(BEFORE|AFTER)/gs)[0],
|
||||||
|
event2: row['SQL Original Statement'].match(/(INSERT|UPDATE|DELETE)/gs)[0]
|
||||||
|
};
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DROP TRIGGER
|
||||||
|
*
|
||||||
|
* @returns {Array.<Object>} parameters
|
||||||
|
* @memberof MySQLClient
|
||||||
|
*/
|
||||||
|
async dropTrigger (params) {
|
||||||
|
const sql = `DROP TRIGGER \`${params.trigger}\``;
|
||||||
|
return await this.raw(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ALTER TRIGGER
|
||||||
|
*
|
||||||
|
* @returns {Array.<Object>} parameters
|
||||||
|
* @memberof MySQLClient
|
||||||
|
*/
|
||||||
|
async alterTrigger (params) {
|
||||||
|
const { trigger } = params;
|
||||||
|
const tempTrigger = Object.assign({}, trigger);
|
||||||
|
tempTrigger.name = `Antares_${tempTrigger.name}_tmp`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.createTrigger(tempTrigger);
|
||||||
|
await this.dropTrigger({ trigger: tempTrigger.name });
|
||||||
|
await this.dropTrigger({ trigger: trigger.oldName });
|
||||||
|
await this.createTrigger(trigger);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CREATE TRIGGER
|
||||||
|
*
|
||||||
|
* @returns {Array.<Object>} parameters
|
||||||
|
* @memberof MySQLClient
|
||||||
|
*/
|
||||||
|
async createTrigger (trigger) {
|
||||||
|
const sql = `CREATE ${trigger.definer ? `DEFINER=${trigger.definer} ` : ''}TRIGGER \`${trigger.name}\` ${trigger.event1} ${trigger.event2} ON \`${trigger.table}\` FOR EACH ROW ${trigger.sql}`;
|
||||||
|
return await this.raw(sql);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SHOW COLLATION
|
* SHOW COLLATION
|
||||||
*
|
*
|
||||||
|
@ -573,7 +639,7 @@ export class MySQLClient extends AntaresCore {
|
||||||
* @memberof MySQLClient
|
* @memberof MySQLClient
|
||||||
*/
|
*/
|
||||||
async dropTable (params) {
|
async dropTable (params) {
|
||||||
const sql = `DROP TABLE \`${params.table}\``;// TODO: schema
|
const sql = `DROP TABLE \`${params.table}\``;
|
||||||
return await this.raw(sql);
|
return await this.raw(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,12 @@
|
||||||
:connection="connection"
|
:connection="connection"
|
||||||
:view="workspace.breadcrumbs.view"
|
:view="workspace.breadcrumbs.view"
|
||||||
/>
|
/>
|
||||||
|
<WorkspacePropsTabTrigger
|
||||||
|
v-show="selectedTab === 'prop' && workspace.breadcrumbs.trigger"
|
||||||
|
:is-selected="selectedTab === 'prop'"
|
||||||
|
:connection="connection"
|
||||||
|
:trigger="workspace.breadcrumbs.trigger"
|
||||||
|
/>
|
||||||
<WorkspaceTableTab
|
<WorkspaceTableTab
|
||||||
v-show="selectedTab === 'data'"
|
v-show="selectedTab === 'data'"
|
||||||
:connection="connection"
|
:connection="connection"
|
||||||
|
@ -101,6 +107,7 @@ import WorkspaceQueryTab from '@/components/WorkspaceQueryTab';
|
||||||
import WorkspaceTableTab from '@/components/WorkspaceTableTab';
|
import WorkspaceTableTab from '@/components/WorkspaceTableTab';
|
||||||
import WorkspacePropsTab from '@/components/WorkspacePropsTab';
|
import WorkspacePropsTab from '@/components/WorkspacePropsTab';
|
||||||
import WorkspacePropsTabView from '@/components/WorkspacePropsTabView';
|
import WorkspacePropsTabView from '@/components/WorkspacePropsTabView';
|
||||||
|
import WorkspacePropsTabTrigger from '@/components/WorkspacePropsTabTrigger';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Workspace',
|
name: 'Workspace',
|
||||||
|
@ -109,7 +116,8 @@ export default {
|
||||||
WorkspaceQueryTab,
|
WorkspaceQueryTab,
|
||||||
WorkspaceTableTab,
|
WorkspaceTableTab,
|
||||||
WorkspacePropsTab,
|
WorkspacePropsTab,
|
||||||
WorkspacePropsTabView
|
WorkspacePropsTabView,
|
||||||
|
WorkspacePropsTabTrigger
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
connection: Object
|
connection: Object
|
||||||
|
@ -131,7 +139,14 @@ export default {
|
||||||
return this.selectedWorkspace === this.connection.uid;
|
return this.selectedWorkspace === this.connection.uid;
|
||||||
},
|
},
|
||||||
selectedTab () {
|
selectedTab () {
|
||||||
if (this.workspace.breadcrumbs.table === null && this.workspace.breadcrumbs.view === null && ['data', 'prop'].includes(this.workspace.selected_tab))
|
if (
|
||||||
|
this.workspace.breadcrumbs.table === null &&
|
||||||
|
this.workspace.breadcrumbs.view === null &&
|
||||||
|
this.workspace.breadcrumbs.trigger === null &&
|
||||||
|
this.workspace.breadcrumbs.procedure === null &&
|
||||||
|
this.workspace.breadcrumbs.scheduler === null &&
|
||||||
|
['data', 'prop'].includes(this.workspace.selected_tab)
|
||||||
|
)
|
||||||
return this.queryTabs[0].uid;
|
return this.queryTabs[0].uid;
|
||||||
|
|
||||||
return this.queryTabs.find(tab => tab.uid === this.workspace.selected_tab) ||
|
return this.queryTabs.find(tab => tab.uid === this.workspace.selected_tab) ||
|
||||||
|
|
|
@ -35,6 +35,90 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="database.triggers.length" class="database-misc">
|
||||||
|
<details class="accordion">
|
||||||
|
<summary class="accordion-header misc-name" :class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.trigger}">
|
||||||
|
<i class="misc-icon mdi mdi-18px mdi-folder-cog mr-1" />
|
||||||
|
{{ $tc('word.trigger', 2) }}
|
||||||
|
</summary>
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div>
|
||||||
|
<ul class="menu menu-nav pt-0">
|
||||||
|
<li
|
||||||
|
v-for="trigger of database.triggers"
|
||||||
|
:key="trigger.name"
|
||||||
|
class="menu-item"
|
||||||
|
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.trigger === trigger.name}"
|
||||||
|
@click="setBreadcrumbs({schema: database.name, trigger: trigger.name})"
|
||||||
|
@contextmenu.prevent="showTableContext($event, trigger)"
|
||||||
|
>
|
||||||
|
<a class="table-name">
|
||||||
|
<i class="table-icon mdi mdi-table-cog mdi-18px mr-1" />
|
||||||
|
<span>{{ trigger.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="database.procedures.length" class="database-misc">
|
||||||
|
<details class="accordion">
|
||||||
|
<summary class="accordion-header misc-name" :class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.procedure}">
|
||||||
|
<i class="misc-icon mdi mdi-18px mdi-folder-move mr-1" />
|
||||||
|
{{ $tc('word.storedRoutine', 2) }}
|
||||||
|
</summary>
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div>
|
||||||
|
<ul class="menu menu-nav pt-0">
|
||||||
|
<li
|
||||||
|
v-for="procedure of database.procedures"
|
||||||
|
:key="procedure.name"
|
||||||
|
class="menu-item"
|
||||||
|
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.procedure === procedure.name}"
|
||||||
|
@click="setBreadcrumbs({schema: database.name, procedure: procedure.name})"
|
||||||
|
@contextmenu.prevent="showTableContext($event, procedure)"
|
||||||
|
>
|
||||||
|
<a class="table-name">
|
||||||
|
<i class="table-icon mdi mdi-arrow-right-bold-box mdi-18px mr-1" />
|
||||||
|
<span>{{ procedure.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="database.schedulers.length" class="database-misc">
|
||||||
|
<details class="accordion">
|
||||||
|
<summary class="accordion-header misc-name" :class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.scheduler}">
|
||||||
|
<i class="misc-icon mdi mdi-18px mdi-folder-clock mr-1" />
|
||||||
|
{{ $tc('word.scheduler', 2) }}
|
||||||
|
</summary>
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div>
|
||||||
|
<ul class="menu menu-nav pt-0">
|
||||||
|
<li
|
||||||
|
v-for="scheduler of database.schedulers"
|
||||||
|
:key="scheduler.name"
|
||||||
|
class="menu-item"
|
||||||
|
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.scheduler === scheduler.name}"
|
||||||
|
@click="setBreadcrumbs({schema: database.name, scheduler: scheduler.name})"
|
||||||
|
@contextmenu.prevent="showTableContext($event, scheduler)"
|
||||||
|
>
|
||||||
|
<a class="table-name">
|
||||||
|
<i class="table-icon mdi mdi-calendar-clock mdi-18px mr-1" />
|
||||||
|
<span>{{ scheduler.name }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</template>
|
</template>
|
||||||
|
@ -72,9 +156,11 @@ export default {
|
||||||
}),
|
}),
|
||||||
formatBytes,
|
formatBytes,
|
||||||
showDatabaseContext (event, database) {
|
showDatabaseContext (event, database) {
|
||||||
|
this.changeBreadcrumbs({ schema: database, table: null });
|
||||||
this.$emit('show-database-context', { event, database });
|
this.$emit('show-database-context', { event, database });
|
||||||
},
|
},
|
||||||
showTableContext (event, table) {
|
showTableContext (event, table) {
|
||||||
|
this.setBreadcrumbs({ schema: this.database.name, [table.type]: table.name });
|
||||||
this.$emit('show-table-context', { event, table });
|
this.$emit('show-table-context', { event, table });
|
||||||
},
|
},
|
||||||
piePercentage (val) {
|
piePercentage (val) {
|
||||||
|
@ -92,6 +178,7 @@ export default {
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.workspace-explorebar-database {
|
.workspace-explorebar-database {
|
||||||
.database-name,
|
.database-name,
|
||||||
|
.misc-name,
|
||||||
a.table-name {
|
a.table-name {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -107,12 +194,20 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.database-icon,
|
.database-icon,
|
||||||
.table-icon {
|
.table-icon,
|
||||||
|
.misc-icon {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.database-name {
|
.misc-name {
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0.1rem 1rem 0.1rem 0.1rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.database-name,
|
||||||
|
.misc-name {
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $body-font-color;
|
color: $body-font-color;
|
||||||
background: rgba($color: #fff, $alpha: 0.05);
|
background: rgba($color: #fff, $alpha: 0.05);
|
||||||
|
@ -142,6 +237,18 @@ export default {
|
||||||
margin-left: 1.2rem;
|
margin-left: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.database-misc {
|
||||||
|
margin-left: 1.6rem;
|
||||||
|
|
||||||
|
.accordion[open] .accordion-header > .misc-icon:first-child::before {
|
||||||
|
content: "\F0770";
|
||||||
|
}
|
||||||
|
|
||||||
|
.accordion-body {
|
||||||
|
margin-bottom: 0.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.table-size {
|
.table-size {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|
|
@ -13,14 +13,14 @@
|
||||||
<div class="context-element" @click="showCreateViewModal">
|
<div class="context-element" @click="showCreateViewModal">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-table-eye text-light pr-1" /> {{ $t('word.view') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-table-eye text-light pr-1" /> {{ $t('word.view') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-element d-none" @click="false">
|
<div class="context-element" @click="false">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-table-cog text-light pr-1" /> {{ $t('word.trigger') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-table-cog text-light pr-1" /> {{ $tc('word.trigger', 1) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-element d-none" @click="false">
|
<div class="context-element d-none" @click="false">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-cog-box pr-1" /> {{ $t('word.storedRoutine') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-arrow-right-bold-box pr-1" /> {{ $tc('word.storedRoutine', 1) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-element d-none" @click="false">
|
<div class="context-element d-none" @click="false">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-calendar-clock text-light pr-1" /> {{ $t('word.scheduler') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-calendar-clock text-light pr-1" /> {{ $tc('word.scheduler', 1) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,275 @@
|
||||||
|
<template>
|
||||||
|
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||||
|
<div class="workspace-query-runner column col-12">
|
||||||
|
<div class="workspace-query-runner-footer">
|
||||||
|
<div class="workspace-query-buttons">
|
||||||
|
<button
|
||||||
|
class="btn btn-primary btn-sm"
|
||||||
|
:disabled="!isChanged"
|
||||||
|
:class="{'loading':isSaving}"
|
||||||
|
@click="saveChanges"
|
||||||
|
>
|
||||||
|
<span>{{ $t('word.save') }}</span>
|
||||||
|
<i class="mdi mdi-24px mdi-content-save ml-1" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:disabled="!isChanged"
|
||||||
|
class="btn btn-link btn-sm mr-0"
|
||||||
|
:title="$t('message.clearChanges')"
|
||||||
|
@click="clearChanges"
|
||||||
|
>
|
||||||
|
<span>{{ $t('word.clear') }}</span>
|
||||||
|
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="columns mb-4">
|
||||||
|
<div class="column col-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">{{ $t('word.name') }}</label>
|
||||||
|
<input
|
||||||
|
v-model="localTrigger.name"
|
||||||
|
class="form-input"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="column col-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">{{ $t('word.definer') }}</label>
|
||||||
|
<select
|
||||||
|
v-if="workspace.users.length"
|
||||||
|
v-model="localTrigger.definer"
|
||||||
|
class="form-select"
|
||||||
|
>
|
||||||
|
<option value="">
|
||||||
|
{{ $t('message.currentUser') }}
|
||||||
|
</option>
|
||||||
|
<option v-if="!isDefinerInUsers" :value="originalTrigger.definer">
|
||||||
|
{{ originalTrigger.definer.replaceAll('`', '') }}
|
||||||
|
</option>
|
||||||
|
<option
|
||||||
|
v-for="user in workspace.users"
|
||||||
|
:key="`${user.name}@${user.host}`"
|
||||||
|
:value="`\`${user.name}\`@\`${user.host}\``"
|
||||||
|
>
|
||||||
|
{{ user.name }}@{{ user.host }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<select v-if="!workspace.users.length" class="form-select">
|
||||||
|
<option value="">
|
||||||
|
{{ $t('message.currentUser') }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column col-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">{{ $t('word.table') }}</label>
|
||||||
|
<select v-model="localTrigger.table" class="form-select">
|
||||||
|
<option v-for="table in schemaTables" :key="table.name">
|
||||||
|
{{ table.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="column col-3">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">{{ $t('word.event') }}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<select v-model="localTrigger.event1" class="form-select">
|
||||||
|
<option>BEFORE</option>
|
||||||
|
<option>AFTER</option>
|
||||||
|
</select>
|
||||||
|
<select v-model="localTrigger.event2" class="form-select">
|
||||||
|
<option>INSERT</option>
|
||||||
|
<option>UPDATE</option>
|
||||||
|
<option>DELETE</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="workspace-query-results column col-12 mt-2">
|
||||||
|
<label class="form-label ml-2">{{ $t('message.triggerStatement') }}</label>
|
||||||
|
<QueryEditor
|
||||||
|
v-if="isSelected"
|
||||||
|
ref="queryEditor"
|
||||||
|
:value.sync="localTrigger.sql"
|
||||||
|
:workspace="workspace"
|
||||||
|
:schema="schema"
|
||||||
|
:height="editorHeight"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters, mapActions } from 'vuex';
|
||||||
|
import QueryEditor from '@/components/QueryEditor';
|
||||||
|
import Triggers from '@/ipc-api/Triggers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'WorkspacePropsTabTrigger',
|
||||||
|
components: {
|
||||||
|
QueryEditor
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
connection: Object,
|
||||||
|
trigger: String
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
tabUid: 'prop',
|
||||||
|
isQuering: false,
|
||||||
|
isSaving: false,
|
||||||
|
originalTrigger: null,
|
||||||
|
localTrigger: { sql: '' },
|
||||||
|
lastTrigger: null,
|
||||||
|
sqlProxy: '',
|
||||||
|
editorHeight: 300
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
getWorkspace: 'workspaces/getWorkspace'
|
||||||
|
}),
|
||||||
|
workspace () {
|
||||||
|
return this.getWorkspace(this.connection.uid);
|
||||||
|
},
|
||||||
|
isSelected () {
|
||||||
|
return this.workspace.selected_tab === 'prop';
|
||||||
|
},
|
||||||
|
schema () {
|
||||||
|
return this.workspace.breadcrumbs.schema;
|
||||||
|
},
|
||||||
|
isChanged () {
|
||||||
|
return JSON.stringify(this.originalTrigger) !== JSON.stringify(this.localTrigger);
|
||||||
|
},
|
||||||
|
isDefinerInUsers () {
|
||||||
|
return this.originalTrigger ? this.workspace.users.some(user => this.originalTrigger.definer === `\`${user.name}\`@\`${user.host}\``) : true;
|
||||||
|
},
|
||||||
|
schemaTables () {
|
||||||
|
const schemaTables = this.workspace.structure
|
||||||
|
.filter(schema => schema.name === this.schema)
|
||||||
|
.map(schema => schema.tables);
|
||||||
|
|
||||||
|
return schemaTables.length ? schemaTables[0].filter(table => table.type === 'table') : [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
async trigger () {
|
||||||
|
if (this.isSelected) {
|
||||||
|
await this.getTriggerData();
|
||||||
|
this.$refs.queryEditor.editor.session.setValue(this.localTrigger.sql);
|
||||||
|
this.lastTrigger = this.trigger;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async isSelected (val) {
|
||||||
|
if (val && this.lastTrigger !== this.trigger) {
|
||||||
|
await this.getTriggerData();
|
||||||
|
this.$refs.queryEditor.editor.session.setValue(this.localTrigger.sql);
|
||||||
|
this.lastTrigger = this.trigger;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isChanged (val) {
|
||||||
|
if (this.isSelected && this.lastTrigger === this.trigger && this.trigger !== null)
|
||||||
|
this.setUnsavedChanges(val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
window.addEventListener('resize', this.resizeQueryEditor);
|
||||||
|
},
|
||||||
|
destroyed () {
|
||||||
|
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions({
|
||||||
|
addNotification: 'notifications/addNotification',
|
||||||
|
refreshStructure: 'workspaces/refreshStructure',
|
||||||
|
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||||
|
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||||
|
}),
|
||||||
|
async getTriggerData () {
|
||||||
|
if (!this.trigger) return;
|
||||||
|
this.isQuering = true;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
uid: this.connection.uid,
|
||||||
|
schema: this.schema,
|
||||||
|
trigger: this.workspace.breadcrumbs.trigger
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { status, response } = await Triggers.getTriggerInformations(params);
|
||||||
|
if (status === 'success') {
|
||||||
|
this.originalTrigger = response;
|
||||||
|
this.localTrigger = JSON.parse(JSON.stringify(this.originalTrigger));
|
||||||
|
this.sqlProxy = this.localTrigger.sql;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.addNotification({ status: 'error', message: response });
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.addNotification({ status: 'error', message: err.stack });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resizeQueryEditor();
|
||||||
|
this.isQuering = false;
|
||||||
|
},
|
||||||
|
async saveChanges () {
|
||||||
|
if (this.isSaving) return;
|
||||||
|
this.isSaving = true;
|
||||||
|
const params = {
|
||||||
|
uid: this.connection.uid,
|
||||||
|
schema: this.schema,
|
||||||
|
trigger: {
|
||||||
|
...this.localTrigger,
|
||||||
|
oldName: this.originalTrigger.name
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { status, response } = await Triggers.alterTrigger(params);
|
||||||
|
|
||||||
|
if (status === 'success') {
|
||||||
|
const oldName = this.originalTrigger.name;
|
||||||
|
|
||||||
|
await this.refreshStructure(this.connection.uid);
|
||||||
|
|
||||||
|
if (oldName !== this.localTrigger.name) {
|
||||||
|
this.setUnsavedChanges(false);
|
||||||
|
this.changeBreadcrumbs({ schema: this.schema, trigger: this.localTrigger.name });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getTriggerData();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.addNotification({ status: 'error', message: response });
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.addNotification({ status: 'error', message: err.stack });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isSaving = false;
|
||||||
|
},
|
||||||
|
clearChanges () {
|
||||||
|
this.localTrigger = JSON.parse(JSON.stringify(this.originalTrigger));
|
||||||
|
this.$refs.queryEditor.editor.session.setValue(this.localTrigger.sql);
|
||||||
|
},
|
||||||
|
resizeQueryEditor () {
|
||||||
|
if (this.$refs.queryEditor) {
|
||||||
|
const footer = document.getElementById('footer');
|
||||||
|
const size = window.innerHeight - this.$refs.queryEditor.$el.getBoundingClientRect().top - footer.offsetHeight;
|
||||||
|
this.editorHeight = size;
|
||||||
|
this.$refs.queryEditor.editor.resize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -47,6 +47,9 @@
|
||||||
<option value="">
|
<option value="">
|
||||||
{{ $t('message.currentUser') }}
|
{{ $t('message.currentUser') }}
|
||||||
</option>
|
</option>
|
||||||
|
<option v-if="!isDefinerInUsers" :value="originalView.definer">
|
||||||
|
{{ originalView.definer.replaceAll('`', '') }}
|
||||||
|
</option>
|
||||||
<option
|
<option
|
||||||
v-for="user in workspace.users"
|
v-for="user in workspace.users"
|
||||||
:key="`${user.name}@${user.host}`"
|
:key="`${user.name}@${user.host}`"
|
||||||
|
@ -208,6 +211,9 @@ export default {
|
||||||
},
|
},
|
||||||
isChanged () {
|
isChanged () {
|
||||||
return JSON.stringify(this.originalView) !== JSON.stringify(this.localView);
|
return JSON.stringify(this.originalView) !== JSON.stringify(this.localView);
|
||||||
|
},
|
||||||
|
isDefinerInUsers () {
|
||||||
|
return this.originalView ? this.workspace.users.some(user => this.originalView.definer === `\`${user.name}\`@\`${user.host}\``) : true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
@ -71,9 +71,10 @@ module.exports = {
|
||||||
view: 'View',
|
view: 'View',
|
||||||
definer: 'Definer',
|
definer: 'Definer',
|
||||||
algorithm: 'Algorithm',
|
algorithm: 'Algorithm',
|
||||||
trigger: 'Trigger',
|
trigger: 'Trigger | Triggers',
|
||||||
storedRoutine: 'Stored routine',
|
storedRoutine: 'Stored routine | Stored routines',
|
||||||
scheduler: 'Scheduler'
|
scheduler: 'Scheduler | Schedulers',
|
||||||
|
event: 'Event'
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
appWelcome: 'Welcome to Antares SQL Client!',
|
appWelcome: 'Welcome to Antares SQL Client!',
|
||||||
|
@ -140,6 +141,7 @@ module.exports = {
|
||||||
editorTheme: 'Editor Theme',
|
editorTheme: 'Editor Theme',
|
||||||
wrapLongLines: 'Wrap long lines',
|
wrapLongLines: 'Wrap long lines',
|
||||||
selectStatement: 'Select statement',
|
selectStatement: 'Select statement',
|
||||||
|
triggerStatement: 'Trigger statement',
|
||||||
sqlSecurity: 'SQL security',
|
sqlSecurity: 'SQL security',
|
||||||
updateOption: 'Update option',
|
updateOption: 'Update option',
|
||||||
deleteView: 'Delete view',
|
deleteView: 'Delete view',
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
'use strict';
|
||||||
|
import { ipcRenderer } from 'electron';
|
||||||
|
|
||||||
|
export default class {
|
||||||
|
static getTriggerInformations (params) {
|
||||||
|
return ipcRenderer.invoke('get-trigger-informations', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dropTrigger (params) {
|
||||||
|
return ipcRenderer.invoke('drop-trigger', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static alterTrigger (params) {
|
||||||
|
return ipcRenderer.invoke('alter-trigger', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static createTrigger (params) {
|
||||||
|
return ipcRenderer.invoke('create-trigger', params);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue