refactor: ts and composition api on WorkspaceExplorebar* components

This commit is contained in:
Fabio Di Stasio 2022-06-09 20:08:32 +02:00
parent be70b5be7f
commit bd46d17424
16 changed files with 853 additions and 910 deletions

View File

@ -87,7 +87,7 @@ export interface TableInfos {
updated: Date;
engine: string;
comment: string;
size: number;
size: number | false;
autoIncrement: number;
collation: string;
}
@ -216,6 +216,7 @@ export interface TriggerInfos {
sqlMode: string;
created: Date;
charset: string;
enabled?: boolean;
}
export interface CreateTriggerParams {
@ -231,8 +232,21 @@ export interface CreateTriggerParams {
export interface AlterTriggerParams extends CreateTriggerParams {
oldName?: string;
}
export interface TriggerFunctionInfos {
name: string;
type: string;
security: string;
}
// Routines & Functions
export interface FunctionParam {
context: string;
name: string;
type: string;
length: number;
}
export interface RoutineInfos {
name: string;
type: string;
@ -242,17 +256,11 @@ export interface RoutineInfos {
comment?: string;
charset?: string;
security?: string;
parameters?: FunctionParam[];
}
export type FunctionInfos = RoutineInfos
export interface FunctionParam {
context: string;
name: string;
type: string;
length: number;
}
export interface CreateRoutineParams {
name: string;
parameters?: FunctionParam[];
@ -337,7 +345,7 @@ export interface SchemaInfos {
name: string;
size: number;
tables: TableInfos[];
functions: RoutineInfos[];
functions: FunctionInfos[];
procedures: RoutineInfos[];
triggers: TriggerInfos[];
schedulers: EventInfos[];

View File

@ -101,7 +101,7 @@ const contextMenu = (event: MouseEvent, connection: ConnectionParams) => {
const tooltipPosition = (e: Event) => {
const el = e.target ? e.target : e;
const fromTop = window.pageYOffset + (el as HTMLElement).getBoundingClientRect().top - ((el as HTMLElement).offsetHeight / 4);
const fromTop = window.scrollY + (el as HTMLElement).getBoundingClientRect().top - ((el as HTMLElement).offsetHeight / 4);
(el as HTMLElement).querySelector<HTMLElement>('.ex-tooltip-content').style.top = `${fromTop}px`;
};

View File

@ -161,8 +161,7 @@ const {
const searchInput: Ref<HTMLInputElement> = ref(null);
const explorebar: Ref<HTMLInputElement> = ref(null);
const resizer: Ref<HTMLInputElement> = ref(null);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const schema: Ref<Component & { selectSchema: (name: string) => void; $refs: any }[]> = ref(null);
const schema: Ref<Component & { selectSchema: (name: string) => void; $refs: {schemaAccordion: HTMLDetailsElement} }[]> = ref(null);
const isRefreshing = ref(false);
const isNewDBModal = ref(false);
const localWidth = ref(null);

View File

@ -56,7 +56,7 @@
</ConfirmModal>
<ModalAskParameters
v-if="isAskingParameters"
:local-routine="localElement"
:local-routine="(localElement as any)"
:client="workspace.client"
@confirm="runElement"
@close="hideAskParamsModal"
@ -64,336 +64,330 @@
</BaseContextMenu>
</template>
<script>
<script setup lang="ts">
import { computed, Prop, Ref, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { useNotificationsStore } from '@/stores/notifications';
import { useWorkspacesStore } from '@/stores/workspaces';
import BaseContextMenu from '@/components/BaseContextMenu';
import ConfirmModal from '@/components/BaseConfirmModal';
import ModalAskParameters from '@/components/ModalAskParameters';
import BaseContextMenu from '@/components/BaseContextMenu.vue';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import ModalAskParameters from '@/components/ModalAskParameters.vue';
import Triggers from '@/ipc-api/Triggers';
import Routines from '@/ipc-api/Routines';
import Functions from '@/ipc-api/Functions';
import Schedulers from '@/ipc-api/Schedulers';
import { storeToRefs } from 'pinia';
import { EventInfos, FunctionInfos, RoutineInfos, TriggerInfos } from 'common/interfaces/antares';
export default {
name: 'WorkspaceExploreBarMiscContext',
components: {
BaseContextMenu,
ConfirmModal,
ModalAskParameters
},
props: {
contextEvent: MouseEvent,
selectedMisc: Object,
selectedSchema: String
},
emits: ['close-context', 'reload'],
setup () {
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();
const { t } = useI18n();
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const props = defineProps({
contextEvent: MouseEvent,
selectedMisc: Object as Prop<{ name:string; type:string; enabled?: boolean }>,
selectedSchema: String
});
const {
getWorkspace,
changeBreadcrumbs,
addLoadingElement,
removeLoadingElement,
removeTabs,
newTab
} = workspacesStore;
const emit = defineEmits(['close-context', 'reload']);
return {
addNotification,
selectedWorkspace,
getWorkspace,
changeBreadcrumbs,
addLoadingElement,
removeLoadingElement,
removeTabs,
newTab
};
},
data () {
return {
isDeleteModal: false,
isRunModal: false,
isAskingParameters: false,
localElement: {}
};
},
computed: {
workspace () {
return this.getWorkspace(this.selectedWorkspace);
},
customizations () {
return this.getWorkspace(this.selectedWorkspace).customizations;
},
deleteMessage () {
switch (this.selectedMisc.type) {
case 'trigger':
return this.$t('message.deleteTrigger');
case 'procedure':
return this.$t('message.deleteRoutine');
case 'function':
case 'triggerFunction':
return this.$t('message.deleteFunction');
case 'scheduler':
return this.$t('message.deleteScheduler');
default:
return '';
}
}
},
methods: {
showDeleteModal () {
this.isDeleteModal = true;
},
hideDeleteModal () {
this.isDeleteModal = false;
},
showAskParamsModal () {
this.isAskingParameters = true;
},
hideAskParamsModal () {
this.isAskingParameters = false;
this.closeContext();
},
closeContext () {
this.$emit('close-context');
},
async deleteMisc () {
try {
let res;
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();
switch (this.selectedMisc.type) {
case 'trigger':
res = await Triggers.dropTrigger({
uid: this.selectedWorkspace,
schema: this.selectedSchema,
trigger: this.selectedMisc.name
});
break;
case 'procedure':
res = await Routines.dropRoutine({
uid: this.selectedWorkspace,
schema: this.selectedSchema,
routine: this.selectedMisc.name
});
break;
case 'function':
case 'triggerFunction':
res = await Functions.dropFunction({
uid: this.selectedWorkspace,
schema: this.selectedSchema,
func: this.selectedMisc.name
});
break;
case 'scheduler':
res = await Schedulers.dropScheduler({
uid: this.selectedWorkspace,
schema: this.selectedSchema,
scheduler: this.selectedMisc.name
});
break;
}
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const { status, response } = res;
const {
getWorkspace,
addLoadingElement,
removeLoadingElement,
removeTabs,
newTab
} = workspacesStore;
if (status === 'success') {
this.removeTabs({
uid: this.selectedWorkspace,
elementName: this.selectedMisc.name,
elementType: this.selectedMisc.type,
schema: this.selectedSchema
});
const isDeleteModal = ref(false);
const isAskingParameters = ref(false);
const localElement: Ref<TriggerInfos | RoutineInfos | FunctionInfos | EventInfos> = ref(null);
this.closeContext();
this.$emit('reload');
}
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
},
runElementCheck () {
if (this.selectedMisc.type === 'procedure')
this.runRoutineCheck();
else if (this.selectedMisc.type === 'function')
this.runFunctionCheck();
},
runElement (params) {
if (this.selectedMisc.type === 'procedure')
this.runRoutine(params);
else if (this.selectedMisc.type === 'function')
this.runFunction(params);
},
async runRoutineCheck () {
const params = {
uid: this.selectedWorkspace,
schema: this.selectedSchema,
routine: this.selectedMisc.name
};
const workspace = computed(() => {
return getWorkspace(selectedWorkspace.value);
});
try {
const { status, response } = await Routines.getRoutineInformations(params);
if (status === 'success')
this.localElement = response;
const customizations = computed(() => {
return getWorkspace(selectedWorkspace.value).customizations;
});
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
const deleteMessage = computed(() => {
switch (props.selectedMisc.type) {
case 'trigger':
return t('message.deleteTrigger');
case 'procedure':
return t('message.deleteRoutine');
case 'function':
case 'triggerFunction':
return t('message.deleteFunction');
case 'scheduler':
return t('message.deleteScheduler');
default:
return '';
}
});
if (this.localElement.parameters.length)
this.showAskParamsModal();
else
this.runRoutine();
},
runRoutine (params) {
if (!params) params = [];
const showDeleteModal = () => {
isDeleteModal.value = true;
};
let sql;
switch (this.workspace.client) { // TODO: move in a better place
case 'maria':
case 'mysql':
case 'pg':
sql = `CALL ${this.localElement.name}(${params.join(',')})`;
break;
case 'mssql':
sql = `EXEC ${this.localElement.name} ${params.join(',')}`;
break;
default:
sql = `CALL \`${this.localElement.name}\`(${params.join(',')})`;
}
const hideDeleteModal = () => {
isDeleteModal.value = false;
};
this.newTab({
uid: this.workspace.uid,
content: sql,
type: 'query',
schema: this.selectedSchema,
autorun: true
});
this.closeContext();
},
async runFunctionCheck () {
const params = {
uid: this.selectedWorkspace,
schema: this.selectedSchema,
func: this.selectedMisc.name
};
const showAskParamsModal = () => {
isAskingParameters.value = true;
};
try {
const { status, response } = await Functions.getFunctionInformations(params);
if (status === 'success')
this.localElement = response;
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
const hideAskParamsModal = () => {
isAskingParameters.value = false;
closeContext();
};
if (this.localElement.parameters.length)
this.showAskParamsModal();
else
this.runFunction();
},
runFunction (params) {
if (!params) params = [];
const closeContext = () => {
emit('close-context');
};
let sql;
switch (this.workspace.client) { // TODO: move in a better place
case 'maria':
case 'mysql':
sql = `SELECT \`${this.localElement.name}\` (${params.join(',')})`;
break;
case 'pg':
sql = `SELECT ${this.localElement.name}(${params.join(',')})`;
break;
case 'mssql':
sql = `SELECT ${this.localElement.name} ${params.join(',')}`;
break;
default:
sql = `SELECT \`${this.localElement.name}\` (${params.join(',')})`;
}
const deleteMisc = async () => {
try {
let res;
this.newTab({
uid: this.workspace.uid,
content: sql,
type: 'query',
schema: this.selectedSchema,
autorun: true
});
this.closeContext();
},
async toggleTrigger () {
this.addLoadingElement({
name: this.selectedMisc.name,
schema: this.selectedSchema,
type: 'trigger'
});
try {
const { status, response } = await Triggers.toggleTrigger({
uid: this.selectedWorkspace,
schema: this.selectedSchema,
trigger: this.selectedMisc.name,
enabled: this.selectedMisc.enabled
switch (props.selectedMisc.type) {
case 'trigger':
res = await Triggers.dropTrigger({
uid: selectedWorkspace.value,
schema: props.selectedSchema,
trigger: props.selectedMisc.name
});
if (status !== 'success')
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
this.removeLoadingElement({
name: this.selectedMisc.name,
schema: this.selectedSchema,
type: 'trigger'
});
this.closeContext();
this.$emit('reload');
},
async toggleScheduler () {
this.addLoadingElement({
name: this.selectedMisc.name,
schema: this.selectedSchema,
type: 'scheduler'
});
try {
const { status, response } = await Schedulers.toggleScheduler({
uid: this.selectedWorkspace,
schema: this.selectedSchema,
scheduler: this.selectedMisc.name,
enabled: this.selectedMisc.enabled
break;
case 'procedure':
res = await Routines.dropRoutine({
uid: selectedWorkspace.value,
schema: props.selectedSchema,
routine: props.selectedMisc.name
});
break;
case 'function':
case 'triggerFunction':
res = await Functions.dropFunction({
uid: selectedWorkspace.value,
schema: props.selectedSchema,
func: props.selectedMisc.name
});
break;
case 'scheduler':
res = await Schedulers.dropScheduler({
uid: selectedWorkspace.value,
schema: props.selectedSchema,
scheduler: props.selectedMisc.name
});
break;
}
if (status !== 'success')
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
const { status, response } = res;
this.removeLoadingElement({
name: this.selectedMisc.name,
schema: this.selectedSchema,
type: 'scheduler'
if (status === 'success') {
removeTabs({
uid: selectedWorkspace.value,
elementName: props.selectedMisc.name,
elementType: props.selectedMisc.type,
schema: props.selectedSchema
});
this.closeContext();
this.$emit('reload');
closeContext();
emit('reload');
}
else
addNotification({ status: 'error', message: response });
}
catch (err) {
addNotification({ status: 'error', message: err.stack });
}
};
const runElementCheck = () => {
if (props.selectedMisc.type === 'procedure')
runRoutineCheck();
else if (props.selectedMisc.type === 'function')
runFunctionCheck();
};
const runElement = (params: string[]) => {
if (props.selectedMisc.type === 'procedure')
runRoutine(params);
else if (props.selectedMisc.type === 'function')
runFunction(params);
};
const runRoutineCheck = async () => {
const params = {
uid: selectedWorkspace.value,
schema: props.selectedSchema,
routine: props.selectedMisc.name
};
try {
const { status, response } = await Routines.getRoutineInformations(params);
if (status === 'success')
localElement.value = response;
else
addNotification({ status: 'error', message: response });
}
catch (err) {
addNotification({ status: 'error', message: err.stack });
}
if ((localElement.value as RoutineInfos).parameters.length)
showAskParamsModal();
else
runRoutine();
};
const runRoutine = (params?: string[]) => {
if (!params) params = [];
let sql;
switch (workspace.value.client) { // TODO: move in a better place
case 'maria':
case 'mysql':
case 'pg':
sql = `CALL ${localElement.value.name}(${params.join(',')})`;
break;
case 'mssql':
sql = `EXEC ${localElement.value.name} ${params.join(',')}`;
break;
default:
sql = `CALL \`${localElement.value.name}\`(${params.join(',')})`;
}
newTab({
uid: workspace.value.uid,
content: sql,
type: 'query',
schema: props.selectedSchema,
autorun: true
});
closeContext();
};
const runFunctionCheck = async () => {
const params = {
uid: selectedWorkspace.value,
schema: props.selectedSchema,
func: props.selectedMisc.name
};
try {
const { status, response } = await Functions.getFunctionInformations(params);
if (status === 'success')
localElement.value = response;
else
addNotification({ status: 'error', message: response });
}
catch (err) {
addNotification({ status: 'error', message: err.stack });
}
if ((localElement.value as FunctionInfos).parameters.length)
showAskParamsModal();
else
runFunction();
};
const runFunction = (params?: string[]) => {
if (!params) params = [];
let sql;
switch (workspace.value.client) { // TODO: move in a better place
case 'maria':
case 'mysql':
sql = `SELECT \`${localElement.value.name}\` (${params.join(',')})`;
break;
case 'pg':
sql = `SELECT ${localElement.value.name}(${params.join(',')})`;
break;
case 'mssql':
sql = `SELECT ${localElement.value.name} ${params.join(',')}`;
break;
default:
sql = `SELECT \`${localElement.value.name}\` (${params.join(',')})`;
}
newTab({
uid: workspace.value.uid,
content: sql,
type: 'query',
schema: props.selectedSchema,
autorun: true
});
closeContext();
};
const toggleTrigger = async () => {
addLoadingElement({
name: props.selectedMisc.name,
schema: props.selectedSchema,
type: 'trigger'
});
try {
const { status, response } = await Triggers.toggleTrigger({
uid: selectedWorkspace.value,
schema: props.selectedSchema,
trigger: props.selectedMisc.name,
enabled: props.selectedMisc.enabled
});
if (status !== 'success')
addNotification({ status: 'error', message: response });
}
catch (err) {
addNotification({ status: 'error', message: err.stack });
}
removeLoadingElement({
name: props.selectedMisc.name,
schema: props.selectedSchema,
type: 'trigger'
});
closeContext();
emit('reload');
};
const toggleScheduler = async () => {
addLoadingElement({
name: props.selectedMisc.name,
schema: props.selectedSchema,
type: 'scheduler'
});
try {
const { status, response } = await Schedulers.toggleScheduler({
uid: selectedWorkspace.value,
schema: props.selectedSchema,
scheduler: props.selectedMisc.name,
enabled: props.selectedMisc.enabled
});
if (status !== 'success')
addNotification({ status: 'error', message: response });
}
catch (err) {
addNotification({ status: 'error', message: err.stack });
}
removeLoadingElement({
name: props.selectedMisc.name,
schema: props.selectedSchema,
type: 'scheduler'
});
closeContext();
emit('reload');
};
</script>

View File

@ -1,112 +1,68 @@
<template>
<BaseContextMenu
:context-event="contextEvent"
:context-event="props.contextEvent"
@close-context="closeContext"
>
<div
v-if="selectedMisc === 'trigger'"
v-if="props.selectedMisc === 'trigger'"
class="context-element"
@click="$emit('open-create-trigger-tab')"
@click="emit('open-create-trigger-tab')"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-table-cog text-light pr-1" /> {{ $t('message.createNewTrigger') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-table-cog text-light pr-1" /> {{ t('message.createNewTrigger') }}</span>
</div>
<div
v-if="selectedMisc === 'procedure'"
v-if="props.selectedMisc === 'procedure'"
class="context-element"
@click="$emit('open-create-routine-tab')"
@click="emit('open-create-routine-tab')"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-sync-circle text-light pr-1" /> {{ $t('message.createNewRoutine') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-sync-circle text-light pr-1" /> {{ t('message.createNewRoutine') }}</span>
</div>
<div
v-if="selectedMisc === 'function'"
v-if="props.selectedMisc === 'function'"
class="context-element"
@click="$emit('open-create-function-tab')"
@click="emit('open-create-function-tab')"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-arrow-right-bold-box text-light pr-1" /> {{ $t('message.createNewFunction') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-arrow-right-bold-box text-light pr-1" /> {{ t('message.createNewFunction') }}</span>
</div>
<div
v-if="selectedMisc === 'triggerFunction'"
v-if="props.selectedMisc === 'triggerFunction'"
class="context-element"
@click="$emit('open-create-trigger-function-tab')"
@click="emit('open-create-trigger-function-tab')"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-cog-clockwise text-light pr-1" /> {{ $t('message.createNewFunction') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-cog-clockwise text-light pr-1" /> {{ t('message.createNewFunction') }}</span>
</div>
<div
v-if="selectedMisc === 'scheduler'"
v-if="props.selectedMisc === 'scheduler'"
class="context-element"
@click="$emit('open-create-scheduler-tab')"
@click="emit('open-create-scheduler-tab')"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-calendar-clock text-light pr-1" /> {{ $t('message.createNewScheduler') }}</span>
<span class="d-flex"><i class="mdi mdi-18px mdi-calendar-clock text-light pr-1" /> {{ t('message.createNewScheduler') }}</span>
</div>
</BaseContextMenu>
</template>
<script>
import { useNotificationsStore } from '@/stores/notifications';
import { useWorkspacesStore } from '@/stores/workspaces';
import BaseContextMenu from '@/components/BaseContextMenu';
import { storeToRefs } from 'pinia';
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import BaseContextMenu from '@/components/BaseContextMenu.vue';
export default {
name: 'WorkspaceExploreBarMiscContext',
components: {
BaseContextMenu
},
props: {
contextEvent: MouseEvent,
selectedMisc: String,
selectedSchema: String
},
emits: [
'open-create-trigger-tab',
'open-create-routine-tab',
'open-create-function-tab',
'open-create-trigger-function-tab',
'open-create-scheduler-tab',
'close-context'
],
setup () {
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();
const { t } = useI18n();
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const props = defineProps({
contextEvent: MouseEvent,
selectedMisc: String,
selectedSchema: String
});
const { getWorkspace, changeBreadcrumbs } = workspacesStore;
const emit = defineEmits([
'open-create-trigger-tab',
'open-create-routine-tab',
'open-create-function-tab',
'open-create-trigger-function-tab',
'open-create-scheduler-tab',
'close-context'
]);
return {
addNotification,
selectedWorkspace,
getWorkspace,
changeBreadcrumbs
};
},
data () {
return {
localElement: {}
};
},
computed: {
workspace () {
return this.getWorkspace(this.selectedWorkspace);
}
},
methods: {
showDeleteModal () {
this.isDeleteModal = true;
},
hideDeleteModal () {
this.isDeleteModal = false;
},
showAskParamsModal () {
this.isAskingParameters = true;
},
hideAskParamsModal () {
this.isAskingParameters = false;
this.closeContext();
},
closeContext () {
this.$emit('close-context');
}
}
const closeContext = () => {
emit('close-context');
};
</script>

View File

@ -25,7 +25,7 @@
<ul class="menu menu-nav pt-0">
<li
v-for="table of filteredTables"
:ref="breadcrumbs.schema === database.name && [breadcrumbs.table, breadcrumbs.view].includes(table.name) ? 'explorebar-selected' : ''"
:ref="breadcrumbs.schema === database.name && [breadcrumbs.table, breadcrumbs.view].includes(table.name) ? 'explorebarSelected' : ''"
:key="table.name"
class="menu-item"
:class="{'selected': breadcrumbs.schema === database.name && [breadcrumbs.table, breadcrumbs.view].includes(table.name)}"
@ -61,7 +61,7 @@
@contextmenu.prevent="showMiscFolderContext($event, 'trigger')"
>
<i class="misc-icon mdi mdi-18px mdi-folder-cog mr-1" />
{{ $tc('word.trigger', 2) }}
{{ t('word.trigger', 2) }}
</summary>
<div class="accordion-body">
<div>
@ -69,7 +69,7 @@
<li
v-for="trigger of filteredTriggers"
:key="trigger.name"
:ref="breadcrumbs.schema === database.name && breadcrumbs.trigger === trigger.name ? 'explorebar-selected' : ''"
:ref="breadcrumbs.schema === database.name && breadcrumbs.trigger === trigger.name ? 'explorebarSelected' : ''"
class="menu-item"
:class="{'selected': breadcrumbs.schema === database.name && breadcrumbs.trigger === trigger.name}"
@mousedown.left="selectMisc({schema: database.name, misc: trigger, type: 'trigger'})"
@ -84,7 +84,7 @@
<div
v-if="trigger.enabled === false"
class="tooltip tooltip-left disabled-indicator"
:data-tooltip="$t('word.disabled')"
:data-tooltip="t('word.disabled')"
>
<i class="table-icon mdi mdi-pause mdi-18px mr-1" />
</div>
@ -100,27 +100,27 @@
<summary
class="accordion-header misc-name"
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.routine}"
@contextmenu.prevent="showMiscFolderContext($event, 'procedure')"
@contextmenu.prevent="showMiscFolderContext($event, 'routine')"
>
<i class="misc-icon mdi mdi-18px mdi-folder-sync mr-1" />
{{ $tc('word.storedRoutine', 2) }}
{{ t('word.storedRoutine', 2) }}
</summary>
<div class="accordion-body">
<div>
<ul class="menu menu-nav pt-0">
<li
v-for="(procedure, i) of filteredProcedures"
:key="`${procedure.name}-${i}`"
:ref="breadcrumbs.schema === database.name && breadcrumbs.routine === procedure.name ? 'explorebar-selected' : ''"
v-for="(routine, i) of filteredProcedures"
:key="`${routine.name}-${i}`"
:ref="breadcrumbs.schema === database.name && breadcrumbs.routine === routine.name ? 'explorebarSelected' : ''"
class="menu-item"
:class="{'selected': breadcrumbs.schema === database.name && breadcrumbs.routine === procedure.name}"
@mousedown.left="selectMisc({schema: database.name, misc: procedure, type: 'routine'})"
@dblclick="openMiscPermanentTab({schema: database.name, misc: procedure, type: 'routine'})"
@contextmenu.prevent="showMiscContext($event, {...procedure, type: 'procedure'})"
:class="{'selected': breadcrumbs.schema === database.name && breadcrumbs.routine === routine.name}"
@mousedown.left="selectMisc({schema: database.name, misc: routine, type: 'routine'})"
@dblclick="openMiscPermanentTab({schema: database.name, misc: routine, type: 'routine'})"
@contextmenu.prevent="showMiscContext($event, {...routine, type: 'routine'})"
>
<a class="table-name">
<i class="table-icon mdi mdi-sync-circle mdi-18px mr-1" />
<span v-html="highlightWord(procedure.name)" />
<span v-html="highlightWord(routine.name)" />
</a>
</li>
</ul>
@ -137,7 +137,7 @@
@contextmenu.prevent="showMiscFolderContext($event, 'triggerFunction')"
>
<i class="misc-icon mdi mdi-18px mdi-folder-refresh mr-1" />
{{ $tc('word.triggerFunction', 2) }}
{{ t('word.triggerFunction', 2) }}
</summary>
<div class="accordion-body">
<div>
@ -145,7 +145,7 @@
<li
v-for="(func, i) of filteredTriggerFunctions"
:key="`${func.name}-${i}`"
:ref="breadcrumbs.schema === database.name && breadcrumbs.triggerFunction === func.name ? 'explorebar-selected' : ''"
:ref="breadcrumbs.schema === database.name && breadcrumbs.triggerFunction === func.name ? 'explorebarSelected' : ''"
class="menu-item"
:class="{'selected': breadcrumbs.schema === database.name && breadcrumbs.triggerFunction === func.name}"
@mousedown.left="selectMisc({schema: database.name, misc: func, type: 'triggerFunction'})"
@ -171,7 +171,7 @@
@contextmenu.prevent="showMiscFolderContext($event, 'function')"
>
<i class="misc-icon mdi mdi-18px mdi-folder-move mr-1" />
{{ $tc('word.function', 2) }}
{{ t('word.function', 2) }}
</summary>
<div class="accordion-body">
<div>
@ -179,7 +179,7 @@
<li
v-for="(func, i) of filteredFunctions"
:key="`${func.name}-${i}`"
:ref="breadcrumbs.schema === database.name && breadcrumbs.function === func.name ? 'explorebar-selected' : ''"
:ref="breadcrumbs.schema === database.name && breadcrumbs.function === func.name ? 'explorebarSelected' : ''"
class="menu-item"
:class="{'selected': breadcrumbs.schema === database.name && breadcrumbs.function === func.name}"
@mousedown.left="selectMisc({schema: database.name, misc: func, type: 'function'})"
@ -205,7 +205,7 @@
@contextmenu.prevent="showMiscFolderContext($event, 'scheduler')"
>
<i class="misc-icon mdi mdi-18px mdi-folder-clock mr-1" />
{{ $tc('word.scheduler', 2) }}
{{ t('word.scheduler', 2) }}
</summary>
<div class="accordion-body">
<div>
@ -213,7 +213,7 @@
<li
v-for="scheduler of filteredSchedulers"
:key="scheduler.name"
:ref="breadcrumbs.schema === database.name && breadcrumbs.scheduler === scheduler.name ? 'explorebar-selected' : ''"
:ref="breadcrumbs.schema === database.name && breadcrumbs.scheduler === scheduler.name ? 'explorebarSelected' : ''"
class="menu-item"
:class="{'selected': breadcrumbs.schema === database.name && breadcrumbs.scheduler === scheduler.name}"
@mousedown.left="selectMisc({schema: database.name, misc: scheduler, type: 'scheduler'})"
@ -228,7 +228,7 @@
<div
v-if="scheduler.enabled === false"
class="tooltip tooltip-left disabled-indicator"
:data-tooltip="$t('word.disabled')"
:data-tooltip="t('word.disabled')"
>
<i class="table-icon mdi mdi-pause mdi-18px mr-1" />
</div>
@ -242,228 +242,235 @@
</details>
</template>
<script>
import { useSettingsStore } from '@/stores/settings';
import { useWorkspacesStore } from '@/stores/workspaces';
import { formatBytes } from 'common/libs/formatBytes';
<script setup lang="ts">
import { computed, Prop, Ref, ref, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { useSettingsStore } from '@/stores/settings';
import { Breadcrumb, useWorkspacesStore, WorkspaceStructure } from '@/stores/workspaces';
import { formatBytes } from 'common/libs/formatBytes';
import { EventInfos, FunctionInfos, RoutineInfos, TableInfos, TriggerFunctionInfos, TriggerInfos } from 'common/interfaces/antares';
// TODO: expose selectSchema & schemaAccordion
const { t } = useI18n();
export default {
name: 'WorkspaceExploreBarSchema',
props: {
database: Object,
connection: Object
},
emits: [
'show-schema-context',
'show-table-context',
'show-misc-context',
'show-misc-folder-context'
],
setup () {
const settingsStore = useSettingsStore();
const workspacesStore = useWorkspacesStore();
const props = defineProps({
database: Object as Prop<WorkspaceStructure>,
connection: Object
});
const { applicationTheme } = storeToRefs(settingsStore);
const emit = defineEmits([
'show-schema-context',
'show-table-context',
'show-misc-context',
'show-misc-folder-context'
]);
const {
getLoadedSchemas,
getWorkspace,
getSearchTerm,
changeBreadcrumbs,
addLoadedSchema,
newTab,
refreshSchema
} = workspacesStore;
const settingsStore = useSettingsStore();
const workspacesStore = useWorkspacesStore();
return {
applicationTheme,
getLoadedSchemas,
getWorkspace,
getSearchTerm,
changeBreadcrumbs,
addLoadedSchema,
newTab,
refreshSchema
};
},
data () {
return {
isLoading: false
};
},
computed: {
searchTerm () {
return this.getSearchTerm(this.connection.uid);
},
filteredTables () {
return this.database.tables.filter(table => table.name.search(this.searchTerm) >= 0);
},
filteredTriggers () {
return this.database.triggers.filter(trigger => trigger.name.search(this.searchTerm) >= 0);
},
filteredProcedures () {
return this.database.procedures.filter(procedure => procedure.name.search(this.searchTerm) >= 0);
},
filteredFunctions () {
return this.database.functions.filter(func => func.name.search(this.searchTerm) >= 0);
},
filteredTriggerFunctions () {
return this.database.triggerFunctions
? this.database.triggerFunctions.filter(func => func.name.search(this.searchTerm) >= 0)
: [];
},
filteredSchedulers () {
return this.database.schedulers.filter(scheduler => scheduler.name.search(this.searchTerm) >= 0);
},
workspace () {
return this.getWorkspace(this.connection.uid);
},
breadcrumbs () {
return this.workspace.breadcrumbs;
},
customizations () {
return this.workspace.customizations;
},
loadedSchemas () {
return this.getLoadedSchemas(this.connection.uid);
},
maxSize () {
return this.database.tables.reduce((acc, curr) => {
if (curr.size > acc) acc = curr.size;
return acc;
}, 0);
},
totalSize () {
return this.database.tables.reduce((acc, curr) => acc + curr.size, 0);
}
},
watch: {
breadcrumbs (newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
setTimeout(() => {
const element = this.$refs['explorebar-selected'] ? this.$refs['explorebar-selected'][0] : null;
if (element) {
const rect = element.getBoundingClientRect();
const elemTop = rect.top;
const elemBottom = rect.bottom;
const isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
const { applicationTheme } = storeToRefs(settingsStore);
if (!isVisible) {
element.setAttribute('tabindex', '-1');
element.focus();
element.removeAttribute('tabindex');
}
}
}, 50);
const {
getLoadedSchemas,
getWorkspace,
getSearchTerm,
changeBreadcrumbs,
addLoadedSchema,
newTab,
refreshSchema
} = workspacesStore;
const schemaAccordion: Ref<HTMLDetailsElement> = ref(null);
const explorebarSelected: Ref<HTMLElement[]> = ref(null);
const isLoading = ref(false);
const searchTerm = computed(() => {
return getSearchTerm(props.connection.uid);
});
const filteredTables = computed(() => {
return props.database.tables.filter(table => table.name.search(searchTerm.value) >= 0);
});
const filteredTriggers = computed(() => {
return props.database.triggers.filter(trigger => trigger.name.search(searchTerm.value) >= 0);
});
const filteredProcedures = computed(() => {
return props.database.procedures.filter(procedure => procedure.name.search(searchTerm.value) >= 0);
});
const filteredFunctions = computed(() => {
return props.database.functions.filter(func => func.name.search(searchTerm.value) >= 0);
});
const filteredTriggerFunctions = computed(() => {
return props.database.triggerFunctions
? props.database.triggerFunctions.filter(func => func.name.search(searchTerm.value) >= 0)
: [];
});
const filteredSchedulers = computed(() => {
return props.database.schedulers.filter(scheduler => scheduler.name.search(searchTerm.value) >= 0);
});
const workspace = computed(() => {
return getWorkspace(props.connection.uid);
});
const breadcrumbs = computed(() => {
return workspace.value.breadcrumbs;
});
const customizations = computed(() => {
return workspace.value.customizations;
});
const loadedSchemas = computed(() => {
return getLoadedSchemas(props.connection.uid);
});
const maxSize = computed(() => {
return props.database.tables.reduce((acc: number, curr) => {
if (curr.size && curr.size > acc) acc = curr.size;
return acc;
}, 0);
});
watch(breadcrumbs, (newVal, oldVal) => {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
setTimeout(() => {
const element = explorebarSelected.value ? explorebarSelected.value[0] : null;
if (element) {
const rect = element.getBoundingClientRect();
const elemTop = rect.top;
const elemBottom = rect.bottom;
const isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
if (!isVisible) {
element.setAttribute('tabindex', '-1');
element.focus();
element.removeAttribute('tabindex');
}
}
}
},
methods: {
formatBytes,
async selectSchema (schema) {
if (!this.loadedSchemas.has(schema) && !this.isLoading) {
this.isLoading = true;
await this.refreshSchema({ uid: this.connection.uid, schema });
this.addLoadedSchema(schema);
this.isLoading = false;
}
},
selectTable ({ schema, table }) {
this.newTab({
uid: this.connection.uid,
elementName: table.name,
schema: this.database.name,
type: 'temp-data',
elementType: table.type
});
}, 50);
}
});
this.setBreadcrumbs({ schema, [table.type]: table.name });
},
selectMisc ({ schema, misc, type }) {
const miscTempTabs = {
trigger: 'temp-trigger-props',
triggerFunction: 'temp-trigger-function-props',
function: 'temp-function-props',
routine: 'temp-routine-props',
scheduler: 'temp-scheduler-props'
};
this.newTab({
uid: this.connection.uid,
elementName: misc.name,
schema: this.database.name,
type: miscTempTabs[type],
elementType: type
});
this.setBreadcrumbs({ schema, [type]: misc.name });
},
openDataTab ({ schema, table }) {
this.newTab({ uid: this.connection.uid, elementName: table.name, schema: this.database.name, type: 'data', elementType: table.type });
this.setBreadcrumbs({ schema, [table.type]: table.name });
},
openMiscPermanentTab ({ schema, misc, type }) {
const miscTabs = {
trigger: 'trigger-props',
triggerFunction: 'trigger-function-props',
function: 'function-props',
routine: 'routine-props',
scheduler: 'scheduler-props'
};
this.newTab({
uid: this.connection.uid,
elementName: misc.name,
schema: this.database.name,
type: miscTabs[type],
elementType: type
});
this.setBreadcrumbs({ schema, [type]: misc.name });
},
showSchemaContext (event, schema) {
this.$emit('show-schema-context', { event, schema });
},
showTableContext (event, table) {
this.$emit('show-table-context', { event, schema: this.database.name, table });
},
showMiscContext (event, misc) {
this.$emit('show-misc-context', { event, schema: this.database.name, misc });
},
showMiscFolderContext (event, type) {
this.$emit('show-misc-folder-context', { event, schema: this.database.name, type });
},
piePercentage (val) {
const perc = val / this.maxSize * 100;
if (this.applicationTheme === 'dark')
return { background: `conic-gradient(lime ${perc}%, white 0)` };
else
return { background: `conic-gradient(teal ${perc}%, silver 0)` };
},
setBreadcrumbs (payload) {
if (this.breadcrumbs.schema === payload.schema && this.breadcrumbs.table === payload.table) return;
this.changeBreadcrumbs(payload);
},
highlightWord (string) {
string = string.replaceAll('<', '&lt;').replaceAll('>', '&gt;');
if (this.searchTerm) {
const regexp = new RegExp(`(${this.searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
return string.replace(regexp, '<span class="text-primary">$1</span>');
}
else
return string;
},
checkLoadingStatus (name, type) {
return this.workspace.loadingElements.some(el =>
el.name === name &&
el.type === type &&
el.schema === this.database.name);
}
const selectSchema = async (schema: string) => {
if (!loadedSchemas.value.has(schema) && !isLoading.value) {
isLoading.value = true;
setBreadcrumbs({ schema });
await refreshSchema({ uid: props.connection.uid, schema });
addLoadedSchema(schema);
isLoading.value = false;
}
};
const selectTable = ({ schema, table }: { schema: string; table: TableInfos }) => {
newTab({
uid: props.connection.uid,
elementName: table.name,
schema: props.database.name,
type: 'temp-data',
elementType: table.type
});
setBreadcrumbs({ schema, [table.type]: table.name });
};
const selectMisc = ({ schema, misc, type }: { schema: string; misc: { name: string }; type: 'trigger' | 'triggerFunction' | 'function' | 'routine' | 'scheduler' }) => {
const miscTempTabs = {
trigger: 'temp-trigger-props',
triggerFunction: 'temp-trigger-function-props',
function: 'temp-function-props',
routine: 'temp-routine-props',
scheduler: 'temp-scheduler-props'
};
newTab({
uid: props.connection.uid,
elementName: misc.name,
schema: props.database.name,
type: miscTempTabs[type],
elementType: type
});
setBreadcrumbs({ schema, [type]: misc.name });
};
const openDataTab = ({ schema, table }: { schema: string; table: TableInfos }) => {
newTab({ uid: props.connection.uid, elementName: table.name, schema: props.database.name, type: 'data', elementType: table.type });
setBreadcrumbs({ schema, [table.type]: table.name });
};
const openMiscPermanentTab = ({ schema, misc, type }: { schema: string; misc: { name: string }; type: 'trigger' | 'triggerFunction' | 'function' | 'routine' | 'scheduler' }) => {
const miscTabs = {
trigger: 'trigger-props',
triggerFunction: 'trigger-function-props',
function: 'function-props',
routine: 'routine-props',
scheduler: 'scheduler-props'
};
newTab({
uid: props.connection.uid,
elementName: misc.name,
schema: props.database.name,
type: miscTabs[type],
elementType: type
});
setBreadcrumbs({ schema, [type]: misc.name });
};
const showSchemaContext = (event: MouseEvent, schema: string) => {
emit('show-schema-context', { event, schema });
};
const showTableContext = (event: MouseEvent, table: TableInfos) => {
emit('show-table-context', { event, schema: props.database.name, table });
};
const showMiscContext = (event: MouseEvent, misc: TriggerInfos | TriggerFunctionInfos | RoutineInfos | FunctionInfos | EventInfos) => {
emit('show-misc-context', { event, schema: props.database.name, misc });
};
const showMiscFolderContext = (event: MouseEvent, type: string) => {
emit('show-misc-folder-context', { event, schema: props.database.name, type });
};
const piePercentage = (val: number) => {
const perc = val / maxSize.value * 100;
if (applicationTheme.value === 'dark')
return { background: `conic-gradient(lime ${perc}%, white 0)` };
else
return { background: `conic-gradient(teal ${perc}%, silver 0)` };
};
const setBreadcrumbs = (payload: Breadcrumb) => {
if (breadcrumbs.value.schema === payload.schema && breadcrumbs.value.table === payload.table) return;
changeBreadcrumbs(payload);
};
const highlightWord = (string: string) => {
string = string.replaceAll('<', '&lt;').replaceAll('>', '&gt;');
if (searchTerm.value) {
const regexp = new RegExp(`(${searchTerm.value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
return string.replace(regexp, '<span class="text-primary">$1</span>');
}
else
return string;
};
const checkLoadingStatus = (name: string, type: string) => {
return workspace.value.loadingElements.some(el =>
el.name === name &&
el.type === type &&
el.schema === props.database.name);
};
defineExpose({ selectSchema, schemaAccordion });
</script>
<style lang="scss">

View File

@ -123,159 +123,154 @@
</BaseContextMenu>
</template>
<script>
<script setup lang="ts">
import { Component, computed, nextTick, Ref, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useNotificationsStore } from '@/stores/notifications';
import { useWorkspacesStore } from '@/stores/workspaces';
import BaseContextMenu from '@/components/BaseContextMenu';
import ConfirmModal from '@/components/BaseConfirmModal';
import ModalEditSchema from '@/components/ModalEditSchema';
import ModalExportSchema from '@/components/ModalExportSchema';
import ModalImportSchema from '@/components/ModalImportSchema';
import BaseContextMenu from '@/components/BaseContextMenu.vue';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import ModalEditSchema from '@/components/ModalEditSchema.vue';
import ModalExportSchema from '@/components/ModalExportSchema.vue';
import ModalImportSchema from '@/components/ModalImportSchema.vue';
import Schema from '@/ipc-api/Schema';
import Application from '@/ipc-api/Application';
import { storeToRefs } from 'pinia';
export default {
name: 'WorkspaceExploreBarSchemaContext',
components: {
BaseContextMenu,
ConfirmModal,
ModalEditSchema,
ModalExportSchema,
ModalImportSchema
},
props: {
contextEvent: MouseEvent,
selectedSchema: String
},
emits: [
'open-create-table-tab',
'open-create-view-tab',
'open-create-trigger-tab',
'open-create-routine-tab',
'open-create-function-tab',
'open-create-trigger-function-tab',
'open-create-scheduler-tab',
'close-context',
'reload'
],
setup () {
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();
const props = defineProps({
contextEvent: MouseEvent,
selectedSchema: String
});
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const emit = defineEmits([
'open-create-table-tab',
'open-create-view-tab',
'open-create-trigger-tab',
'open-create-routine-tab',
'open-create-function-tab',
'open-create-trigger-function-tab',
'open-create-scheduler-tab',
'close-context',
'reload'
]);
const {
getWorkspace,
changeBreadcrumbs
} = workspacesStore;
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();
return {
addNotification,
selectedWorkspace,
getWorkspace,
changeBreadcrumbs
};
},
data () {
return {
isDeleteModal: false,
isEditModal: false,
isExportSchemaModal: false,
isImportSchemaModal: false
};
},
computed: {
workspace () {
return this.getWorkspace(this.selectedWorkspace);
}
},
methods: {
openCreateTableTab () {
this.$emit('open-create-table-tab');
},
openCreateViewTab () {
this.$emit('open-create-view-tab');
},
openCreateTriggerTab () {
this.$emit('open-create-trigger-tab');
},
openCreateRoutineTab () {
this.$emit('open-create-routine-tab');
},
openCreateFunctionTab () {
this.$emit('open-create-function-tab');
},
openCreateTriggerFunctionTab () {
this.$emit('open-create-trigger-function-tab');
},
openCreateSchedulerTab () {
this.$emit('open-create-scheduler-tab');
},
showDeleteModal () {
this.isDeleteModal = true;
},
hideDeleteModal () {
this.isDeleteModal = false;
},
showEditModal () {
this.isEditModal = true;
},
hideEditModal () {
this.isEditModal = false;
this.closeContext();
},
showExportSchemaModal () {
this.isExportSchemaModal = true;
},
hideExportSchemaModal () {
this.isExportSchemaModal = false;
this.closeContext();
},
showImportSchemaModal () {
this.isImportSchemaModal = true;
},
hideImportSchemaModal () {
this.isImportSchemaModal = false;
this.closeContext();
},
async initImport () {
const result = await Application.showOpenDialog({ properties: ['openFile'], filters: [{ name: 'SQL', extensions: ['sql'] }] });
if (result && !result.canceled) {
const file = result.filePaths[0];
this.showImportSchemaModal();
this.$nextTick(() => {
this.$refs.importModalRef.startImport(file);
});
}
},
closeContext () {
this.$emit('close-context');
},
async deleteSchema () {
try {
const { status, response } = await Schema.deleteSchema({
uid: this.selectedWorkspace,
database: this.selectedSchema
});
if (status === 'success') {
if (this.selectedSchema === this.workspace.breadcrumbs.schema)
this.changeBreadcrumbs({ schema: null });
this.closeContext();
this.$emit('reload');
}
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const {
getWorkspace,
changeBreadcrumbs
} = workspacesStore;
const importModalRef: Ref<Component & {startImport: (file: string) => void}> = ref(null);
const isDeleteModal = ref(false);
const isEditModal = ref(false);
const isExportSchemaModal = ref(false);
const isImportSchemaModal = ref(false);
const workspace = computed(() => getWorkspace(selectedWorkspace.value));
const openCreateTableTab = () => {
emit('open-create-table-tab');
};
const openCreateViewTab = () => {
emit('open-create-view-tab');
};
const openCreateTriggerTab = () => {
emit('open-create-trigger-tab');
};
const openCreateRoutineTab = () => {
emit('open-create-routine-tab');
};
const openCreateFunctionTab = () => {
emit('open-create-function-tab');
};
const openCreateTriggerFunctionTab = () => {
emit('open-create-trigger-function-tab');
};
const openCreateSchedulerTab = () => {
emit('open-create-scheduler-tab');
};
const showDeleteModal = () => {
isDeleteModal.value = true;
};
const hideDeleteModal = () => {
isDeleteModal.value = false;
};
const showEditModal = () => {
isEditModal.value = true;
};
const hideEditModal = () => {
isEditModal.value = false;
closeContext();
};
const showExportSchemaModal = () => {
isExportSchemaModal.value = true;
};
const hideExportSchemaModal = () => {
isExportSchemaModal.value = false;
closeContext();
};
const showImportSchemaModal = () => {
isImportSchemaModal.value = true;
};
const hideImportSchemaModal = () => {
isImportSchemaModal.value = false;
closeContext();
};
const initImport = async () => {
const result = await Application.showOpenDialog({ properties: ['openFile'], filters: [{ name: 'SQL', extensions: ['sql'] }] });
if (result && !result.canceled) {
const file = result.filePaths[0];
showImportSchemaModal();
await nextTick();
importModalRef.value.startImport(file);
}
};
const closeContext = () => {
emit('close-context');
};
const deleteSchema = async () => {
try {
const { status, response } = await Schema.deleteSchema({
uid: selectedWorkspace.value,
database: props.selectedSchema
});
if (status === 'success') {
if (props.selectedSchema === workspace.value.breadcrumbs.schema)
changeBreadcrumbs({ schema: null });
closeContext();
emit('reload');
}
else
addNotification({ status: 'error', message: response });
}
catch (err) {
addNotification({ status: 'error', message: err.stack });
}
};
</script>
<style lang="scss" scoped>
.context-submenu {
min-width: 150px !important;

View File

@ -71,151 +71,133 @@
</BaseContextMenu>
</template>
<script>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { useNotificationsStore } from '@/stores/notifications';
import { useWorkspacesStore } from '@/stores/workspaces';
import BaseContextMenu from '@/components/BaseContextMenu';
import ConfirmModal from '@/components/BaseConfirmModal';
import BaseContextMenu from '@/components/BaseContextMenu.vue';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import Tables from '@/ipc-api/Tables';
import { storeToRefs } from 'pinia';
export default {
name: 'WorkspaceExploreBarTableContext',
components: {
BaseContextMenu,
ConfirmModal
},
props: {
contextEvent: MouseEvent,
selectedTable: Object,
selectedSchema: String
},
emits: ['close-context', 'duplicate-table', 'reload', 'delete-table'],
setup () {
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();
const props = defineProps({
contextEvent: MouseEvent,
selectedTable: Object,
selectedSchema: String
});
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const emit = defineEmits(['close-context', 'duplicate-table', 'reload', 'delete-table']);
const {
getWorkspace,
newTab,
removeTabs,
addLoadingElement,
removeLoadingElement,
changeBreadcrumbs
} = workspacesStore;
const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore();
return {
addNotification,
getWorkspace,
newTab,
removeTabs,
addLoadingElement,
removeLoadingElement,
changeBreadcrumbs,
selectedWorkspace
};
},
data () {
return {
isDeleteModal: false,
isEmptyModal: false
};
},
computed: {
workspace () {
return this.getWorkspace(this.selectedWorkspace);
},
customizations () {
return this.workspace && this.workspace.customizations ? this.workspace.customizations : {};
}
},
methods: {
showDeleteModal () {
this.isDeleteModal = true;
},
hideDeleteModal () {
this.isDeleteModal = false;
},
showEmptyModal () {
this.isEmptyModal = true;
},
hideEmptyModal () {
this.isEmptyModal = false;
},
closeContext () {
this.$emit('close-context');
},
openTableSettingTab () {
this.newTab({
uid: this.selectedWorkspace,
elementName: this.selectedTable.name,
schema: this.selectedSchema,
type: 'table-props',
elementType: 'table'
});
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
this.changeBreadcrumbs({
schema: this.selectedSchema,
table: this.selectedTable.name
});
const {
getWorkspace,
newTab,
addLoadingElement,
removeLoadingElement,
changeBreadcrumbs
} = workspacesStore;
this.closeContext();
},
openViewSettingTab () {
this.newTab({
uid: this.selectedWorkspace,
elementType: 'table',
elementName: this.selectedTable.name,
schema: this.selectedSchema,
type: 'view-props'
});
const isDeleteModal = ref(false);
const isEmptyModal = ref(false);
this.changeBreadcrumbs({
schema: this.selectedSchema,
view: this.selectedTable.name
});
const workspace = computed(() => getWorkspace(selectedWorkspace.value));
const customizations = computed(() => workspace.value && workspace.value.customizations ? workspace.value.customizations : null);
this.closeContext();
},
duplicateTable () {
this.$emit('duplicate-table', { schema: this.selectedSchema, table: this.selectedTable });
},
async emptyTable () {
this.closeContext();
const showDeleteModal = () => {
isDeleteModal.value = true;
};
this.addLoadingElement({
name: this.selectedTable.name,
schema: this.selectedSchema,
type: 'table'
});
const hideDeleteModal = () => {
isDeleteModal.value = false;
};
try {
const { status, response } = await Tables.truncateTable({
uid: this.selectedWorkspace,
table: this.selectedTable.name,
schema: this.selectedSchema
});
const showEmptyModal = () => {
isEmptyModal.value = true;
};
if (status === 'success')
this.$emit('reload');
else
this.addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
}
const hideEmptyModal = () => {
isEmptyModal.value = false;
};
this.removeLoadingElement({
name: this.selectedTable.name,
schema: this.selectedSchema,
type: 'table'
});
},
deleteTable () {
this.$emit('delete-table', { schema: this.selectedSchema, table: this.selectedTable });
}
const closeContext = () => {
emit('close-context');
};
const openTableSettingTab = () => {
newTab({
uid: selectedWorkspace.value,
elementName: props.selectedTable.name,
schema: props.selectedSchema,
type: 'table-props',
elementType: 'table'
});
changeBreadcrumbs({
schema: props.selectedSchema,
table: props.selectedTable.name
});
closeContext();
};
const openViewSettingTab = () => {
newTab({
uid: selectedWorkspace.value,
elementType: 'table',
elementName: props.selectedTable.name,
schema: props.selectedSchema,
type: 'view-props'
});
changeBreadcrumbs({
schema: props.selectedSchema,
view: props.selectedTable.name
});
closeContext();
};
const duplicateTable = () => {
emit('duplicate-table', { schema: props.selectedSchema, table: props.selectedTable });
};
const emptyTable = async () => {
closeContext();
addLoadingElement({
name: props.selectedTable.name,
schema: props.selectedSchema,
type: 'table'
});
try {
const { status, response } = await Tables.truncateTable({
uid: selectedWorkspace.value,
table: props.selectedTable.name,
schema: props.selectedSchema
});
if (status === 'success')
emit('reload');
else
addNotification({ status: 'error', message: response });
}
catch (err) {
addNotification({ status: 'error', message: err.stack });
}
removeLoadingElement({
name: props.selectedTable.name,
schema: props.selectedSchema,
type: 'table'
});
};
const deleteTable = () => {
emit('delete-table', { schema: props.selectedSchema, table: props.selectedTable });
};
</script>

View File

@ -4,12 +4,12 @@ import connStringConstruct from '../libs/connStringDecode';
import { unproxify } from '../libs/unproxify';
export default class {
static makeTest (params: ConnectionParams & { pgConnString: string }): Promise<IpcResponse> {
static makeTest (params: ConnectionParams & { pgConnString?: string }): Promise<IpcResponse> {
const newParams = connStringConstruct(params) as ConnectionParams;
return ipcRenderer.invoke('test-connection', unproxify(newParams));
}
static connect (params: ConnectionParams & { pgConnString: string }): Promise<IpcResponse> {
static connect (params: ConnectionParams & { pgConnString?: string }): Promise<IpcResponse> {
const newParams = connStringConstruct(params) as ConnectionParams;
return ipcRenderer.invoke('connect', unproxify(newParams));
}

View File

@ -1,9 +1,9 @@
import { AlterFunctionParams, CreateFunctionParams, FunctionInfos, IpcResponse } from 'common/interfaces/antares';
import { AlterFunctionParams, CreateFunctionParams, IpcResponse } from 'common/interfaces/antares';
import { ipcRenderer } from 'electron';
import { unproxify } from '../libs/unproxify';
export default class {
static getFunctionInformations (params: { uid: string; schema: string; func: string}): Promise<IpcResponse<FunctionInfos>> {
static getFunctionInformations (params: { uid: string; schema: string; func: string}): Promise<IpcResponse> {
return ipcRenderer.invoke('get-function-informations', unproxify(params));
}

View File

@ -1,9 +1,9 @@
import { ipcRenderer } from 'electron';
import { unproxify } from '../libs/unproxify';
import { AlterRoutineParams, CreateRoutineParams, IpcResponse, RoutineInfos } from 'common/interfaces/antares';
import { AlterRoutineParams, CreateRoutineParams, IpcResponse } from 'common/interfaces/antares';
export default class {
static getRoutineInformations (params: { uid: string; schema: string; routine: string}): Promise<IpcResponse<RoutineInfos>> {
static getRoutineInformations (params: { uid: string; schema: string; routine: string}): Promise<IpcResponse> {
return ipcRenderer.invoke('get-routine-informations', unproxify(params));
}

View File

@ -19,7 +19,7 @@ export default class {
return ipcRenderer.invoke('create-scheduler', unproxify(params));
}
static toggleScheduler (params: { uid: string; schema: string; scheduler: string}): Promise<IpcResponse> {
static toggleScheduler (params: { uid: string; schema: string; scheduler: string; enabled: boolean}): Promise<IpcResponse> {
return ipcRenderer.invoke('toggle-scheduler', unproxify(params));
}
}

View File

@ -7,7 +7,7 @@ export default class {
return ipcRenderer.invoke('get-trigger-informations', unproxify(params));
}
static dropTrigger (params: { schema: string; trigger: string }): Promise<IpcResponse> {
static dropTrigger (params: { uid: string; schema: string; trigger: string }): Promise<IpcResponse> {
return ipcRenderer.invoke('drop-trigger', unproxify(params));
}
@ -19,7 +19,7 @@ export default class {
return ipcRenderer.invoke('create-trigger', unproxify(params));
}
static toggleTrigger (params: { uid: string; schema: string; trigger: string }): Promise<IpcResponse> {
static toggleTrigger (params: { uid: string; schema: string; trigger: string; enabled: boolean }): Promise<IpcResponse> {
return ipcRenderer.invoke('toggle-trigger', unproxify(params));
}
}

View File

@ -10,7 +10,7 @@ const checkForSSl = (conn: string) => {
return conn.includes('ssl=true');
};
const connStringConstruct = (args: ConnectionParams & { pgConnString: string }): ConnectionParams => {
const connStringConstruct = (args: ConnectionParams & { pgConnString?: string }): ConnectionParams => {
if (!args.pgConnString)
return args;

View File

@ -11,12 +11,14 @@ import { useConnectionsStore } from '@/stores/connections';
import { useNotificationsStore } from '@/stores/notifications';
import { useSettingsStore } from '@/stores/settings';
import {
ClientCode,
CollationInfos,
ConnectionParams,
EventInfos,
FunctionInfos,
RoutineInfos,
TableInfos,
TriggerFunctionInfos,
TriggerInfos,
TypesGroup
} from 'common/interfaces/antares';
@ -44,12 +46,13 @@ export interface WorkspaceStructure {
schedulers: EventInfos[];
tables: TableInfos[];
triggers: TriggerInfos[];
triggerFunctions: TriggerFunctionInfos[];
size: number;
}
export interface Breadcrumb {
function?: string;
procedure?: string;
routine?: string;
query?: string;
scheduler?: string;
schema?: string;
@ -61,7 +64,7 @@ export interface Breadcrumb {
export interface Workspace {
uid: string;
client?: string;
client?: ClientCode;
connectionStatus: string;
selectedTab: string | number;
searchTerm: string;
@ -133,7 +136,7 @@ export const useWorkspacesStore = defineStore('workspaces', {
else
this.selectedWorkspace = uid;
},
async connectWorkspace (connection: ConnectionParams & { pgConnString: string }) {
async connectWorkspace (connection: ConnectionParams & { pgConnString?: string }) {
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === connection.uid
? {
...workspace,
@ -405,7 +408,7 @@ export const useWorkspacesStore = defineStore('workspaces', {
table: null,
trigger: null,
triggerFunction: null,
procedure: null,
routine: null,
function: null,
scheduler: null,
view: null,

View File

@ -21,7 +21,6 @@ test('launch app', async () => {
test('main window elements visibility', async () => {
const visibleSelectors = [
'#titlebar',
'#window-content',
'#settingbar',
'#footer'