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:
@ -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', () => {
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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',
|
||||||
|
21
src/renderer/stores/schemaExport.ts
Normal file
21
src/renderer/stores/schemaExport.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
Reference in New Issue
Block a user