mirror of
https://github.com/Fabio286/antares.git
synced 2025-04-22 05:57:25 +02:00
feat: views edit
This commit is contained in:
parent
dcf469ebed
commit
56f2a27f00
@ -20,4 +20,14 @@ export default (connections) => {
|
|||||||
return { status: 'error', response: err.toString() };
|
return { status: 'error', response: err.toString() };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('alter-view', async (event, params) => {
|
||||||
|
try {
|
||||||
|
await connections[params.uid].alterView(params);
|
||||||
|
return { status: 'success' };
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return { status: 'error', response: err.toString() };
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -295,6 +295,18 @@ export class MySQLClient extends AntaresCore {
|
|||||||
return await this.raw(sql);
|
return await this.raw(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ALTER VIEW
|
||||||
|
*
|
||||||
|
* @returns {Array.<Object>} parameters
|
||||||
|
* @memberof MySQLClient
|
||||||
|
*/
|
||||||
|
async alterView (params) {
|
||||||
|
const { view } = params;
|
||||||
|
const sql = `ALTER ALGORITHM = ${view.algorithm} DEFINER=${view.definer} SQL SECURITY ${view.security} VIEW \`${view.name}\` AS ${view.sql} ${view.updateOption ? `WITH ${view.updateOption} CHECK OPTION` : ''}`;
|
||||||
|
return await this.raw(sql);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SHOW COLLATION
|
* SHOW COLLATION
|
||||||
*
|
*
|
||||||
|
@ -182,8 +182,13 @@ export default {
|
|||||||
if (this.autoFocus) {
|
if (this.autoFocus) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.editor.focus();
|
this.editor.focus();
|
||||||
|
this.editor.resize();
|
||||||
}, 20);
|
}, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.editor.resize();
|
||||||
|
}, 20);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -13,25 +13,25 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="workspace.breadcrumbs.table"
|
v-if="schemaChild"
|
||||||
class="tab-item"
|
class="tab-item"
|
||||||
:class="{'active': selectedTab === 'prop'}"
|
:class="{'active': selectedTab === 'prop'}"
|
||||||
@click="selectTab({uid: workspace.uid, tab: 'prop'})"
|
@click="selectTab({uid: workspace.uid, tab: 'prop'})"
|
||||||
>
|
>
|
||||||
<a class="tab-link">
|
<a class="tab-link">
|
||||||
<i class="mdi mdi-18px mdi-tune mr-1" />
|
<i class="mdi mdi-18px mdi-tune mr-1" />
|
||||||
<span :title="workspace.breadcrumbs.table">{{ $t('word.properties').toUpperCase() }}: {{ workspace.breadcrumbs.table }}</span>
|
<span :title="schemaChild">{{ $t('word.properties').toUpperCase() }}: {{ schemaChild }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="workspace.breadcrumbs.table"
|
v-if="workspace.breadcrumbs.table || workspace.breadcrumbs.view"
|
||||||
class="tab-item"
|
class="tab-item"
|
||||||
:class="{'active': selectedTab === 'data'}"
|
:class="{'active': selectedTab === 'data'}"
|
||||||
@click="selectTab({uid: workspace.uid, tab: 'data'})"
|
@click="selectTab({uid: workspace.uid, tab: 'data'})"
|
||||||
>
|
>
|
||||||
<a class="tab-link">
|
<a class="tab-link">
|
||||||
<i class="mdi mdi-18px mdi-table mr-1" />
|
<i class="mdi mdi-18px mr-1" :class="workspace.breadcrumbs.table ? 'mdi-table' : 'mdi-table-eye'" />
|
||||||
<span :title="workspace.breadcrumbs.table">{{ $t('word.data').toUpperCase() }}: {{ workspace.breadcrumbs.table }}</span>
|
<span :title="schemaChild">{{ $t('word.data').toUpperCase() }}: {{ schemaChild }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
@ -66,15 +66,21 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<WorkspacePropsTab
|
<WorkspacePropsTab
|
||||||
v-show="selectedTab === 'prop'"
|
v-show="selectedTab === 'prop' && workspace.breadcrumbs.table"
|
||||||
:is-selected="selectedTab === 'prop'"
|
:is-selected="selectedTab === 'prop'"
|
||||||
:connection="connection"
|
:connection="connection"
|
||||||
:table="workspace.breadcrumbs.table"
|
:table="workspace.breadcrumbs.table"
|
||||||
/>
|
/>
|
||||||
|
<WorkspacePropsTabView
|
||||||
|
v-show="selectedTab === 'prop' && workspace.breadcrumbs.view"
|
||||||
|
:is-selected="selectedTab === 'prop'"
|
||||||
|
:connection="connection"
|
||||||
|
:view="workspace.breadcrumbs.view"
|
||||||
|
/>
|
||||||
<WorkspaceTableTab
|
<WorkspaceTableTab
|
||||||
v-show="selectedTab === 'data'"
|
v-show="selectedTab === 'data'"
|
||||||
:connection="connection"
|
:connection="connection"
|
||||||
:table="workspace.breadcrumbs.table"
|
:table="workspace.breadcrumbs.table || workspace.breadcrumbs.view"
|
||||||
/>
|
/>
|
||||||
<WorkspaceQueryTab
|
<WorkspaceQueryTab
|
||||||
v-for="tab of queryTabs"
|
v-for="tab of queryTabs"
|
||||||
@ -94,6 +100,7 @@ import WorkspaceExploreBar from '@/components/WorkspaceExploreBar';
|
|||||||
import WorkspaceQueryTab from '@/components/WorkspaceQueryTab';
|
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';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Workspace',
|
name: 'Workspace',
|
||||||
@ -101,7 +108,8 @@ export default {
|
|||||||
WorkspaceExploreBar,
|
WorkspaceExploreBar,
|
||||||
WorkspaceQueryTab,
|
WorkspaceQueryTab,
|
||||||
WorkspaceTableTab,
|
WorkspaceTableTab,
|
||||||
WorkspacePropsTab
|
WorkspacePropsTab,
|
||||||
|
WorkspacePropsTabView
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
connection: Object
|
connection: Object
|
||||||
@ -123,7 +131,7 @@ export default {
|
|||||||
return this.selectedWorkspace === this.connection.uid;
|
return this.selectedWorkspace === this.connection.uid;
|
||||||
},
|
},
|
||||||
selectedTab () {
|
selectedTab () {
|
||||||
if (this.workspace.breadcrumbs.table === null && ['data', 'prop'].includes(this.workspace.selected_tab))
|
if (this.workspace.breadcrumbs.table === null && this.workspace.breadcrumbs.view === 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) ||
|
||||||
@ -133,6 +141,13 @@ export default {
|
|||||||
},
|
},
|
||||||
queryTabs () {
|
queryTabs () {
|
||||||
return this.workspace.tabs.filter(tab => tab.type === 'query');
|
return this.workspace.tabs.filter(tab => tab.type === 'query');
|
||||||
|
},
|
||||||
|
schemaChild () {
|
||||||
|
for (const key in this.workspace.breadcrumbs) {
|
||||||
|
if (key === 'schema') continue;
|
||||||
|
if (this.workspace.breadcrumbs[key]) return this.workspace.breadcrumbs[key];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created () {
|
async created () {
|
||||||
|
@ -10,6 +10,18 @@
|
|||||||
<div class="context-element" @click="showCreateTableModal">
|
<div class="context-element" @click="showCreateTableModal">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-table text-light pr-1" /> {{ $t('word.table') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-table text-light pr-1" /> {{ $t('word.table') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="context-element" @click="showCreateTableModal">
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-table-eye text-light pr-1" /> {{ $t('word.view') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="context-element d-none" @click="false">
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-table-cog text-light pr-1" /> {{ $t('word.trigger') }}</span>
|
||||||
|
</div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-element" @click="showEditModal">
|
<div class="context-element" @click="showEditModal">
|
||||||
@ -124,3 +136,8 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.context-submenu {
|
||||||
|
min-width: 150px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
296
src/renderer/components/WorkspacePropsTabView.vue
Normal file
296
src/renderer/components/WorkspacePropsTabView.vue
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
<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="localView.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>
|
||||||
|
<input
|
||||||
|
v-model="localView.definer"
|
||||||
|
class="form-input"
|
||||||
|
type="text"
|
||||||
|
readonly
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column col-2">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">{{ $t('message.sqlSecurity') }}</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="localView.security"
|
||||||
|
type="radio"
|
||||||
|
name="security"
|
||||||
|
value="DEFINER"
|
||||||
|
>
|
||||||
|
<i class="form-icon" /> DEFINER
|
||||||
|
</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="localView.security"
|
||||||
|
type="radio"
|
||||||
|
name="security"
|
||||||
|
value="INVOKER"
|
||||||
|
>
|
||||||
|
<i class="form-icon" /> INVOKER
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="column col-2">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">{{ $t('word.algorithm') }}</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="localView.algorithm"
|
||||||
|
type="radio"
|
||||||
|
name="algorithm"
|
||||||
|
value="UNDEFINED"
|
||||||
|
>
|
||||||
|
<i class="form-icon" /> UNDEFINED
|
||||||
|
</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="localView.algorithm"
|
||||||
|
type="radio"
|
||||||
|
value="MERGE"
|
||||||
|
name="algorithm"
|
||||||
|
>
|
||||||
|
<i class="form-icon" /> MERGE
|
||||||
|
</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="localView.algorithm"
|
||||||
|
type="radio"
|
||||||
|
value="TEMPTABLE"
|
||||||
|
name="algorithm"
|
||||||
|
>
|
||||||
|
<i class="form-icon" /> TEMPTABLE
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="column col-2">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">{{ $t('message.updateOption') }}</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="localView.updateOption"
|
||||||
|
type="radio"
|
||||||
|
name="update"
|
||||||
|
value=""
|
||||||
|
>
|
||||||
|
<i class="form-icon" /> None
|
||||||
|
</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="localView.updateOption"
|
||||||
|
type="radio"
|
||||||
|
name="update"
|
||||||
|
value="CASCADED"
|
||||||
|
>
|
||||||
|
<i class="form-icon" /> CASCADED
|
||||||
|
</label>
|
||||||
|
<label class="form-radio">
|
||||||
|
<input
|
||||||
|
v-model="localView.updateOption"
|
||||||
|
type="radio"
|
||||||
|
name="update"
|
||||||
|
value="LOCAL"
|
||||||
|
>
|
||||||
|
<i class="form-icon" /> LOCAL
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="workspace-query-results column col-12 mt-2">
|
||||||
|
<label class="form-label ml-2">{{ $t('message.selectStatement') }}</label>
|
||||||
|
<QueryEditor
|
||||||
|
v-if="isSelected"
|
||||||
|
ref="queryEditor"
|
||||||
|
:value.sync="localView.sql"
|
||||||
|
:workspace="workspace"
|
||||||
|
:schema="schema"
|
||||||
|
:height="editorHeight"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters, mapActions } from 'vuex';
|
||||||
|
import QueryEditor from '@/components/QueryEditor';
|
||||||
|
import Views from '@/ipc-api/Views';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'WorkspacePropsTabView',
|
||||||
|
components: {
|
||||||
|
QueryEditor
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
connection: Object,
|
||||||
|
view: String
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
tabUid: 'prop',
|
||||||
|
isQuering: false,
|
||||||
|
isSaving: false,
|
||||||
|
originalView: null,
|
||||||
|
localView: { sql: '' },
|
||||||
|
lastView: 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.originalView) !== JSON.stringify(this.localView);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
async view () {
|
||||||
|
if (this.isSelected) {
|
||||||
|
await this.getViewData();
|
||||||
|
this.$refs.queryEditor.editor.session.setValue(this.localView.sql);
|
||||||
|
this.lastView = this.view;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async isSelected (val) {
|
||||||
|
if (val && this.lastView !== this.view) {
|
||||||
|
await this.getViewData();
|
||||||
|
this.$refs.queryEditor.editor.session.setValue(this.localView.sql);
|
||||||
|
this.lastView = this.view;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isChanged (val) {
|
||||||
|
if (this.isSelected && this.lastView === this.view && this.view !== 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'
|
||||||
|
}),
|
||||||
|
async getViewData () {
|
||||||
|
if (!this.view) return;
|
||||||
|
this.isQuering = true;
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
uid: this.connection.uid,
|
||||||
|
schema: this.schema,
|
||||||
|
view: this.workspace.breadcrumbs.view
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { status, response } = await Views.getViewInformations(params);
|
||||||
|
if (status === 'success') {
|
||||||
|
this.originalView = response;
|
||||||
|
this.localView = JSON.parse(JSON.stringify(this.originalView));
|
||||||
|
this.sqlProxy = this.localView.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,
|
||||||
|
view: this.localView
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { status, response } = await Views.alterView(params);
|
||||||
|
|
||||||
|
if (status === 'success') {
|
||||||
|
await this.refreshStructure(this.connection.uid);
|
||||||
|
this.getViewData();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.addNotification({ status: 'error', message: response });
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.addNotification({ status: 'error', message: err.stack });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isSaving = false;
|
||||||
|
},
|
||||||
|
clearChanges () {
|
||||||
|
this.localView = JSON.parse(JSON.stringify(this.originalView));
|
||||||
|
this.$refs.queryEditor.editor.session.setValue(this.localView.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>
|
@ -9,4 +9,8 @@ export default class {
|
|||||||
static dropView (params) {
|
static dropView (params) {
|
||||||
return ipcRenderer.invoke('drop-view', params);
|
return ipcRenderer.invoke('drop-view', params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static alterView (params) {
|
||||||
|
return ipcRenderer.invoke('alter-view', params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user