1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-06-05 21:59:22 +02:00

feat: ability to export a table dump from table context menu

This commit is contained in:
2023-08-11 11:49:49 +02:00
parent 2e39d810b5
commit 84b2255bf4
6 changed files with 88 additions and 26 deletions

View File

@ -21,7 +21,15 @@
<BaseTextEditor class="d-none" value="" /> <BaseTextEditor class="d-none" value="" />
</div> </div>
</div> </div>
<ModalAllConnections v-if="isAllConnectionsModal" @close="isAllConnectionsModal = false" /> <ModalAllConnections
v-if="isAllConnectionsModal"
@close="isAllConnectionsModal = false"
/>
<ModalExportSchema
v-if="isExportSchemaModal"
@close="hideExportModal"
/>
</div> </div>
</template> </template>
@ -33,9 +41,11 @@ import { useI18n } from 'vue-i18n';
import { Menu, getCurrentWindow } from '@electron/remote'; import { Menu, getCurrentWindow } from '@electron/remote';
import { useApplicationStore } from '@/stores/application'; import { useApplicationStore } from '@/stores/application';
import { useConnectionsStore } from '@/stores/connections'; import { useConnectionsStore } from '@/stores/connections';
import { useSchemaExportStore } from '@/stores/schemaExport';
import { useSettingsStore } from '@/stores/settings'; import { useSettingsStore } from '@/stores/settings';
import { useWorkspacesStore } from '@/stores/workspaces'; import { useWorkspacesStore } from '@/stores/workspaces';
import TheSettingBar from '@/components/TheSettingBar.vue'; import TheSettingBar from '@/components/TheSettingBar.vue';
import ModalExportSchema from '@/components/ModalExportSchema.vue';
const { t } = useI18n(); const { t } = useI18n();
@ -65,6 +75,10 @@ const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const { checkVersionUpdate } = applicationStore; const { checkVersionUpdate } = applicationStore;
const { changeApplicationTheme } = settingsStore; const { changeApplicationTheme } = settingsStore;
const schemaExportStore = useSchemaExportStore();
const { hideExportModal } = schemaExportStore;
const { isExportModal: isExportSchemaModal } = storeToRefs(schemaExportStore);
const isAllConnectionsModal: Ref<boolean> = ref(false); const isAllConnectionsModal: Ref<boolean> = ref(false);
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {

View File

@ -154,6 +154,7 @@
v-for="item in tables" v-for="item in tables"
:key="item.table" :key="item.table"
class="tr" class="tr"
:class="{'selected': item.table === selectedTable}"
> >
<div class="td"> <div class="td">
{{ item.table }} {{ item.table }}
@ -278,6 +279,7 @@ import { useI18n } from 'vue-i18n';
import { ClientCode, SchemaInfos } from 'common/interfaces/antares'; import { ClientCode, SchemaInfos } from 'common/interfaces/antares';
import { ExportOptions, ExportState } from 'common/interfaces/exporter'; import { ExportOptions, ExportState } from 'common/interfaces/exporter';
import { useNotificationsStore } from '@/stores/notifications'; import { useNotificationsStore } from '@/stores/notifications';
import { useSchemaExportStore } from '@/stores/schemaExport';
import { useWorkspacesStore } from '@/stores/workspaces'; import { useWorkspacesStore } from '@/stores/workspaces';
import { useFocusTrap } from '@/composables/useFocusTrap'; import { useFocusTrap } from '@/composables/useFocusTrap';
import Application from '@/ipc-api/Application'; import Application from '@/ipc-api/Application';
@ -285,15 +287,12 @@ import Schema from '@/ipc-api/Schema';
import { Customizations } from 'common/interfaces/customizations'; import { Customizations } from 'common/interfaces/customizations';
import BaseSelect from '@/components/BaseSelect.vue'; import BaseSelect from '@/components/BaseSelect.vue';
const props = defineProps({
selectedSchema: String
});
const emit = defineEmits(['close']); const emit = defineEmits(['close']);
const { t } = useI18n(); const { t } = useI18n();
const { addNotification } = useNotificationsStore(); const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore(); const workspacesStore = useWorkspacesStore();
const schemaExportStore = useSchemaExportStore();
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore); const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
@ -304,6 +303,8 @@ const {
refreshSchema refreshSchema
} = workspacesStore; } = workspacesStore;
const { selectedTable, selectedSchema } = storeToRefs(schemaExportStore);
const isExporting = ref(false); const isExporting = ref(false);
const isRefreshing = ref(false); const isRefreshing = ref(false);
const progressPercentage = ref(0); const progressPercentage = ref(0);
@ -315,7 +316,7 @@ const tables: Ref<{
includeDropStatement: boolean; includeDropStatement: boolean;
}[]> = ref([]); }[]> = ref([]);
const options: Ref<Partial<ExportOptions>> = ref({ const options: Ref<Partial<ExportOptions>> = ref({
schema: props.selectedSchema, schema: selectedSchema.value,
includes: {} as {[key: string]: boolean}, includes: {} as {[key: string]: boolean},
outputFormat: 'sql' as 'sql' | 'sql.zip', outputFormat: 'sql' as 'sql' | 'sql.zip',
sqlInsertAfter: 250, sqlInsertAfter: 250,
@ -327,7 +328,7 @@ const chosenFilename = ref('');
const currentWorkspace = computed(() => getWorkspace(selectedWorkspace.value)); const currentWorkspace = computed(() => getWorkspace(selectedWorkspace.value));
const clientCustoms: Ref<Customizations> = computed(() => currentWorkspace.value.customizations); const clientCustoms: Ref<Customizations> = computed(() => currentWorkspace.value.customizations);
const schemaItems = computed(() => { const schemaItems = computed(() => {
const db: SchemaInfos = currentWorkspace.value.structure.find((db: SchemaInfos) => db.name === props.selectedSchema); const db: SchemaInfos = currentWorkspace.value.structure.find((db: SchemaInfos) => db.name === selectedSchema.value);
if (db) if (db)
return db.tables.filter(table => table.type === 'table'); return db.tables.filter(table => table.type === 'table');
@ -335,7 +336,7 @@ const schemaItems = computed(() => {
}); });
const filename = computed(() => { const filename = computed(() => {
const date = moment().format('YYYY-MM-DD_HH-mm-ss'); const date = moment().format('YYYY-MM-DD_HH-mm-ss');
return `${props.selectedSchema}_${date}`; return `${selectedTable.value || selectedSchema.value}_${date}`;
}); });
const dumpFilePath = computed(() => `${basePath.value}/${chosenFilename.value || filename.value}.${options.value.outputFormat}`); const dumpFilePath = computed(() => `${basePath.value}/${chosenFilename.value || filename.value}.${options.value.outputFormat}`);
const includeStructureStatus = computed(() => { const includeStructureStatus = computed(() => {
@ -360,7 +361,7 @@ const startExport = async () => {
const params = { const params = {
uid, uid,
type: client, type: client,
schema: props.selectedSchema, schema: selectedSchema.value,
outputFile: dumpFilePath.value, outputFile: dumpFilePath.value,
tables: [...tables.value], tables: [...tables.value],
...options.value ...options.value
@ -438,7 +439,7 @@ const toggleAllTablesOption = (option: 'includeStructure' | 'includeContent' |'i
const refresh = async () => { const refresh = async () => {
isRefreshing.value = true; isRefreshing.value = true;
await refreshSchema({ uid: currentWorkspace.value.uid, schema: props.selectedSchema }); await refreshSchema({ uid: currentWorkspace.value.uid, schema: selectedSchema.value });
isRefreshing.value = false; isRefreshing.value = false;
}; };
@ -453,12 +454,31 @@ const openPathDialog = async () => {
window.addEventListener('keydown', onKey); window.addEventListener('keydown', onKey);
if (selectedTable.value) {
setTimeout(() => {
const element = document.querySelector<HTMLElement>('.modal.active .selected');
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');
}
}
}, 100);
}
basePath.value = await Application.getDownloadPathDirectory(); basePath.value = await Application.getDownloadPathDirectory();
tables.value = schemaItems.value.map(item => ({ tables.value = schemaItems.value.map(item => ({
table: item.name, table: item.name,
includeStructure: true, includeStructure: !selectedTable.value ? true : selectedTable.value === item.name,
includeContent: true, includeContent: !selectedTable.value ? true : selectedTable.value === item.name,
includeDropStatement: true includeDropStatement: !selectedTable.value ? true : selectedTable.value === item.name
})); }));
const structure = ['functions', 'views', 'triggers', 'routines', 'schedulers']; const structure = ['functions', 'views', 'triggers', 'routines', 'schedulers'];
@ -466,7 +486,7 @@ const openPathDialog = async () => {
structure.forEach((feat: keyof Customizations) => { structure.forEach((feat: keyof Customizations) => {
const val = clientCustoms.value[feat]; const val = clientCustoms.value[feat];
if (val) if (val)
options.value.includes[feat] = true; options.value.includes[feat] = !selectedTable.value;
}); });
ipcRenderer.on('export-progress', updateProgress); ipcRenderer.on('export-progress', updateProgress);

View File

@ -109,11 +109,6 @@
:selected-schema="selectedSchema" :selected-schema="selectedSchema"
@close="hideEditModal" @close="hideEditModal"
/> />
<ModalExportSchema
v-if="isExportSchemaModal"
:selected-schema="selectedSchema"
@close="hideExportSchemaModal"
/>
<ModalImportSchema <ModalImportSchema
v-if="isImportSchemaModal" v-if="isImportSchemaModal"
ref="importModalRef" ref="importModalRef"
@ -128,10 +123,10 @@ import { Component, computed, nextTick, Ref, ref } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useNotificationsStore } from '@/stores/notifications'; import { useNotificationsStore } from '@/stores/notifications';
import { useWorkspacesStore } from '@/stores/workspaces'; import { useWorkspacesStore } from '@/stores/workspaces';
import { useSchemaExportStore } from '@/stores/schemaExport';
import BaseContextMenu from '@/components/BaseContextMenu.vue'; import BaseContextMenu from '@/components/BaseContextMenu.vue';
import ConfirmModal from '@/components/BaseConfirmModal.vue'; import ConfirmModal from '@/components/BaseConfirmModal.vue';
import ModalEditSchema from '@/components/ModalEditSchema.vue'; import ModalEditSchema from '@/components/ModalEditSchema.vue';
import ModalExportSchema from '@/components/ModalExportSchema.vue';
import ModalImportSchema from '@/components/ModalImportSchema.vue'; import ModalImportSchema from '@/components/ModalImportSchema.vue';
import Schema from '@/ipc-api/Schema'; import Schema from '@/ipc-api/Schema';
import Application from '@/ipc-api/Application'; import Application from '@/ipc-api/Application';
@ -158,6 +153,8 @@ const emit = defineEmits([
const { addNotification } = useNotificationsStore(); const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore(); const workspacesStore = useWorkspacesStore();
const schemaExportStore = useSchemaExportStore();
const { showExportModal } = schemaExportStore;
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore); const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
@ -169,7 +166,6 @@ const {
const importModalRef: Ref<Component & {startImport: (file: string) => void}> = ref(null); const importModalRef: Ref<Component & {startImport: (file: string) => void}> = ref(null);
const isDeleteModal = ref(false); const isDeleteModal = ref(false);
const isEditModal = ref(false); const isEditModal = ref(false);
const isExportSchemaModal = ref(false);
const isImportSchemaModal = ref(false); const isImportSchemaModal = ref(false);
const workspace = computed(() => getWorkspace(selectedWorkspace.value)); const workspace = computed(() => getWorkspace(selectedWorkspace.value));
@ -220,11 +216,7 @@ const hideEditModal = () => {
}; };
const showExportSchemaModal = () => { const showExportSchemaModal = () => {
isExportSchemaModal.value = true; showExportModal(props.selectedSchema);
};
const hideExportSchemaModal = () => {
isExportSchemaModal.value = false;
closeContext(); closeContext();
}; };

View File

@ -10,6 +10,13 @@
> >
<span class="d-flex"><i class="mdi mdi-18px mdi-wrench-cog text-light pr-1" /> {{ t('application.settings') }}</span> <span class="d-flex"><i class="mdi mdi-18px mdi-wrench-cog text-light pr-1" /> {{ t('application.settings') }}</span>
</div> </div>
<div
v-if="selectedTable && selectedTable.type === 'table' && customizations.schemaExport"
class="context-element"
@click="showTableExportModal"
>
<span class="d-flex"><i class="mdi mdi-18px mdi-table-arrow-right text-light pr-1" /> {{ t('database.exportTable') }}</span>
</div>
<div <div
v-if="selectedTable && selectedTable.type === 'view' && customizations.viewSettings" v-if="selectedTable && selectedTable.type === 'view' && customizations.viewSettings"
class="context-element" class="context-element"
@ -81,6 +88,7 @@ import { computed, ref } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useNotificationsStore } from '@/stores/notifications'; import { useNotificationsStore } from '@/stores/notifications';
import { useWorkspacesStore } from '@/stores/workspaces'; import { useWorkspacesStore } from '@/stores/workspaces';
import { useSchemaExportStore } from '@/stores/schemaExport';
import BaseContextMenu from '@/components/BaseContextMenu.vue'; import BaseContextMenu from '@/components/BaseContextMenu.vue';
import ConfirmModal from '@/components/BaseConfirmModal.vue'; import ConfirmModal from '@/components/BaseConfirmModal.vue';
import Tables from '@/ipc-api/Tables'; import Tables from '@/ipc-api/Tables';
@ -98,6 +106,7 @@ const emit = defineEmits(['close-context', 'duplicate-table', 'reload', 'delete-
const { addNotification } = useNotificationsStore(); const { addNotification } = useNotificationsStore();
const workspacesStore = useWorkspacesStore(); const workspacesStore = useWorkspacesStore();
const { showExportModal } = useSchemaExportStore();
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore); const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
@ -116,6 +125,11 @@ const forceTruncate = ref(false);
const workspace = computed(() => getWorkspace(selectedWorkspace.value)); const workspace = computed(() => getWorkspace(selectedWorkspace.value));
const customizations = computed(() => workspace.value && workspace.value.customizations ? workspace.value.customizations : null); const customizations = computed(() => workspace.value && workspace.value.customizations ? workspace.value.customizations : null);
const showTableExportModal = () => {
showExportModal(props.selectedSchema, props.selectedTable.name);
closeContext();
};
const showDeleteModal = () => { const showDeleteModal = () => {
isDeleteModal.value = true; isDeleteModal.value = true;
}; };

View File

@ -181,6 +181,7 @@ export const enUS = {
emptyTable: 'Empty table', emptyTable: 'Empty table',
duplicateTable: 'Duplicate table', duplicateTable: 'Duplicate table',
deleteTable: 'Delete table', deleteTable: 'Delete table',
exportTable: 'Export table',
emptyConfirm: 'Do you confirm to empty', emptyConfirm: 'Do you confirm to empty',
thereAreNoIndexes: 'There are no indexes', thereAreNoIndexes: 'There are no indexes',
thereAreNoForeign: 'There are no foreign keys', thereAreNoForeign: 'There are no foreign keys',

View File

@ -0,0 +1,21 @@
import { defineStore } from 'pinia';
export const useSchemaExportStore = defineStore('schemaExport', {
state: () => ({
isExportModal: false,
selectedTable: undefined as undefined | string,
selectedSchema: undefined as undefined | string
}),
actions: {
showExportModal (schema?: string, table?: string) {
this.selectedTable = table;
this.selectedSchema = schema;
this.isExportModal = true;
},
hideExportModal () {
this.isExportModal = false;
this.selectedTable = undefined;
this.selectedSchema = undefined;
}
}
});