mirror of
https://github.com/Fabio286/antares.git
synced 2025-02-03 10:47:31 +01:00
refactor: ts and composition api on more elements
This commit is contained in:
parent
5a50ba88e8
commit
84826ff4c0
@ -73,6 +73,19 @@ export interface TypesGroup {
|
||||
}
|
||||
|
||||
// Tables
|
||||
export interface TableInfos {
|
||||
name: string;
|
||||
type: string;
|
||||
rows: number;
|
||||
created: Date;
|
||||
updated: Date;
|
||||
engine: string;
|
||||
comment: string;
|
||||
size: number;
|
||||
autoIncrement: number;
|
||||
collation: string;
|
||||
}
|
||||
|
||||
export interface TableField {
|
||||
name: string;
|
||||
key: string;
|
||||
@ -87,7 +100,7 @@ export interface TableField {
|
||||
unsigned?: boolean;
|
||||
zerofill?: boolean;
|
||||
order?: number;
|
||||
default?: number | string;
|
||||
default?: string;
|
||||
enumValues?: string;
|
||||
charset?: string;
|
||||
collation?: string;
|
||||
@ -97,6 +110,7 @@ export interface TableField {
|
||||
comment?: string;
|
||||
after?: string;
|
||||
orgName?: string;
|
||||
length?: number;
|
||||
}
|
||||
|
||||
export interface TableIndex {
|
||||
@ -170,6 +184,7 @@ export interface AlterTableParams {
|
||||
}
|
||||
|
||||
// Views
|
||||
export type ViewInfos = TableInfos
|
||||
export interface CreateViewParams {
|
||||
schema: string;
|
||||
name: string;
|
||||
@ -185,6 +200,18 @@ export interface AlterViewParams extends CreateViewParams {
|
||||
}
|
||||
|
||||
// Triggers
|
||||
export interface TriggerInfos {
|
||||
name: string;
|
||||
statement: string;
|
||||
timing: string;
|
||||
definer: string;
|
||||
event: string;
|
||||
table: string;
|
||||
sqlMode: string;
|
||||
created: Date;
|
||||
charset: string;
|
||||
}
|
||||
|
||||
export interface CreateTriggerParams {
|
||||
definer?: string;
|
||||
schema: string;
|
||||
@ -200,6 +227,19 @@ export interface AlterTriggerParams extends CreateTriggerParams {
|
||||
}
|
||||
|
||||
// Routines & Functions
|
||||
export interface RoutineInfos {
|
||||
name: string;
|
||||
type: string;
|
||||
definer: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
comment?: string;
|
||||
charset?: string;
|
||||
security?: string;
|
||||
}
|
||||
|
||||
export type FunctionInfos = RoutineInfos
|
||||
|
||||
export interface FunctionParam {
|
||||
context: string;
|
||||
name: string;
|
||||
@ -244,6 +284,29 @@ export interface AlterFunctionParams extends CreateFunctionParams {
|
||||
}
|
||||
|
||||
// Events
|
||||
export interface EventInfos {
|
||||
name: string;
|
||||
definition: string;
|
||||
type: string;
|
||||
definer: string;
|
||||
body: string;
|
||||
starts: string;
|
||||
ends: string;
|
||||
enabled: boolean;
|
||||
executeAt: string;
|
||||
intervalField: string;
|
||||
intervalValue: string;
|
||||
onCompletion: string;
|
||||
originator: string;
|
||||
sqlMode: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
lastExecuted: string;
|
||||
comment: string;
|
||||
charset: string;
|
||||
timezone: string;
|
||||
}
|
||||
|
||||
export interface CreateEventParams {
|
||||
definer?: string;
|
||||
schema: string;
|
||||
@ -263,6 +326,17 @@ export interface AlterEventParams extends CreateEventParams {
|
||||
oldName?: string;
|
||||
}
|
||||
|
||||
// Schema
|
||||
export interface SchemaInfos {
|
||||
name: string;
|
||||
size: number;
|
||||
tables: TableInfos[];
|
||||
functions: RoutineInfos[];
|
||||
procedures: RoutineInfos[];
|
||||
triggers: TriggerInfos[];
|
||||
schedulers: EventInfos[];
|
||||
}
|
||||
|
||||
// Query
|
||||
export interface QueryBuilderObject {
|
||||
schema: string;
|
||||
|
@ -172,7 +172,10 @@ export default (connections: {[key: string]: antares.Client}) => {
|
||||
});
|
||||
|
||||
ipcMain.handle('export', (event, { uid, type, tables, ...rest }) => {
|
||||
if (exporter !== null) return;
|
||||
if (exporter !== null) {
|
||||
exporter.kill();
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve/*, reject */) => {
|
||||
(async () => {
|
||||
@ -265,7 +268,10 @@ export default (connections: {[key: string]: antares.Client}) => {
|
||||
});
|
||||
|
||||
ipcMain.handle('import-sql', async (event, options) => {
|
||||
if (importer !== null) return;
|
||||
if (importer !== null) {
|
||||
importer.kill();
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve/*, reject */) => {
|
||||
(async () => {
|
||||
|
@ -321,7 +321,7 @@ export class MySQLClient extends AntaresCore {
|
||||
return filteredDatabases.map(db => {
|
||||
if (schemas.has(db.Database)) {
|
||||
// TABLES
|
||||
const remappedTables = tablesArr.filter(table => table.Db === db.Database).map(table => {
|
||||
const remappedTables: antares.TableInfos[] = tablesArr.filter(table => table.Db === db.Database).map(table => {
|
||||
let tableType;
|
||||
switch (table.Comment) {
|
||||
case 'VIEW':
|
||||
@ -350,7 +350,7 @@ export class MySQLClient extends AntaresCore {
|
||||
});
|
||||
|
||||
// PROCEDURES
|
||||
const remappedProcedures = procedures.filter(procedure => procedure.Db === db.Database).map(procedure => {
|
||||
const remappedProcedures: antares.RoutineInfos[] = procedures.filter(procedure => procedure.Db === db.Database).map(procedure => {
|
||||
return {
|
||||
name: procedure.Name,
|
||||
type: procedure.Type,
|
||||
@ -364,7 +364,7 @@ export class MySQLClient extends AntaresCore {
|
||||
});
|
||||
|
||||
// FUNCTIONS
|
||||
const remappedFunctions = functions.filter(func => func.Db === db.Database).map(func => {
|
||||
const remappedFunctions: antares.FunctionInfos[] = functions.filter(func => func.Db === db.Database).map(func => {
|
||||
return {
|
||||
name: func.Name,
|
||||
type: func.Type,
|
||||
@ -378,7 +378,7 @@ export class MySQLClient extends AntaresCore {
|
||||
});
|
||||
|
||||
// SCHEDULERS
|
||||
const remappedSchedulers = schedulers.filter(scheduler => scheduler.Db === db.Database).map(scheduler => {
|
||||
const remappedSchedulers: antares.EventInfos[] = schedulers.filter(scheduler => scheduler.Db === db.Database).map(scheduler => {
|
||||
return {
|
||||
name: scheduler.EVENT_NAME,
|
||||
definition: scheduler.EVENT_DEFINITION,
|
||||
@ -404,7 +404,7 @@ export class MySQLClient extends AntaresCore {
|
||||
});
|
||||
|
||||
// TRIGGERS
|
||||
const remappedTriggers = triggersArr.filter(trigger => trigger.Db === db.Database).map(trigger => {
|
||||
const remappedTriggers: antares.TriggerInfos[] = triggersArr.filter(trigger => trigger.Db === db.Database).map(trigger => {
|
||||
return {
|
||||
name: trigger.Trigger,
|
||||
statement: trigger.Statement,
|
||||
|
@ -10,7 +10,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { onMounted, watch } from 'vue';
|
||||
import * as ace from 'ace-builds';
|
||||
import 'ace-builds/webpack-resolver';
|
||||
import { storeToRefs } from 'pinia';
|
||||
@ -28,7 +28,6 @@ const props = defineProps({
|
||||
});
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
const settingsStore = useSettingsStore();
|
||||
const mode = ref(props.mode);
|
||||
|
||||
const {
|
||||
editorTheme,
|
||||
@ -40,7 +39,7 @@ const {
|
||||
let editor: ace.Ace.Editor;
|
||||
const id = uidGen();
|
||||
|
||||
watch(mode, () => {
|
||||
watch(() => props.mode, () => {
|
||||
if (editor)
|
||||
editor.session.setMode(`ace/mode/${props.mode}`);
|
||||
});
|
||||
@ -82,7 +81,7 @@ watch(lineWrap, () => {
|
||||
|
||||
onMounted(() => {
|
||||
editor = ace.edit(`editor-${id}`, {
|
||||
mode: `ace/mode/${mode.value}`,
|
||||
mode: `ace/mode/${props.mode}`,
|
||||
theme: `ace/theme/${editorTheme.value}`,
|
||||
value: props.modelValue || '',
|
||||
fontSize: 14,
|
||||
|
@ -10,8 +10,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { ref, watch } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
message: {
|
||||
|
@ -4,7 +4,7 @@
|
||||
class="form-select pl-1 pr-4"
|
||||
:class="{'small-select': size === 'small'}"
|
||||
@change="onChange"
|
||||
@blur="$emit('blur')"
|
||||
@blur="emit('blur')"
|
||||
>
|
||||
<option v-if="!isValidDefault" :value="modelValue">
|
||||
{{ modelValue === null ? 'NULL' : modelValue }}
|
||||
@ -20,88 +20,84 @@
|
||||
</select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, Ref, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { TEXT, LONG_TEXT } from 'common/fieldTypes';
|
||||
export default {
|
||||
name: 'ForeignKeySelect',
|
||||
props: {
|
||||
modelValue: [String, Number],
|
||||
keyUsage: Object,
|
||||
size: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['update:modelValue', 'blur'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
return { addNotification, selectedWorkspace };
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
foreignList: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isValidDefault () {
|
||||
if (!this.foreignList.length) return true;
|
||||
if (this.modelValue === null) return false;
|
||||
return this.foreignList.some(foreign => foreign.foreign_column.toString() === this.modelValue.toString());
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
let foreignDesc;
|
||||
const params = {
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.keyUsage.refSchema,
|
||||
table: this.keyUsage.refTable
|
||||
};
|
||||
|
||||
try { // Field data
|
||||
const { status, response } = await Tables.getTableColumns(params);
|
||||
if (status === 'success') {
|
||||
const textField = response.find(field => [...TEXT, ...LONG_TEXT].includes(field.type) && field.name !== this.keyUsage.refField);
|
||||
foreignDesc = textField ? textField.name : false;
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
try { // Foregn list
|
||||
const { status, response } = await Tables.getForeignList({
|
||||
...params,
|
||||
column: this.keyUsage.refField,
|
||||
description: foreignDesc
|
||||
});
|
||||
|
||||
if (status === 'success')
|
||||
this.foreignList = response.rows;
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange () {
|
||||
this.$emit('update:modelValue', this.$refs.editField.value);
|
||||
},
|
||||
cutText (val) {
|
||||
if (typeof val !== 'string') return val;
|
||||
return val.length > 15 ? `${val.substring(0, 15)}...` : val;
|
||||
}
|
||||
const props = defineProps({
|
||||
modelValue: [String, Number],
|
||||
keyUsage: Object,
|
||||
size: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'blur']);
|
||||
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const editField: Ref<HTMLSelectElement> = ref(null);
|
||||
const foreignList = ref([]);
|
||||
|
||||
const isValidDefault = computed(() => {
|
||||
if (!foreignList.value.length) return true;
|
||||
if (props.modelValue === null) return false;
|
||||
return foreignList.value.some(foreign => foreign.foreign_column.toString() === props.modelValue.toString());
|
||||
});
|
||||
|
||||
const onChange = () => {
|
||||
emit('update:modelValue', editField.value.value);
|
||||
};
|
||||
|
||||
const cutText = (val: string) => {
|
||||
if (typeof val !== 'string') return val;
|
||||
return val.length > 15 ? `${val.substring(0, 15)}...` : val;
|
||||
};
|
||||
|
||||
let foreignDesc;
|
||||
const params = {
|
||||
uid: selectedWorkspace.value,
|
||||
schema: props.keyUsage.refSchema,
|
||||
table: props.keyUsage.refTable
|
||||
};
|
||||
|
||||
(async () => {
|
||||
try { // Field data
|
||||
const { status, response } = await Tables.getTableColumns(params);
|
||||
|
||||
if (status === 'success') {
|
||||
const textField = response.find((field: {type: string; name: string}) => [...TEXT, ...LONG_TEXT].includes(field.type) && field.name !== props.keyUsage.refField);
|
||||
foreignDesc = textField ? textField.name : false;
|
||||
}
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
try { // Foregn list
|
||||
const { status, response } = await Tables.getForeignList({
|
||||
...params,
|
||||
column: props.keyUsage.refField,
|
||||
description: foreignDesc
|
||||
});
|
||||
|
||||
if (status === 'success')
|
||||
foreignList.value = response.rows;
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
@ -55,30 +55,25 @@
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ModalAskCredentials',
|
||||
emits: ['close-asking', 'credentials'],
|
||||
data () {
|
||||
return {
|
||||
credentials: {
|
||||
user: '',
|
||||
password: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
created () {
|
||||
setTimeout(() => {
|
||||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
methods: {
|
||||
closeModal () {
|
||||
this.$emit('close-asking');
|
||||
},
|
||||
sendCredentials () {
|
||||
this.$emit('credentials', this.credentials);
|
||||
}
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import { Ref, ref } from 'vue';
|
||||
|
||||
const credentials = ref({
|
||||
user: '',
|
||||
password: ''
|
||||
});
|
||||
const firstInput: Ref<HTMLInputElement> = ref(null);
|
||||
const emit = defineEmits(['close-asking', 'credentials']);
|
||||
|
||||
const closeModal = () => {
|
||||
emit('close-asking');
|
||||
};
|
||||
|
||||
const sendCredentials = () => {
|
||||
emit('credentials', credentials.value);
|
||||
};
|
||||
|
||||
setTimeout(() => {
|
||||
firstInput.value.focus();
|
||||
}, 20);
|
||||
</script>
|
||||
|
@ -47,83 +47,78 @@
|
||||
</ConfirmModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, PropType, Ref, ref } from 'vue';
|
||||
import { NUMBER, FLOAT } from 'common/fieldTypes';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import { FunctionParam } from 'common/interfaces/antares';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal.vue';
|
||||
|
||||
export default {
|
||||
name: 'ModalAskParameters',
|
||||
components: {
|
||||
ConfirmModal
|
||||
},
|
||||
props: {
|
||||
localRoutine: Object,
|
||||
client: String
|
||||
},
|
||||
emits: ['confirm', 'close'],
|
||||
data () {
|
||||
return {
|
||||
values: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
inParameters () {
|
||||
return this.localRoutine.parameters.filter(param => param.context === 'IN');
|
||||
}
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
// eslint-disable-next-line camelcase
|
||||
type LocalRoutineParams = FunctionParam & {_antares_id: string};
|
||||
|
||||
setTimeout(() => {
|
||||
this.$refs.firstInput[0].focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
typeClass (type) {
|
||||
if (type)
|
||||
return `type-${type.toLowerCase().replaceAll(' ', '_').replaceAll('"', '')}`;
|
||||
return '';
|
||||
},
|
||||
runRoutine () {
|
||||
const valArr = Object.keys(this.values).reduce((acc, curr, i) => {
|
||||
let qc;
|
||||
switch (this.client) {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
qc = '"';
|
||||
break;
|
||||
case 'pg':
|
||||
qc = '\'';
|
||||
break;
|
||||
default:
|
||||
qc = '"';
|
||||
}
|
||||
const props = defineProps({
|
||||
localRoutine: Object as PropType<{name: string; parameters: LocalRoutineParams[]}>,
|
||||
client: String
|
||||
});
|
||||
|
||||
const param = this.localRoutine.parameters.find(param => `${i}-${param.name}` === curr);
|
||||
const emit = defineEmits(['confirm', 'close']);
|
||||
|
||||
const value = [...NUMBER, ...FLOAT].includes(param.type) ? this.values[curr] : `${qc}${this.values[curr]}${qc}`;
|
||||
acc.push(value);
|
||||
return acc;
|
||||
}, []);
|
||||
this.$emit('confirm', valArr);
|
||||
},
|
||||
closeModal () {
|
||||
this.$emit('close');
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
}
|
||||
const firstInput: Ref<HTMLInputElement[]> = ref(null);
|
||||
const values: Ref<{[key: string]: string}> = ref({});
|
||||
|
||||
const inParameters = computed(() => {
|
||||
return props.localRoutine.parameters.filter(param => param.context === 'IN');
|
||||
});
|
||||
|
||||
const typeClass = (type: string) => {
|
||||
if (type)
|
||||
return `type-${type.toLowerCase().replaceAll(' ', '_').replaceAll('"', '')}`;
|
||||
return '';
|
||||
};
|
||||
|
||||
const runRoutine = () => {
|
||||
const valArr = Object.keys(values.value).reduce((acc, curr, i) => {
|
||||
let qc;
|
||||
switch (props.client) {
|
||||
case 'maria':
|
||||
case 'mysql':
|
||||
qc = '"';
|
||||
break;
|
||||
case 'pg':
|
||||
qc = '\'';
|
||||
break;
|
||||
default:
|
||||
qc = '"';
|
||||
}
|
||||
|
||||
const param = props.localRoutine.parameters.find(param => `${i}-${param.name}` === curr);
|
||||
|
||||
const value = [...NUMBER, ...FLOAT].includes(param.type) ? values.value[curr] : `${qc}${values.value[curr]}${qc}`;
|
||||
acc.push(value);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
emit('confirm', valArr);
|
||||
};
|
||||
|
||||
const closeModal = () => emit('close');
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
closeModal();
|
||||
};
|
||||
|
||||
const wrapNumber = (num: number) => {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', onKey);
|
||||
|
||||
setTimeout(() => {
|
||||
firstInput.value[0].focus();
|
||||
}, 20);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -2,8 +2,8 @@
|
||||
<ConfirmModal
|
||||
:confirm-text="$t('word.discard')"
|
||||
:cancel-text="$t('word.stay')"
|
||||
@confirm="$emit('confirm')"
|
||||
@hide="$emit('close')"
|
||||
@confirm="emit('confirm')"
|
||||
@hide="emit('close')"
|
||||
>
|
||||
<template #header>
|
||||
<div class="d-flex">
|
||||
@ -18,29 +18,23 @@
|
||||
</ConfirmModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
<script setup lang="ts">
|
||||
import ConfirmModal from '@/components/BaseConfirmModal.vue';
|
||||
import { onBeforeUnmount } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'ModalDiscardChanges',
|
||||
components: {
|
||||
ConfirmModal
|
||||
},
|
||||
emits: ['confirm', 'close'],
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
}
|
||||
}
|
||||
const emit = defineEmits(['confirm', 'close']);
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
emit('close');
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', onKey);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -67,112 +67,98 @@
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, Ref, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
|
||||
export default {
|
||||
name: 'ModalEditSchema',
|
||||
props: {
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: ['close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const props = defineProps({
|
||||
selectedSchema: String
|
||||
});
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const { getWorkspace, getDatabaseVariable } = workspacesStore;
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getDatabaseVariable
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
database: {
|
||||
name: '',
|
||||
prevName: '',
|
||||
collation: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
collations () {
|
||||
return this.getWorkspace(this.selectedWorkspace).collations;
|
||||
},
|
||||
defaultCollation () {
|
||||
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server').value || '';
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
let actualCollation;
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, getDatabaseVariable } = workspacesStore;
|
||||
|
||||
const firstInput: Ref<HTMLInputElement> = ref(null);
|
||||
const database = ref({
|
||||
name: '',
|
||||
prevName: '',
|
||||
collation: '',
|
||||
prevCollation: null
|
||||
});
|
||||
|
||||
const collations = computed(() => getWorkspace(selectedWorkspace.value).collations);
|
||||
const defaultCollation = computed(() => (getDatabaseVariable(selectedWorkspace.value, 'collation_server').value || ''));
|
||||
|
||||
const updateSchema = async () => {
|
||||
if (database.value.collation !== database.value.prevCollation) {
|
||||
try {
|
||||
const { status, response } = await Schema.getDatabaseCollation({ uid: this.selectedWorkspace, database: this.selectedSchema });
|
||||
const { status, response } = await Schema.updateSchema({
|
||||
uid: selectedWorkspace.value,
|
||||
...database.value
|
||||
});
|
||||
|
||||
if (status === 'success')
|
||||
actualCollation = response;
|
||||
|
||||
closeModal();
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.database = {
|
||||
name: this.selectedSchema,
|
||||
prevName: this.selectedSchema,
|
||||
collation: actualCollation || this.defaultCollation,
|
||||
prevCollation: actualCollation || this.defaultCollation
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
|
||||
setTimeout(() => {
|
||||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
async updateSchema () {
|
||||
if (this.database.collation !== this.database.prevCollation) {
|
||||
try {
|
||||
const { status, response } = await Schema.updateSchema({
|
||||
uid: this.selectedWorkspace,
|
||||
...this.database
|
||||
});
|
||||
|
||||
if (status === 'success')
|
||||
this.closeModal();
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
}
|
||||
else
|
||||
this.closeModal();
|
||||
},
|
||||
closeModal () {
|
||||
this.$emit('close');
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
}
|
||||
else closeModal();
|
||||
};
|
||||
|
||||
const closeModal = () => emit('close');
|
||||
|
||||
const onKey =(e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
closeModal();
|
||||
};
|
||||
|
||||
(async () => {
|
||||
let actualCollation;
|
||||
try {
|
||||
const { status, response } = await Schema.getDatabaseCollation({ uid: selectedWorkspace.value, database: props.selectedSchema });
|
||||
|
||||
if (status === 'success')
|
||||
actualCollation = response;
|
||||
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
database.value = {
|
||||
name: props.selectedSchema,
|
||||
prevName: props.selectedSchema,
|
||||
collation: actualCollation || defaultCollation.value,
|
||||
prevCollation: actualCollation || defaultCollation.value
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', onKey);
|
||||
|
||||
setTimeout(() => {
|
||||
firstInput.value.focus();
|
||||
}, 20);
|
||||
})();
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -146,7 +146,7 @@
|
||||
<div class="tbody">
|
||||
<div
|
||||
v-for="item in tables"
|
||||
:key="item.name"
|
||||
:key="item.table"
|
||||
class="tr"
|
||||
>
|
||||
<div class="td">
|
||||
@ -193,7 +193,7 @@
|
||||
>
|
||||
<input v-model="options.includes[key]" type="checkbox"><i class="form-icon" /> {{ $tc(`word.${key}`, 2) }}
|
||||
</label>
|
||||
<div v-if="customizations.exportByChunks">
|
||||
<div v-if="clientCustoms.exportByChunks">
|
||||
<div class="h6 mt-4 mb-2">
|
||||
{{ $t('message.newInserStmtEvery') }}:
|
||||
</div>
|
||||
@ -269,207 +269,203 @@
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, Ref, ref } from 'vue';
|
||||
import * as moment from 'moment';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { SchemaInfos } from 'common/interfaces/antares';
|
||||
import { ExportState, TableParams } from 'common/interfaces/exporter';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import customizations from 'common/customizations';
|
||||
import Application from '@/ipc-api/Application';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import { Customizations } from 'common/interfaces/customizations';
|
||||
|
||||
export default {
|
||||
name: 'ModalExportSchema',
|
||||
props: {
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: ['close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const props = defineProps({
|
||||
selectedSchema: String
|
||||
});
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const emit = defineEmits(['close']);
|
||||
const { t } = useI18n();
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
getDatabaseVariable,
|
||||
refreshSchema
|
||||
} = workspacesStore;
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getDatabaseVariable,
|
||||
refreshSchema
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isExporting: false,
|
||||
isRefreshing: false,
|
||||
progressPercentage: 0,
|
||||
progressStatus: '',
|
||||
tables: [],
|
||||
options: {
|
||||
includes: {},
|
||||
outputFormat: 'sql',
|
||||
sqlInsertAfter: 250,
|
||||
sqlInsertDivider: 'bytes'
|
||||
},
|
||||
basePath: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentWorkspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
customizations () {
|
||||
return this.currentWorkspace.customizations;
|
||||
},
|
||||
schemaItems () {
|
||||
const db = this.currentWorkspace.structure.find(db => db.name === this.selectedSchema);
|
||||
if (db)
|
||||
return db.tables.filter(table => table.type === 'table');
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
return [];
|
||||
},
|
||||
filename () {
|
||||
const date = moment().format('YYYY-MM-DD');
|
||||
return `${this.selectedSchema}_${date}.${this.options.outputFormat}`;
|
||||
},
|
||||
dumpFilePath () {
|
||||
return `${this.basePath}/${this.filename}`;
|
||||
},
|
||||
includeStructureStatus () {
|
||||
if (this.tables.every(item => item.includeStructure)) return 1;
|
||||
else if (this.tables.some(item => item.includeStructure)) return 2;
|
||||
else return 0;
|
||||
},
|
||||
includeContentStatus () {
|
||||
if (this.tables.every(item => item.includeContent)) return 1;
|
||||
else if (this.tables.some(item => item.includeContent)) return 2;
|
||||
else return 0;
|
||||
},
|
||||
includeDropStatementStatus () {
|
||||
if (this.tables.every(item => item.includeDropStatement)) return 1;
|
||||
else if (this.tables.some(item => item.includeDropStatement)) return 2;
|
||||
else return 0;
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
if (!this.schemaItems.length) await this.refresh();
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshSchema
|
||||
} = workspacesStore;
|
||||
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
const isExporting = ref(false);
|
||||
const isRefreshing = ref(false);
|
||||
const progressPercentage = ref(0);
|
||||
const progressStatus = ref('');
|
||||
const tables: Ref<TableParams[]> = ref([]);
|
||||
const options = ref({
|
||||
includes: {} as {[key: string]: boolean},
|
||||
outputFormat: 'sql',
|
||||
sqlInsertAfter: 250,
|
||||
sqlInsertDivider: 'bytes'
|
||||
});
|
||||
const basePath = ref('');
|
||||
|
||||
this.basePath = await Application.getDownloadPathDirectory();
|
||||
this.tables = this.schemaItems.map(item => ({
|
||||
table: item.name,
|
||||
includeStructure: true,
|
||||
includeContent: true,
|
||||
includeDropStatement: true
|
||||
}));
|
||||
const currentWorkspace = computed(() => getWorkspace(selectedWorkspace.value));
|
||||
const clientCustoms: Ref<Customizations> = computed(() => currentWorkspace.value.customizations);
|
||||
const schemaItems = computed(() => {
|
||||
const db: SchemaInfos = currentWorkspace.value.structure.find((db: SchemaInfos) => db.name === props.selectedSchema);
|
||||
if (db)
|
||||
return db.tables.filter(table => table.type === 'table');
|
||||
|
||||
const structure = ['functions', 'views', 'triggers', 'routines', 'schedulers'];
|
||||
return [];
|
||||
});
|
||||
const filename = computed(() => {
|
||||
const date = moment().format('YYYY-MM-DD');
|
||||
return `${props.selectedSchema}_${date}.${options.value.outputFormat}`;
|
||||
});
|
||||
const dumpFilePath = computed(() => `${basePath.value}/${filename.value}`);
|
||||
const includeStructureStatus = computed(() => {
|
||||
if (tables.value.every(item => item.includeStructure)) return 1;
|
||||
else if (tables.value.some(item => item.includeStructure)) return 2;
|
||||
else return 0;
|
||||
});
|
||||
const includeContentStatus = computed(() => {
|
||||
if (tables.value.every(item => item.includeContent)) return 1;
|
||||
else if (tables.value.some(item => item.includeContent)) return 2;
|
||||
else return 0;
|
||||
});
|
||||
const includeDropStatementStatus = computed(() => {
|
||||
if (tables.value.every(item => item.includeDropStatement)) return 1;
|
||||
else if (tables.value.some(item => item.includeDropStatement)) return 2;
|
||||
else return 0;
|
||||
});
|
||||
|
||||
structure.forEach(feat => {
|
||||
const val = customizations[this.currentWorkspace.client][feat];
|
||||
if (val)
|
||||
this.options.includes[feat] = true;
|
||||
});
|
||||
const startExport = async () => {
|
||||
isExporting.value = true;
|
||||
const { uid, client } = currentWorkspace.value;
|
||||
const params = {
|
||||
uid,
|
||||
type: client,
|
||||
schema: props.selectedSchema,
|
||||
outputFile: dumpFilePath.value,
|
||||
tables: [...tables.value],
|
||||
...options.value
|
||||
};
|
||||
|
||||
ipcRenderer.on('export-progress', this.updateProgress);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
ipcRenderer.off('export-progress', this.updateProgress);
|
||||
},
|
||||
methods: {
|
||||
async startExport () {
|
||||
this.isExporting = true;
|
||||
const { uid, client } = this.currentWorkspace;
|
||||
const params = {
|
||||
uid,
|
||||
type: client,
|
||||
schema: this.selectedSchema,
|
||||
outputFile: this.dumpFilePath,
|
||||
tables: [...this.tables],
|
||||
...this.options
|
||||
};
|
||||
|
||||
try {
|
||||
const { status, response } = await Schema.export(params);
|
||||
if (status === 'success')
|
||||
this.progressStatus = response.cancelled ? this.$t('word.aborted') : this.$t('word.completed');
|
||||
else {
|
||||
this.progressStatus = response;
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isExporting = false;
|
||||
},
|
||||
updateProgress (event, state) {
|
||||
this.progressPercentage = Number((state.currentItemIndex / state.totalItems * 100).toFixed(1));
|
||||
switch (state.op) {
|
||||
case 'PROCESSING':
|
||||
this.progressStatus = this.$t('message.processingTableExport', { table: state.currentItem });
|
||||
break;
|
||||
case 'FETCH':
|
||||
this.progressStatus = this.$t('message.fechingTableExport', { table: state.currentItem });
|
||||
break;
|
||||
case 'WRITE':
|
||||
this.progressStatus = this.$t('message.writingTableExport', { table: state.currentItem });
|
||||
break;
|
||||
}
|
||||
},
|
||||
async closeModal () {
|
||||
let willClose = true;
|
||||
if (this.isExporting) {
|
||||
willClose = false;
|
||||
const { response } = await Schema.abortExport();
|
||||
willClose = response.willAbort;
|
||||
}
|
||||
|
||||
if (willClose)
|
||||
this.$emit('close');
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
checkAllTables () {
|
||||
this.tables = this.tables.map(item => ({ ...item, includeStructure: true, includeContent: true, includeDropStatement: true }));
|
||||
},
|
||||
uncheckAllTables () {
|
||||
this.tables = this.tables.map(item => ({ ...item, includeStructure: false, includeContent: false, includeDropStatement: false }));
|
||||
},
|
||||
toggleAllTablesOption (option) {
|
||||
const options = ['includeStructure', 'includeContent', 'includeDropStatement'];
|
||||
if (!options.includes(option)) return;
|
||||
|
||||
if (this[`${option}Status`] !== 1)
|
||||
this.tables = this.tables.map(item => ({ ...item, [option]: true }));
|
||||
else
|
||||
this.tables = this.tables.map(item => ({ ...item, [option]: false }));
|
||||
},
|
||||
async refresh () {
|
||||
this.isRefreshing = true;
|
||||
await this.refreshSchema({ uid: this.currentWorkspace.uid, schema: this.selectedSchema });
|
||||
this.isRefreshing = false;
|
||||
},
|
||||
async openPathDialog () {
|
||||
const result = await Application.showOpenDialog({ properties: ['openDirectory'] });
|
||||
if (result && !result.canceled)
|
||||
this.basePath = result.filePaths[0];
|
||||
try {
|
||||
const { status, response } = await Schema.export(params);
|
||||
if (status === 'success')
|
||||
progressStatus.value = response.cancelled ? t('word.aborted') : t('word.completed');
|
||||
else {
|
||||
progressStatus.value = response;
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
isExporting.value = false;
|
||||
};
|
||||
|
||||
const updateProgress = (event: Event, state: ExportState) => {
|
||||
progressPercentage.value = Number((state.currentItemIndex / state.totalItems * 100).toFixed(1));
|
||||
switch (state.op) {
|
||||
case 'PROCESSING':
|
||||
progressStatus.value = t('message.processingTableExport', { table: state.currentItem });
|
||||
break;
|
||||
case 'FETCH':
|
||||
progressStatus.value = t('message.fechingTableExport', { table: state.currentItem });
|
||||
break;
|
||||
case 'WRITE':
|
||||
progressStatus.value = t('message.writingTableExport', { table: state.currentItem });
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const closeModal = async () => {
|
||||
let willClose = true;
|
||||
if (isExporting.value) {
|
||||
willClose = false;
|
||||
const { response } = await Schema.abortExport();
|
||||
willClose = response.willAbort;
|
||||
}
|
||||
|
||||
if (willClose)
|
||||
emit('close');
|
||||
};
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
closeModal();
|
||||
};
|
||||
|
||||
const checkAllTables = () => {
|
||||
tables.value = tables.value.map(item => ({ ...item, includeStructure: true, includeContent: true, includeDropStatement: true }));
|
||||
};
|
||||
|
||||
const uncheckAllTables = () => {
|
||||
tables.value = tables.value.map(item => ({ ...item, includeStructure: false, includeContent: false, includeDropStatement: false }));
|
||||
};
|
||||
|
||||
const toggleAllTablesOption = (option: 'includeStructure' | 'includeContent' |'includeDropStatement') => {
|
||||
const options = {
|
||||
includeStructure: includeStructureStatus.value,
|
||||
includeContent: includeContentStatus.value,
|
||||
includeDropStatement: includeDropStatementStatus.value
|
||||
};
|
||||
|
||||
if (options[option] !== 1)
|
||||
tables.value = tables.value.map(item => ({ ...item, [option]: true }));
|
||||
else
|
||||
tables.value = tables.value.map(item => ({ ...item, [option]: false }));
|
||||
};
|
||||
|
||||
const refresh = async () => {
|
||||
isRefreshing.value = true;
|
||||
await refreshSchema({ uid: currentWorkspace.value.uid, schema: props.selectedSchema });
|
||||
isRefreshing.value = false;
|
||||
};
|
||||
|
||||
const openPathDialog = async () => {
|
||||
const result = await Application.showOpenDialog({ properties: ['openDirectory'] });
|
||||
if (result && !result.canceled)
|
||||
basePath.value = result.filePaths[0];
|
||||
};
|
||||
|
||||
(async () => {
|
||||
if (!schemaItems.value.length) await refresh();
|
||||
|
||||
window.addEventListener('keydown', onKey);
|
||||
|
||||
basePath.value = await Application.getDownloadPathDirectory();
|
||||
tables.value = schemaItems.value.map(item => ({
|
||||
table: item.name,
|
||||
includeStructure: true,
|
||||
includeContent: true,
|
||||
includeDropStatement: true
|
||||
}));
|
||||
|
||||
const structure = ['functions', 'views', 'triggers', 'routines', 'schedulers'];
|
||||
|
||||
structure.forEach((feat: keyof Customizations) => {
|
||||
const val = clientCustoms.value[feat];
|
||||
if (val)
|
||||
options.value.includes[feat] = true;
|
||||
});
|
||||
|
||||
ipcRenderer.on('export-progress', updateProgress);
|
||||
})();
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
ipcRenderer.off('export-progress', updateProgress);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -185,201 +185,178 @@
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount, onMounted, Prop, Ref, ref, watch } from 'vue';
|
||||
import * as moment from 'moment';
|
||||
import { TableField, TableForeign } from 'common/interfaces/antares';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import FakerSelect from '@/components/FakerSelect';
|
||||
import FakerSelect from '@/components/FakerSelect.vue';
|
||||
|
||||
export default {
|
||||
name: 'ModalFakerRows',
|
||||
components: {
|
||||
FakerSelect
|
||||
},
|
||||
props: {
|
||||
tabUid: [String, Number],
|
||||
fields: Array,
|
||||
keyUsage: Array
|
||||
},
|
||||
emits: ['reload', 'hide'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const props = defineProps({
|
||||
tabUid: [String, Number],
|
||||
fields: Array as Prop<TableField[]>,
|
||||
keyUsage: Array as Prop<TableForeign[]>
|
||||
});
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const emit = defineEmits(['reload', 'hide']);
|
||||
|
||||
const { getWorkspace, getWorkspaceTab } = workspacesStore;
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getWorkspaceTab
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localRow: {},
|
||||
fieldsToExclude: [],
|
||||
nInserts: 1,
|
||||
isInserting: false,
|
||||
fakerLocale: 'en'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
foreignKeys () {
|
||||
return this.keyUsage.map(key => key.field);
|
||||
},
|
||||
hasFakes () {
|
||||
return Object.keys(this.localRow).some(field => 'group' in this.localRow[field] && this.localRow[field].group !== 'manual');
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
nInserts (val) {
|
||||
if (!val || val < 1)
|
||||
this.nInserts = 1;
|
||||
else if (val > 1000)
|
||||
this.nInserts = 1000;
|
||||
}
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
mounted () {
|
||||
const rowObj = {};
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
for (const field of this.fields) {
|
||||
let fieldDefault;
|
||||
const { getWorkspace } = workspacesStore;
|
||||
|
||||
if (field.default === 'NULL') fieldDefault = null;
|
||||
else {
|
||||
if ([...NUMBER, ...FLOAT].includes(field.type))
|
||||
fieldDefault = !field.default || Number.isNaN(+field.default.replaceAll('\'', '')) ? null : +field.default.replaceAll('\'', '');
|
||||
else if ([...TEXT, ...LONG_TEXT].includes(field.type)) {
|
||||
fieldDefault = field.default
|
||||
? field.default.includes('\'')
|
||||
? field.default.split('\'')[1]
|
||||
: field.default
|
||||
: '';
|
||||
}
|
||||
else if ([...TIME, ...DATE].includes(field.type))
|
||||
fieldDefault = field.default;
|
||||
else if (BIT.includes(field.type))
|
||||
fieldDefault = field.default?.replaceAll('\'', '').replaceAll('b', '');
|
||||
else if (DATETIME.includes(field.type)) {
|
||||
if (field.default && ['current_timestamp', 'now()'].some(term => field.default.toLowerCase().includes(term))) {
|
||||
let datePrecision = '';
|
||||
for (let i = 0; i < field.datePrecision; i++)
|
||||
datePrecision += i === 0 ? '.S' : 'S';
|
||||
fieldDefault = moment().format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
|
||||
}
|
||||
else
|
||||
fieldDefault = field.default;
|
||||
}
|
||||
else if (field.enumValues)
|
||||
fieldDefault = field.enumValues.replaceAll('\'', '').split(',');
|
||||
else
|
||||
fieldDefault = field.default;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const localRow: Ref<{[key: string]: any}> = ref({});
|
||||
const fieldsToExclude = ref([]);
|
||||
const nInserts = ref(1);
|
||||
const isInserting = ref(false);
|
||||
const fakerLocale = ref('en');
|
||||
|
||||
rowObj[field.name] = { value: fieldDefault };
|
||||
const workspace = computed(() => getWorkspace(selectedWorkspace.value));
|
||||
const foreignKeys = computed(() => props.keyUsage.map(key => key.field));
|
||||
const hasFakes = computed(() => Object.keys(localRow.value).some(field => 'group' in localRow.value[field] && localRow.value[field].group !== 'manual'));
|
||||
|
||||
if (field.autoIncrement || !!field.onUpdate)// Disable by default auto increment or "on update" fields
|
||||
this.fieldsToExclude = [...this.fieldsToExclude, field.name];
|
||||
}
|
||||
watch(nInserts, (val) => {
|
||||
if (!val || val < 1)
|
||||
nInserts.value = 1;
|
||||
else if (val > 1000)
|
||||
nInserts.value = 1000;
|
||||
});
|
||||
|
||||
this.localRow = { ...rowObj };
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
typeClass (type) {
|
||||
if (type)
|
||||
return `type-${type.toLowerCase().replaceAll(' ', '_').replaceAll('"', '')}`;
|
||||
return '';
|
||||
},
|
||||
async insertRows () {
|
||||
this.isInserting = true;
|
||||
const rowToInsert = this.localRow;
|
||||
|
||||
Object.keys(rowToInsert).forEach(key => {
|
||||
if (this.fieldsToExclude.includes(key))
|
||||
delete rowToInsert[key];
|
||||
|
||||
if (typeof rowToInsert[key] === 'undefined')
|
||||
delete rowToInsert[key];
|
||||
});
|
||||
|
||||
const fieldTypes = {};
|
||||
this.fields.forEach(field => {
|
||||
fieldTypes[field.name] = field.type;
|
||||
});
|
||||
|
||||
try {
|
||||
const { status, response } = await Tables.insertTableFakeRows({
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.workspace.breadcrumbs.schema,
|
||||
table: this.workspace.breadcrumbs.table,
|
||||
row: rowToInsert,
|
||||
repeat: this.nInserts,
|
||||
fields: fieldTypes,
|
||||
locale: this.fakerLocale
|
||||
});
|
||||
|
||||
if (status === 'success') {
|
||||
this.closeModal();
|
||||
this.$emit('reload');
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isInserting = false;
|
||||
},
|
||||
closeModal () {
|
||||
this.$emit('hide');
|
||||
},
|
||||
fieldLength (field) {
|
||||
if ([...BLOB, ...LONG_TEXT].includes(field.type)) return null;
|
||||
else if (TEXT.includes(field.type)) return Number(field.charLength);
|
||||
return Number(field.length);
|
||||
},
|
||||
toggleFields (event, field) {
|
||||
if (event.target.checked)
|
||||
this.fieldsToExclude = this.fieldsToExclude.filter(f => f !== field.name);
|
||||
else
|
||||
this.fieldsToExclude = [...this.fieldsToExclude, field.name];
|
||||
},
|
||||
filesChange (event, field) {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
this.localRow[field] = files[0].path;
|
||||
},
|
||||
getKeyUsage (keyName) {
|
||||
return this.keyUsage.find(key => key.field === keyName);
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
}
|
||||
const typeClass = (type: string) => {
|
||||
if (type)
|
||||
return `type-${type.toLowerCase().replaceAll(' ', '_').replaceAll('"', '')}`;
|
||||
return '';
|
||||
};
|
||||
|
||||
const insertRows = async () => {
|
||||
isInserting.value = true;
|
||||
const rowToInsert = localRow.value;
|
||||
|
||||
Object.keys(rowToInsert).forEach(key => {
|
||||
if (fieldsToExclude.value.includes(key))
|
||||
delete rowToInsert[key];
|
||||
|
||||
if (typeof rowToInsert[key] === 'undefined')
|
||||
delete rowToInsert[key];
|
||||
});
|
||||
|
||||
const fieldTypes: {[key: string]: string} = {};
|
||||
props.fields.forEach(field => {
|
||||
fieldTypes[field.name] = field.type;
|
||||
});
|
||||
|
||||
try {
|
||||
const { status, response } = await Tables.insertTableFakeRows({
|
||||
uid: selectedWorkspace.value,
|
||||
schema: workspace.value.breadcrumbs.schema,
|
||||
table: workspace.value.breadcrumbs.table,
|
||||
row: rowToInsert,
|
||||
repeat: nInserts.value,
|
||||
fields: fieldTypes,
|
||||
locale: fakerLocale.value
|
||||
});
|
||||
|
||||
if (status === 'success') {
|
||||
closeModal();
|
||||
emit('reload');
|
||||
}
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
isInserting.value = false;
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
emit('hide');
|
||||
};
|
||||
|
||||
const fieldLength = (field: TableField) => {
|
||||
if ([...BLOB, ...LONG_TEXT].includes(field.type)) return null;
|
||||
else if (TEXT.includes(field.type)) return Number(field.charLength);
|
||||
return Number(field.length);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const toggleFields = (event: any, field: TableField) => {
|
||||
if (event.target.checked)
|
||||
fieldsToExclude.value = fieldsToExclude.value.filter(f => f !== field.name);
|
||||
else
|
||||
fieldsToExclude.value = [...fieldsToExclude.value, field.name];
|
||||
};
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
closeModal();
|
||||
};
|
||||
|
||||
const wrapNumber = (num: number) => {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', onKey);
|
||||
|
||||
onMounted(() => {
|
||||
const rowObj: {[key: string]: unknown} = {};
|
||||
|
||||
for (const field of props.fields) {
|
||||
let fieldDefault;
|
||||
|
||||
if (field.default === 'NULL') fieldDefault = null;
|
||||
else {
|
||||
if ([...NUMBER, ...FLOAT].includes(field.type))
|
||||
fieldDefault = !field.default || Number.isNaN(+field.default.replaceAll('\'', '')) ? null : +field.default.replaceAll('\'', '');
|
||||
else if ([...TEXT, ...LONG_TEXT].includes(field.type)) {
|
||||
fieldDefault = field.default
|
||||
? field.default.includes('\'')
|
||||
? field.default.split('\'')[1]
|
||||
: field.default
|
||||
: '';
|
||||
}
|
||||
else if ([...TIME, ...DATE].includes(field.type))
|
||||
fieldDefault = field.default;
|
||||
else if (BIT.includes(field.type))
|
||||
fieldDefault = field.default?.replaceAll('\'', '').replaceAll('b', '');
|
||||
else if (DATETIME.includes(field.type)) {
|
||||
if (field.default && ['current_timestamp', 'now()'].some(term => field.default.toLowerCase().includes(term))) {
|
||||
let datePrecision = '';
|
||||
for (let i = 0; i < field.datePrecision; i++)
|
||||
datePrecision += i === 0 ? '.S' : 'S';
|
||||
fieldDefault = moment().format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
|
||||
}
|
||||
else
|
||||
fieldDefault = field.default;
|
||||
}
|
||||
else if (field.enumValues)
|
||||
fieldDefault = field.enumValues.replaceAll('\'', '').split(',');
|
||||
else
|
||||
fieldDefault = field.default;
|
||||
}
|
||||
|
||||
rowObj[field.name] = { value: fieldDefault };
|
||||
|
||||
if (field.autoIncrement || !!field.onUpdate)// Disable by default auto increment or "on update" fields
|
||||
fieldsToExclude.value = [...fieldsToExclude.value, field.name];
|
||||
}
|
||||
|
||||
localRow.value = { ...rowObj };
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -97,129 +97,115 @@
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
<script setup lang="ts">
|
||||
import { Component, computed, ComputedRef, onBeforeUnmount, onMounted, onUpdated, Prop, Ref, ref, watch } from 'vue';
|
||||
import * as moment from 'moment';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
import { useHistoryStore } from '@/stores/history';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
|
||||
|
||||
export default {
|
||||
name: 'ModalHistory',
|
||||
components: {
|
||||
BaseVirtualScroll
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
emits: ['select-query', 'close'],
|
||||
setup () {
|
||||
const { getHistoryByWorkspace, deleteQueryFromHistory } = useHistoryStore();
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
interface HistoryRow {
|
||||
uid:string;
|
||||
sql: string;
|
||||
schema: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
return {
|
||||
getHistoryByWorkspace,
|
||||
deleteQueryFromHistory,
|
||||
getConnectionName,
|
||||
addNotification
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
resultsSize: 1000,
|
||||
isQuering: false,
|
||||
scrollElement: null,
|
||||
searchTermInterval: null,
|
||||
searchTerm: '',
|
||||
localSearchTerm: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
connectionName () {
|
||||
return this.getConnectionName(this.connection.uid);
|
||||
},
|
||||
history () {
|
||||
return this.getHistoryByWorkspace(this.connection.uid) || [];
|
||||
},
|
||||
filteredHistory () {
|
||||
return this.history.filter(q => q.sql.toLowerCase().search(this.searchTerm.toLowerCase()) >= 0);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchTerm () {
|
||||
clearTimeout(this.searchTermInterval);
|
||||
const { getHistoryByWorkspace, deleteQueryFromHistory } = useHistoryStore();
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
|
||||
this.searchTermInterval = setTimeout(() => {
|
||||
this.localSearchTerm = this.searchTerm;
|
||||
}, 200);
|
||||
}
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey, { capture: true });
|
||||
},
|
||||
updated () {
|
||||
if (this.$refs.table)
|
||||
this.refreshScroller();
|
||||
const props = defineProps({
|
||||
connection: Object as Prop<ConnectionParams>
|
||||
});
|
||||
|
||||
if (this.$refs.tableWrapper)
|
||||
this.scrollElement = this.$refs.tableWrapper;
|
||||
},
|
||||
mounted () {
|
||||
this.resizeResults();
|
||||
window.addEventListener('resize', this.resizeResults);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey, { capture: true });
|
||||
window.removeEventListener('resize', this.resizeResults);
|
||||
clearInterval(this.refreshInterval);
|
||||
},
|
||||
methods: {
|
||||
copyQuery (sql) {
|
||||
navigator.clipboard.writeText(sql);
|
||||
},
|
||||
deleteQuery (query) {
|
||||
this.deleteQueryFromHistory({
|
||||
workspace: this.connection.uid,
|
||||
...query
|
||||
});
|
||||
},
|
||||
resizeResults () {
|
||||
if (this.$refs.resultTable) {
|
||||
const el = this.$refs.tableWrapper.parentElement;
|
||||
const emit = defineEmits(['select-query', 'close']);
|
||||
|
||||
if (el)
|
||||
this.resultsSize = el.offsetHeight - this.$refs.searchForm.offsetHeight;
|
||||
const table: Ref<HTMLDivElement> = ref(null);
|
||||
const resultTable: Ref<Component & { updateWindow: () => void }> = ref(null);
|
||||
const tableWrapper: Ref<HTMLDivElement> = ref(null);
|
||||
const searchForm: Ref<HTMLInputElement> = ref(null);
|
||||
const resultsSize = ref(1000);
|
||||
const scrollElement: Ref<HTMLDivElement> = ref(null);
|
||||
const searchTermInterval: Ref<NodeJS.Timeout> = ref(null);
|
||||
const searchTerm = ref('');
|
||||
const localSearchTerm = ref('');
|
||||
|
||||
this.$refs.resultTable.updateWindow();
|
||||
}
|
||||
},
|
||||
formatDate (date) {
|
||||
return moment(date).isValid() ? moment(date).format('HH:mm:ss - YYYY/MM/DD') : date;
|
||||
},
|
||||
refreshScroller () {
|
||||
this.resizeResults();
|
||||
},
|
||||
closeModal () {
|
||||
this.$emit('close');
|
||||
},
|
||||
highlightWord (string) {
|
||||
string = string.replaceAll('<', '<').replaceAll('>', '>');
|
||||
const connectionName = computed(() => getConnectionName(props.connection.uid));
|
||||
const history: ComputedRef<HistoryRow[]> = computed(() => (getHistoryByWorkspace(props.connection.uid) || []));
|
||||
const filteredHistory = computed(() => history.value.filter(q => q.sql.toLowerCase().search(searchTerm.value.toLowerCase()) >= 0));
|
||||
|
||||
if (this.searchTerm) {
|
||||
const regexp = new RegExp(`(${this.searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
|
||||
return string.replace(regexp, '<span class="text-primary text-bold">$1</span>');
|
||||
}
|
||||
else
|
||||
return string;
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
}
|
||||
watch(searchTerm, () => {
|
||||
clearTimeout(searchTermInterval.value);
|
||||
|
||||
searchTermInterval.value = setTimeout(() => {
|
||||
localSearchTerm.value = searchTerm.value;
|
||||
}, 200);
|
||||
});
|
||||
|
||||
const copyQuery = (sql: string) => {
|
||||
navigator.clipboard.writeText(sql);
|
||||
};
|
||||
|
||||
const deleteQuery = (query: HistoryRow[]) => {
|
||||
deleteQueryFromHistory({
|
||||
workspace: props.connection.uid,
|
||||
...query
|
||||
});
|
||||
};
|
||||
|
||||
const resizeResults = () => {
|
||||
if (resultTable.value) {
|
||||
const el = tableWrapper.value.parentElement;
|
||||
|
||||
if (el)
|
||||
resultsSize.value = el.offsetHeight - searchForm.value.offsetHeight;
|
||||
|
||||
resultTable.value.updateWindow();
|
||||
}
|
||||
};
|
||||
|
||||
const formatDate = (date: Date) => moment(date).isValid() ? moment(date).format('HH:mm:ss - YYYY/MM/DD') : date;
|
||||
const refreshScroller = () => resizeResults();
|
||||
const closeModal = () => emit('close');
|
||||
|
||||
const highlightWord = (string: string) => {
|
||||
string = string.replaceAll('<', '<').replaceAll('>', '>');
|
||||
|
||||
if (searchTerm.value) {
|
||||
const regexp = new RegExp(`(${searchTerm.value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
|
||||
return string.replace(regexp, '<span class="text-primary text-bold">$1</span>');
|
||||
}
|
||||
else
|
||||
return string;
|
||||
};
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
closeModal();
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', onKey, { capture: true });
|
||||
|
||||
onUpdated(() => {
|
||||
if (table.value)
|
||||
refreshScroller();
|
||||
|
||||
if (tableWrapper.value)
|
||||
scrollElement.value = tableWrapper.value;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
resizeResults();
|
||||
window.addEventListener('resize', resizeResults);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKey, { capture: true });
|
||||
window.removeEventListener('resize', resizeResults);
|
||||
clearInterval(searchTermInterval.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -49,124 +49,119 @@
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, Ref, ref } from 'vue';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import * as moment from 'moment';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import moment from 'moment';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ImportState } from 'common/interfaces/importer';
|
||||
|
||||
export default {
|
||||
name: 'ModalImportSchema',
|
||||
const { t } = useI18n();
|
||||
|
||||
props: {
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: ['close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, refreshSchema } = workspacesStore;
|
||||
const { getWorkspace, refreshSchema } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshSchema
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
sqlFile: '',
|
||||
isImporting: false,
|
||||
progressPercentage: 0,
|
||||
queryCount: 0,
|
||||
completed: false,
|
||||
progressStatus: 'Reading',
|
||||
queryErrors: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
currentWorkspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
formattedQueryErrors () {
|
||||
return this.queryErrors.map(err =>
|
||||
`Time: ${moment(err.time).format('HH:mm:ss.S')} (${err.time})\nError: ${err.message}`
|
||||
).join('\n\n');
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
|
||||
ipcRenderer.on('import-progress', this.updateProgress);
|
||||
ipcRenderer.on('query-error', this.handleQueryError);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
ipcRenderer.off('import-progress', this.updateProgress);
|
||||
ipcRenderer.off('query-error', this.handleQueryError);
|
||||
},
|
||||
methods: {
|
||||
async startImport (sqlFile) {
|
||||
this.isImporting = true;
|
||||
this.sqlFile = sqlFile;
|
||||
|
||||
const { uid, client } = this.currentWorkspace;
|
||||
const params = {
|
||||
uid,
|
||||
type: client,
|
||||
schema: this.selectedSchema,
|
||||
file: sqlFile
|
||||
};
|
||||
|
||||
try {
|
||||
this.completed = false;
|
||||
const { status, response } = await Schema.import(params);
|
||||
if (status === 'success')
|
||||
this.progressStatus = response.cancelled ? this.$t('word.aborted') : this.$t('word.completed');
|
||||
else {
|
||||
this.progressStatus = response;
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
this.refreshSchema({ uid, schema: this.selectedSchema });
|
||||
this.completed = true;
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isImporting = false;
|
||||
},
|
||||
updateProgress (event, state) {
|
||||
this.progressPercentage = Number(state.percentage).toFixed(1);
|
||||
this.queryCount = Number(state.queryCount);
|
||||
},
|
||||
handleQueryError (event, err) {
|
||||
this.queryErrors.push(err);
|
||||
},
|
||||
async closeModal () {
|
||||
let willClose = true;
|
||||
if (this.isImporting) {
|
||||
willClose = false;
|
||||
const { response } = await Schema.abortImport();
|
||||
willClose = response.willAbort;
|
||||
}
|
||||
|
||||
if (willClose)
|
||||
this.$emit('close');
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
const props = defineProps({
|
||||
selectedSchema: String
|
||||
});
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const sqlFile = ref('');
|
||||
const isImporting = ref(false);
|
||||
const progressPercentage = ref(0);
|
||||
const queryCount = ref(0);
|
||||
const completed = ref(false);
|
||||
const progressStatus = ref('Reading');
|
||||
const queryErrors: Ref<{time: string; message: string}[]> = ref([]);
|
||||
|
||||
const currentWorkspace = computed(() => getWorkspace(selectedWorkspace.value));
|
||||
|
||||
const formattedQueryErrors = computed(() => {
|
||||
return queryErrors.value.map(err =>
|
||||
`Time: ${moment(err.time).format('HH:mm:ss.S')} (${err.time})\nError: ${err.message}`
|
||||
).join('\n\n');
|
||||
});
|
||||
|
||||
const startImport = async (file: string) => {
|
||||
isImporting.value = true;
|
||||
sqlFile.value = file;
|
||||
|
||||
const { uid, client } = currentWorkspace.value;
|
||||
const params = {
|
||||
uid,
|
||||
type: client,
|
||||
schema: props.selectedSchema,
|
||||
file: sqlFile.value
|
||||
};
|
||||
|
||||
try {
|
||||
completed.value = false;
|
||||
const { status, response } = await Schema.import(params);
|
||||
|
||||
if (status === 'success')
|
||||
progressStatus.value = response.cancelled ? t('word.aborted') : t('word.completed');
|
||||
else {
|
||||
progressStatus.value = response;
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
refreshSchema({ uid, schema: props.selectedSchema });
|
||||
completed.value = true;
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
isImporting.value = false;
|
||||
};
|
||||
|
||||
const updateProgress = (event: Event, state: ImportState) => {
|
||||
progressPercentage.value = parseFloat(Number(state.percentage).toFixed(1));
|
||||
queryCount.value = Number(state.queryCount);
|
||||
};
|
||||
|
||||
const handleQueryError = (event: Event, err: { time: string; message: string }) => {
|
||||
queryErrors.value.push(err);
|
||||
};
|
||||
|
||||
const closeModal = async () => {
|
||||
let willClose = true;
|
||||
if (isImporting.value) {
|
||||
willClose = false;
|
||||
const { response } = await Schema.abortImport();
|
||||
willClose = response.willAbort;
|
||||
}
|
||||
|
||||
if (willClose)
|
||||
emit('close');
|
||||
};
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
closeModal();
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', onKey);
|
||||
|
||||
ipcRenderer.on('import-progress', updateProgress);
|
||||
ipcRenderer.on('query-error', handleQueryError);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
ipcRenderer.off('import-progress', updateProgress);
|
||||
ipcRenderer.off('query-error', handleQueryError);
|
||||
});
|
||||
|
||||
defineExpose({ startImport });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -67,91 +67,74 @@
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, Ref, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'ModalNewSchema',
|
||||
emits: ['reload', 'close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, getDatabaseVariable } = workspacesStore;
|
||||
const { getWorkspace, getDatabaseVariable } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getDatabaseVariable
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
database: {
|
||||
name: '',
|
||||
collation: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
collations () {
|
||||
return this.getWorkspace(this.selectedWorkspace).collations;
|
||||
},
|
||||
customizations () {
|
||||
return this.getWorkspace(this.selectedWorkspace).customizations;
|
||||
},
|
||||
defaultCollation () {
|
||||
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server') ? this.getDatabaseVariable(this.selectedWorkspace, 'collation_server').value : '';
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.database = { ...this.database, collation: this.defaultCollation };
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
setTimeout(() => {
|
||||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
async createSchema () {
|
||||
this.isLoading = true;
|
||||
try {
|
||||
const { status, response } = await Schema.createSchema({
|
||||
uid: this.selectedWorkspace,
|
||||
...this.database
|
||||
});
|
||||
|
||||
if (status === 'success') {
|
||||
this.closeModal();
|
||||
this.$emit('reload');
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
this.isLoading = false;
|
||||
},
|
||||
closeModal () {
|
||||
this.$emit('close');
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
const emit = defineEmits(['reload', 'close']);
|
||||
|
||||
const firstInput: Ref<HTMLInputElement> = ref(null);
|
||||
const isLoading = ref(false);
|
||||
const database = ref({
|
||||
name: '',
|
||||
collation: ''
|
||||
});
|
||||
|
||||
const collations = computed(() => getWorkspace(selectedWorkspace.value).collations);
|
||||
const customizations = computed(() => getWorkspace(selectedWorkspace.value).customizations);
|
||||
const defaultCollation = computed(() => getDatabaseVariable(selectedWorkspace.value, 'collation_server') ? getDatabaseVariable(selectedWorkspace.value, 'collation_server').value : '');
|
||||
|
||||
database.value = { ...database.value, collation: defaultCollation.value };
|
||||
|
||||
const createSchema = async () => {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
const { status, response } = await Schema.createSchema({
|
||||
uid: selectedWorkspace.value,
|
||||
...database.value
|
||||
});
|
||||
|
||||
if (status === 'success') {
|
||||
closeModal();
|
||||
emit('reload');
|
||||
}
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
isLoading.value = false;
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
emit('close');
|
||||
};
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
closeModal();
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', onKey);
|
||||
setTimeout(() => {
|
||||
firstInput.value.focus();
|
||||
}, 20);
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -1,366 +0,0 @@
|
||||
<template>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
|
||||
<span class="cut-text">{{ $t('message.addNewRow') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<fieldset :disabled="isInserting">
|
||||
<div
|
||||
v-for="(field, key) in fields"
|
||||
:key="field.name"
|
||||
class="form-group"
|
||||
>
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label" :title="field.name">{{ field.name }}</label>
|
||||
</div>
|
||||
<div class="input-group col-8 col-sm-12">
|
||||
<ForeignKeySelect
|
||||
v-if="foreignKeys.includes(field.name)"
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
class="form-select"
|
||||
:key-usage="getKeyUsage(field.name)"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
/>
|
||||
<input
|
||||
v-else-if="inputProps(field).mask"
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
v-mask="inputProps(field).mask"
|
||||
class="form-input"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<input
|
||||
v-else-if="inputProps(field).type === 'file'"
|
||||
ref="formInput"
|
||||
class="form-input"
|
||||
type="file"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
@change="filesChange($event,field.name)"
|
||||
>
|
||||
<input
|
||||
v-else-if="inputProps(field).type === 'number'"
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
class="form-input"
|
||||
step="any"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<input
|
||||
v-else
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
class="form-input"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<span class="input-group-addon" :class="typeCLass(field.type)">
|
||||
{{ field.type }} {{ wrapNumber(fieldLength(field)) }}
|
||||
</span>
|
||||
<label class="form-checkbox ml-3" :title="$t('word.insert')">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="!field.autoIncrement"
|
||||
@change.prevent="toggleFields($event, field)"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="input-group col-3 tooltip tooltip-right" :data-tooltip="$t('message.numberOfInserts')">
|
||||
<input
|
||||
v-model="nInserts"
|
||||
type="number"
|
||||
class="form-input"
|
||||
min="1"
|
||||
:disabled="isInserting"
|
||||
>
|
||||
<span class="input-group-addon">
|
||||
<i class="mdi mdi-24px mdi-repeat" />
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isInserting}"
|
||||
@click.stop="insertRows"
|
||||
>
|
||||
{{ $t('word.insert') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import ForeignKeySelect from '@/components/ForeignKeySelect';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'ModalNewTableRow',
|
||||
components: {
|
||||
ForeignKeySelect
|
||||
},
|
||||
props: {
|
||||
tabUid: [String, Number],
|
||||
fields: Array,
|
||||
keyUsage: Array
|
||||
},
|
||||
emits: ['reload', 'hide'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, getWorkspaceTab } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getWorkspaceTab
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localRow: {},
|
||||
fieldsToExclude: [],
|
||||
nInserts: 1,
|
||||
isInserting: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
foreignKeys () {
|
||||
return this.keyUsage.map(key => key.field);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
nInserts (val) {
|
||||
if (!val || val < 1)
|
||||
this.nInserts = 1;
|
||||
else if (val > 1000)
|
||||
this.nInserts = 1000;
|
||||
}
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
mounted () {
|
||||
const rowObj = {};
|
||||
|
||||
for (const field of this.fields) {
|
||||
let fieldDefault;
|
||||
|
||||
if (field.default === 'NULL') fieldDefault = null;
|
||||
else {
|
||||
if ([...NUMBER, ...FLOAT].includes(field.type))
|
||||
fieldDefault = +field.default;
|
||||
|
||||
if ([...TEXT, ...LONG_TEXT].includes(field.type))
|
||||
fieldDefault = field.default ? field.default.substring(1, field.default.length - 1) : '';
|
||||
|
||||
if ([...TIME, ...DATE].includes(field.type))
|
||||
fieldDefault = field.default;
|
||||
|
||||
if (DATETIME.includes(field.type)) {
|
||||
if (field.default && field.default.toLowerCase().includes('current_timestamp')) {
|
||||
let datePrecision = '';
|
||||
for (let i = 0; i < field.datePrecision; i++)
|
||||
datePrecision += i === 0 ? '.S' : 'S';
|
||||
fieldDefault = moment().format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rowObj[field.name] = fieldDefault;
|
||||
|
||||
if (field.autoIncrement)// Disable by default auto increment fields
|
||||
this.fieldsToExclude = [...this.fieldsToExclude, field.name];
|
||||
}
|
||||
|
||||
this.localRow = { ...rowObj };
|
||||
|
||||
// Auto focus
|
||||
setTimeout(() => {
|
||||
const firstSelectableInput = this.$refs.formInput.find(input => !input.disabled);
|
||||
firstSelectableInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
typeClass (type) {
|
||||
if (type)
|
||||
return `type-${type.toLowerCase().replaceAll(' ', '_').replaceAll('"', '')}`;
|
||||
return '';
|
||||
},
|
||||
async insertRows () {
|
||||
this.isInserting = true;
|
||||
const rowToInsert = this.localRow;
|
||||
Object.keys(rowToInsert).forEach(key => {
|
||||
if (this.fieldsToExclude.includes(key))
|
||||
delete rowToInsert[key];
|
||||
if (typeof rowToInsert[key] === 'undefined')
|
||||
delete rowToInsert[key];
|
||||
});
|
||||
|
||||
const fieldTypes = {};
|
||||
this.fields.forEach(field => {
|
||||
fieldTypes[field.name] = field.type;
|
||||
});
|
||||
|
||||
try {
|
||||
const { status, response } = await Tables.insertTableRows({
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.workspace.breadcrumbs.schema,
|
||||
table: this.workspace.breadcrumbs.table,
|
||||
row: rowToInsert,
|
||||
repeat: this.nInserts,
|
||||
fields: fieldTypes
|
||||
});
|
||||
|
||||
if (status === 'success') {
|
||||
this.closeModal();
|
||||
this.$emit('reload');
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isInserting = false;
|
||||
},
|
||||
closeModal () {
|
||||
this.$emit('hide');
|
||||
},
|
||||
fieldLength (field) {
|
||||
if ([...BLOB, ...LONG_TEXT].includes(field.type)) return null;
|
||||
else if (TEXT.includes(field.type)) return field.charLength;
|
||||
return field.length;
|
||||
},
|
||||
inputProps (field) {
|
||||
if ([...TEXT, ...LONG_TEXT].includes(field.type))
|
||||
return { type: 'text', mask: false };
|
||||
|
||||
if ([...NUMBER, ...FLOAT].includes(field.type))
|
||||
return { type: 'number', mask: false };
|
||||
|
||||
if (TIME.includes(field.type)) {
|
||||
let timeMask = '##:##:##';
|
||||
const precision = this.fieldLength(field);
|
||||
|
||||
for (let i = 0; i < precision; i++)
|
||||
timeMask += i === 0 ? '.#' : '#';
|
||||
|
||||
return { type: 'text', mask: timeMask };
|
||||
}
|
||||
|
||||
if (DATE.includes(field.type))
|
||||
return { type: 'text', mask: '####-##-##' };
|
||||
|
||||
if (DATETIME.includes(field.type)) {
|
||||
let datetimeMask = '####-##-## ##:##:##';
|
||||
const precision = this.fieldLength(field);
|
||||
|
||||
for (let i = 0; i < precision; i++)
|
||||
datetimeMask += i === 0 ? '.#' : '#';
|
||||
|
||||
return { type: 'text', mask: datetimeMask };
|
||||
}
|
||||
|
||||
if (BLOB.includes(field.type))
|
||||
return { type: 'file', mask: false };
|
||||
|
||||
if (BIT.includes(field.type))
|
||||
return { type: 'text', mask: false };
|
||||
|
||||
return { type: 'text', mask: false };
|
||||
},
|
||||
toggleFields (event, field) {
|
||||
if (event.target.checked)
|
||||
this.fieldsToExclude = this.fieldsToExclude.filter(f => f !== field.name);
|
||||
else
|
||||
this.fieldsToExclude = [...this.fieldsToExclude, field.name];
|
||||
},
|
||||
filesChange (event, field) {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
this.localRow[field] = files[0].path;
|
||||
},
|
||||
getKeyUsage (keyName) {
|
||||
return this.keyUsage.find(key => key.field === keyName);
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-container {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
overflow: hidden;
|
||||
white-space: normal;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.input-group-addon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
@ -133,218 +133,218 @@
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { Component, computed, onBeforeUnmount, onMounted, onUpdated, Prop, Ref, ref } from 'vue';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
import { arrayToFile } from '../libs/arrayToFile';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
|
||||
import ModalProcessesListRow from '@/components/ModalProcessesListRow';
|
||||
import ModalProcessesListContext from '@/components/ModalProcessesListContext';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
|
||||
import ModalProcessesListRow from '@/components/ModalProcessesListRow.vue';
|
||||
import ModalProcessesListContext from '@/components/ModalProcessesListContext.vue';
|
||||
|
||||
export default {
|
||||
name: 'ModalProcessesList',
|
||||
components: {
|
||||
BaseVirtualScroll,
|
||||
ModalProcessesListRow,
|
||||
ModalProcessesListContext
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
emits: ['close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
|
||||
return { addNotification, getConnectionName };
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
resultsSize: 1000,
|
||||
isQuering: false,
|
||||
isContext: false,
|
||||
autorefreshTimer: 0,
|
||||
refreshInterval: null,
|
||||
contextEvent: null,
|
||||
selectedCell: null,
|
||||
selectedRow: null,
|
||||
results: [],
|
||||
fields: [],
|
||||
currentSort: '',
|
||||
currentSortDir: 'asc',
|
||||
scrollElement: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
connectionName () {
|
||||
return this.getConnectionName(this.connection.uid);
|
||||
},
|
||||
sortedResults () {
|
||||
if (this.currentSort) {
|
||||
return [...this.results].sort((a, b) => {
|
||||
let modifier = 1;
|
||||
const valA = typeof a[this.currentSort] === 'string' ? a[this.currentSort].toLowerCase() : a[this.currentSort];
|
||||
const valB = typeof b[this.currentSort] === 'string' ? b[this.currentSort].toLowerCase() : b[this.currentSort];
|
||||
if (this.currentSortDir === 'desc') modifier = -1;
|
||||
if (valA < valB) return -1 * modifier;
|
||||
if (valA > valB) return 1 * modifier;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
else
|
||||
return this.results;
|
||||
const props = defineProps({
|
||||
connection: Object as Prop<ConnectionParams>
|
||||
});
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const tableWrapper: Ref<HTMLDivElement> = ref(null);
|
||||
const table: Ref<HTMLDivElement> = ref(null);
|
||||
const resultTable: Ref<Component & {updateWindow: () => void}> = ref(null);
|
||||
const resultsSize = ref(1000);
|
||||
const isQuering = ref(false);
|
||||
const isContext = ref(false);
|
||||
const autorefreshTimer = ref(0);
|
||||
const refreshInterval: Ref<NodeJS.Timeout> = ref(null);
|
||||
const contextEvent = ref(null);
|
||||
const selectedCell = ref(null);
|
||||
const selectedRow: Ref<number> = ref(null);
|
||||
const results = ref([]);
|
||||
const fields = ref([]);
|
||||
const currentSort = ref('');
|
||||
const currentSortDir = ref('asc');
|
||||
const scrollElement = ref(null);
|
||||
|
||||
const connectionName = computed(() => getConnectionName(props.connection.uid));
|
||||
|
||||
const sortedResults = computed(() => {
|
||||
if (currentSort.value) {
|
||||
return [...results.value].sort((a, b) => {
|
||||
let modifier = 1;
|
||||
const valA = typeof a[currentSort.value] === 'string' ? a[currentSort.value].toLowerCase() : a[currentSort.value];
|
||||
const valB = typeof b[currentSort.value] === 'string' ? b[currentSort.value].toLowerCase() : b[currentSort.value];
|
||||
if (currentSortDir.value === 'desc') modifier = -1;
|
||||
if (valA < valB) return -1 * modifier;
|
||||
if (valA > valB) return 1 * modifier;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
else
|
||||
return results.value;
|
||||
});
|
||||
|
||||
const getProcessesList = async () => {
|
||||
isQuering.value = true;
|
||||
|
||||
try { // Table data
|
||||
const { status, response } = await Schema.getProcesses(props.connection.uid);
|
||||
|
||||
if (status === 'success') {
|
||||
results.value = response;
|
||||
fields.value = response.length ? Object.keys(response[0]) : [];
|
||||
}
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey, { capture: true });
|
||||
},
|
||||
updated () {
|
||||
if (this.$refs.table)
|
||||
this.refreshScroller();
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
if (this.$refs.tableWrapper)
|
||||
this.scrollElement = this.$refs.tableWrapper;
|
||||
},
|
||||
mounted () {
|
||||
this.getProcessesList();
|
||||
window.addEventListener('resize', this.resizeResults);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey, { capture: true });
|
||||
window.removeEventListener('resize', this.resizeResults);
|
||||
clearInterval(this.refreshInterval);
|
||||
},
|
||||
methods: {
|
||||
async getProcessesList () {
|
||||
this.isQuering = true;
|
||||
isQuering.value = false;
|
||||
};
|
||||
|
||||
// if table changes clear cached values
|
||||
if (this.lastTable !== this.table)
|
||||
this.results = [];
|
||||
const setRefreshInterval = () => {
|
||||
clearRefresh();
|
||||
|
||||
try { // Table data
|
||||
const { status, response } = await Schema.getProcesses(this.connection.uid);
|
||||
|
||||
if (status === 'success') {
|
||||
this.results = response;
|
||||
this.fields = response.length ? Object.keys(response[0]) : [];
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isQuering = false;
|
||||
},
|
||||
setRefreshInterval () {
|
||||
this.clearRefresh();
|
||||
|
||||
if (+this.autorefreshTimer) {
|
||||
this.refreshInterval = setInterval(() => {
|
||||
if (!this.isQuering)
|
||||
this.getProcessesList();
|
||||
}, this.autorefreshTimer * 1000);
|
||||
}
|
||||
},
|
||||
clearRefresh () {
|
||||
if (this.refreshInterval)
|
||||
clearInterval(this.refreshInterval);
|
||||
},
|
||||
resizeResults () {
|
||||
if (this.$refs.resultTable) {
|
||||
const el = this.$refs.tableWrapper.parentElement;
|
||||
|
||||
if (el) {
|
||||
const size = el.offsetHeight;
|
||||
this.resultsSize = size;
|
||||
}
|
||||
this.$refs.resultTable.updateWindow();
|
||||
}
|
||||
},
|
||||
refreshScroller () {
|
||||
this.resizeResults();
|
||||
},
|
||||
sort (field) {
|
||||
if (field === this.currentSort) {
|
||||
if (this.currentSortDir === 'asc')
|
||||
this.currentSortDir = 'desc';
|
||||
else
|
||||
this.resetSort();
|
||||
}
|
||||
else {
|
||||
this.currentSortDir = 'asc';
|
||||
this.currentSort = field;
|
||||
}
|
||||
},
|
||||
resetSort () {
|
||||
this.currentSort = '';
|
||||
this.currentSortDir = 'asc';
|
||||
},
|
||||
stopRefresh () {
|
||||
this.autorefreshTimer = 0;
|
||||
this.clearRefresh();
|
||||
},
|
||||
selectRow (row) {
|
||||
this.selectedRow = Number(row);
|
||||
},
|
||||
contextMenu (event, cell) {
|
||||
if (event.target.localName === 'input') return;
|
||||
this.stopRefresh();
|
||||
|
||||
this.selectedCell = cell;
|
||||
this.selectedRow = Number(cell.id);
|
||||
this.contextEvent = event;
|
||||
this.isContext = true;
|
||||
},
|
||||
async killProcess () {
|
||||
try { // Table data
|
||||
const { status, response } = await Schema.killProcess({ uid: this.connection.uid, pid: this.selectedRow });
|
||||
|
||||
if (status === 'success')
|
||||
this.getProcessesList();
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
closeContext () {
|
||||
this.isContext = false;
|
||||
},
|
||||
copyCell () {
|
||||
const row = this.results.find(row => row.id === this.selectedRow);
|
||||
const valueToCopy = row[this.selectedCell.field];
|
||||
navigator.clipboard.writeText(valueToCopy);
|
||||
},
|
||||
copyRow () {
|
||||
const row = this.results.find(row => row.id === this.selectedRow);
|
||||
const rowToCopy = JSON.parse(JSON.stringify(row));
|
||||
navigator.clipboard.writeText(JSON.stringify(rowToCopy));
|
||||
},
|
||||
closeModal () {
|
||||
this.$emit('close');
|
||||
},
|
||||
downloadTable (format) {
|
||||
if (!this.sortedResults) return;
|
||||
arrayToFile({
|
||||
type: format,
|
||||
content: this.sortedResults,
|
||||
filename: 'processes'
|
||||
});
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
if (e.key === 'F5')
|
||||
this.getProcessesList();
|
||||
}
|
||||
if (+autorefreshTimer.value) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
if (!isQuering.value)
|
||||
getProcessesList();
|
||||
}, autorefreshTimer.value * 1000);
|
||||
}
|
||||
};
|
||||
|
||||
const clearRefresh = () => {
|
||||
if (refreshInterval.value)
|
||||
clearInterval(refreshInterval.value);
|
||||
};
|
||||
|
||||
const resizeResults = () => {
|
||||
if (resultTable.value) {
|
||||
const el = tableWrapper.value.parentElement;
|
||||
|
||||
if (el) {
|
||||
const size = el.offsetHeight;
|
||||
resultsSize.value = size;
|
||||
}
|
||||
resultTable.value.updateWindow();
|
||||
}
|
||||
};
|
||||
|
||||
const refreshScroller = () => resizeResults();
|
||||
|
||||
const sort = (field: string) => {
|
||||
if (field === currentSort.value) {
|
||||
if (currentSortDir.value === 'asc')
|
||||
currentSortDir.value = 'desc';
|
||||
else
|
||||
resetSort();
|
||||
}
|
||||
else {
|
||||
currentSortDir.value = 'asc';
|
||||
currentSort.value = field;
|
||||
}
|
||||
};
|
||||
|
||||
const resetSort = () => {
|
||||
currentSort.value = '';
|
||||
currentSortDir.value = 'asc';
|
||||
};
|
||||
|
||||
const stopRefresh = () => {
|
||||
autorefreshTimer.value = 0;
|
||||
clearRefresh();
|
||||
};
|
||||
|
||||
const selectRow = (row: number) => {
|
||||
selectedRow.value = Number(row);
|
||||
};
|
||||
|
||||
const contextMenu = (event: MouseEvent, cell: { id: number; field: string }) => {
|
||||
if ((event.target as HTMLElement).localName === 'input') return;
|
||||
stopRefresh();
|
||||
|
||||
selectedCell.value = cell;
|
||||
selectedRow.value = Number(cell.id);
|
||||
contextEvent.value = event;
|
||||
isContext.value = true;
|
||||
};
|
||||
|
||||
const killProcess = async () => {
|
||||
try { // Table data
|
||||
const { status, response } = await Schema.killProcess({ uid: props.connection.uid, pid: selectedRow.value });
|
||||
|
||||
if (status === 'success')
|
||||
getProcessesList();
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
};
|
||||
|
||||
const closeContext = () => {
|
||||
isContext.value = false;
|
||||
};
|
||||
|
||||
const copyCell = () => {
|
||||
const row = results.value.find(row => row.id === selectedRow.value);
|
||||
const valueToCopy = row[selectedCell.value.field];
|
||||
navigator.clipboard.writeText(valueToCopy);
|
||||
};
|
||||
|
||||
const copyRow = () => {
|
||||
const row = results.value.find(row => row.id === selectedRow.value);
|
||||
const rowToCopy = JSON.parse(JSON.stringify(row));
|
||||
navigator.clipboard.writeText(JSON.stringify(rowToCopy));
|
||||
};
|
||||
|
||||
const closeModal = () => emit('close');
|
||||
|
||||
const downloadTable = (format: 'csv' | 'json') => {
|
||||
if (!sortedResults.value) return;
|
||||
arrayToFile({
|
||||
type: format,
|
||||
content: sortedResults.value,
|
||||
filename: 'processes'
|
||||
});
|
||||
};
|
||||
|
||||
const onKey = (e:KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
closeModal();
|
||||
if (e.key === 'F5')
|
||||
getProcessesList();
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', onKey, { capture: true });
|
||||
|
||||
onMounted(() => {
|
||||
getProcessesList();
|
||||
window.addEventListener('resize', resizeResults);
|
||||
});
|
||||
|
||||
onUpdated(() => {
|
||||
if (table.value)
|
||||
refreshScroller();
|
||||
if (tableWrapper.value)
|
||||
scrollElement.value = tableWrapper.value;
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKey, { capture: true });
|
||||
window.removeEventListener('resize', resizeResults);
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
defineExpose({ refreshScroller });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -56,7 +56,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, Ref } from 'vue';
|
||||
import { ref, Ref, computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
@ -64,7 +64,6 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import * as Draggable from 'vuedraggable';
|
||||
import SettingBarContext from '@/components/SettingBarContext.vue';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
import { computed } from '@vue/reactivity';
|
||||
|
||||
const applicationStore = useApplicationStore();
|
||||
const connectionsStore = useConnectionsStore();
|
||||
@ -80,7 +79,7 @@ const { getWorkspace, selectWorkspace } = workspacesStore;
|
||||
|
||||
const isContext: Ref<boolean> = ref(false);
|
||||
const isDragging: Ref<boolean> = ref(false);
|
||||
const contextEvent: Ref<Event> = ref(null);
|
||||
const contextEvent: Ref<MouseEvent> = ref(null);
|
||||
const contextConnection: Ref<ConnectionParams> = ref(null);
|
||||
|
||||
const connections = computed({
|
||||
@ -94,7 +93,7 @@ const connections = computed({
|
||||
|
||||
const hasUpdates = computed(() => ['available', 'downloading', 'downloaded', 'link'].includes(updateStatus.value));
|
||||
|
||||
const contextMenu = (event: Event, connection: ConnectionParams) => {
|
||||
const contextMenu = (event: MouseEvent, connection: ConnectionParams) => {
|
||||
contextEvent.value = event;
|
||||
contextConnection.value = connection;
|
||||
isContext.value = true;
|
||||
@ -133,110 +132,6 @@ const dragStop = (e: any) => { // TODO: temp
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- <script>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Draggable from 'vuedraggable';
|
||||
import SettingBarContext from '@/components/SettingBarContext';
|
||||
|
||||
export default {
|
||||
name: 'TheSettingBar',
|
||||
components: {
|
||||
Draggable,
|
||||
SettingBarContext
|
||||
},
|
||||
setup () {
|
||||
const applicationStore = useApplicationStore();
|
||||
const connectionsStore = useConnectionsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { updateStatus } = storeToRefs(applicationStore);
|
||||
const { connections: getConnections } = storeToRefs(connectionsStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { showSettingModal, showScratchpad } = applicationStore;
|
||||
const { getConnectionName, updateConnections } = connectionsStore;
|
||||
const { getWorkspace, selectWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
applicationStore,
|
||||
updateStatus,
|
||||
showSettingModal,
|
||||
showScratchpad,
|
||||
getConnections,
|
||||
getConnectionName,
|
||||
updateConnections,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
selectWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dragElement: null,
|
||||
isContext: false,
|
||||
isDragging: false,
|
||||
contextEvent: null,
|
||||
contextConnection: {},
|
||||
scale: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
connections: {
|
||||
get () {
|
||||
return this.getConnections;
|
||||
},
|
||||
set (value) {
|
||||
this.updateConnections(value);
|
||||
}
|
||||
},
|
||||
hasUpdates () {
|
||||
return ['available', 'downloading', 'downloaded', 'link'].includes(this.updateStatus);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
contextMenu (event, connection) {
|
||||
this.contextEvent = event;
|
||||
this.contextConnection = connection;
|
||||
this.isContext = true;
|
||||
},
|
||||
workspaceName (connection) {
|
||||
return connection.ask ? '' : `${connection.user + '@'}${connection.host}:${connection.port}`;
|
||||
},
|
||||
tooltipPosition (e) {
|
||||
const el = e.target ? e.target : e;
|
||||
const fromTop = window.pageYOffset + el.getBoundingClientRect().top - (el.offsetHeight / 4);
|
||||
el.querySelector('.ex-tooltip-content').style.top = `${fromTop}px`;
|
||||
},
|
||||
getStatusBadge (uid) {
|
||||
if (this.getWorkspace(uid)) {
|
||||
const status = this.getWorkspace(uid).connectionStatus;
|
||||
|
||||
switch (status) {
|
||||
case 'connected':
|
||||
return 'badge badge-connected';
|
||||
case 'connecting':
|
||||
return 'badge badge-connecting';
|
||||
case 'failed':
|
||||
return 'badge badge-failed';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
dragStop (e) {
|
||||
this.isDragging = false;
|
||||
|
||||
setTimeout(() => {
|
||||
this.tooltipPosition(e.originalEvent.target.parentNode);
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script> -->
|
||||
|
||||
<style lang="scss">
|
||||
#settingbar {
|
||||
width: $settingbar-width;
|
||||
|
@ -53,13 +53,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onUnmounted, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { getCurrentWindow } from '@electron/remote';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { onUnmounted, ref } from 'vue';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -326,7 +326,7 @@
|
||||
/>
|
||||
<WorkspaceTabTable
|
||||
v-else-if="['temp-data', 'data'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_data'"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
@ -336,7 +336,7 @@
|
||||
/>
|
||||
<WorkspaceTabNewTable
|
||||
v-else-if="tab.type === 'new-table'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_new-table'"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
@ -345,7 +345,7 @@
|
||||
/>
|
||||
<WorkspaceTabPropsTable
|
||||
v-else-if="tab.type === 'table-props'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_table-props'"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
@ -354,7 +354,7 @@
|
||||
/>
|
||||
<WorkspaceTabNewView
|
||||
v-else-if="tab.type === 'new-view'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_new-view'"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
@ -363,7 +363,7 @@
|
||||
/>
|
||||
<WorkspaceTabPropsView
|
||||
v-else-if="tab.type === 'view-props'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_view-props'"
|
||||
:tab-uid="tab.uid"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:connection="connection"
|
||||
@ -372,7 +372,7 @@
|
||||
/>
|
||||
<WorkspaceTabNewTrigger
|
||||
v-else-if="tab.type === 'new-trigger'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_new-trigger'"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
@ -382,7 +382,7 @@
|
||||
/>
|
||||
<WorkspaceTabPropsTrigger
|
||||
v-else-if="['temp-trigger-props', 'trigger-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_trigger-props'"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
@ -391,7 +391,7 @@
|
||||
/>
|
||||
<WorkspaceTabNewTriggerFunction
|
||||
v-else-if="tab.type === 'new-trigger-function'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_new-trigger-function'"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
@ -401,7 +401,7 @@
|
||||
/>
|
||||
<WorkspaceTabPropsTriggerFunction
|
||||
v-else-if="['temp-trigger-function-props', 'trigger-function-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_trigger-function-props'"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
@ -410,7 +410,7 @@
|
||||
/>
|
||||
<WorkspaceTabNewRoutine
|
||||
v-else-if="tab.type === 'new-routine'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_new-routine'"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
@ -420,7 +420,7 @@
|
||||
/>
|
||||
<WorkspaceTabPropsRoutine
|
||||
v-else-if="['temp-routine-props', 'routine-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_routine-props'"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
@ -429,7 +429,7 @@
|
||||
/>
|
||||
<WorkspaceTabNewFunction
|
||||
v-else-if="tab.type === 'new-function'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_new-function'"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
@ -439,7 +439,7 @@
|
||||
/>
|
||||
<WorkspaceTabPropsFunction
|
||||
v-else-if="['temp-function-props', 'function-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_function-props'"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
@ -448,7 +448,7 @@
|
||||
/>
|
||||
<WorkspaceTabNewScheduler
|
||||
v-else-if="tab.type === 'new-scheduler'"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_new-scheduler'"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
@ -458,7 +458,7 @@
|
||||
/>
|
||||
<WorkspaceTabPropsScheduler
|
||||
v-else-if="['temp-scheduler-props', 'scheduler-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:key="tab.uid+'_scheduler-props'"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
|
@ -272,7 +272,13 @@ export default {
|
||||
sql = `CALL \`${this.localElement.name}\`(${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.workspace.uid, content: sql, type: 'query', autorun: true });
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
content: sql,
|
||||
type: 'query',
|
||||
schema: this.selectedSchema,
|
||||
autorun: true
|
||||
});
|
||||
this.closeContext();
|
||||
},
|
||||
async runFunctionCheck () {
|
||||
@ -317,7 +323,13 @@ export default {
|
||||
sql = `SELECT \`${this.localElement.name}\` (${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.workspace.uid, content: sql, type: 'query', autorun: true });
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
content: sql,
|
||||
type: 'query',
|
||||
schema: this.selectedSchema,
|
||||
autorun: true
|
||||
});
|
||||
this.closeContext();
|
||||
},
|
||||
async toggleTrigger () {
|
||||
|
@ -156,14 +156,6 @@
|
||||
@hard-sort="hardSort"
|
||||
/>
|
||||
</div>
|
||||
<ModalNewTableRow
|
||||
v-if="isAddModal"
|
||||
:fields="fields"
|
||||
:key-usage="keyUsage"
|
||||
:tab-uid="tabUid"
|
||||
@hide="hideAddModal"
|
||||
@reload="reloadTable"
|
||||
/>
|
||||
<ModalFakerRows
|
||||
v-if="isFakerModal"
|
||||
:fields="fields"
|
||||
@ -184,7 +176,6 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import WorkspaceTabQueryTable from '@/components/WorkspaceTabQueryTable';
|
||||
import WorkspaceTabTableFilters from '@/components/WorkspaceTabTableFilters';
|
||||
import ModalNewTableRow from '@/components/ModalNewTableRow';
|
||||
import ModalFakerRows from '@/components/ModalFakerRows';
|
||||
import tableTabs from '@/mixins/tableTabs';
|
||||
|
||||
@ -194,7 +185,6 @@ export default {
|
||||
BaseLoader,
|
||||
WorkspaceTabQueryTable,
|
||||
WorkspaceTabTableFilters,
|
||||
ModalNewTableRow,
|
||||
ModalFakerRows
|
||||
},
|
||||
mixins: [tableTabs],
|
||||
@ -231,7 +221,6 @@ export default {
|
||||
isSearch: false,
|
||||
results: [],
|
||||
lastTable: null,
|
||||
isAddModal: false,
|
||||
isFakerModal: false,
|
||||
autorefreshTimer: 0,
|
||||
refreshInterval: null,
|
||||
@ -410,12 +399,6 @@ export default {
|
||||
else if (direction === 'prev' && this.page > 1)
|
||||
this.page--;
|
||||
},
|
||||
showAddModal () {
|
||||
this.isAddModal = true;
|
||||
},
|
||||
hideAddModal () {
|
||||
this.isAddModal = false;
|
||||
},
|
||||
showFakerModal () {
|
||||
if (this.isQuering) return;
|
||||
this.isFakerModal = true;
|
||||
|
0
src/renderer/composables/useFilter.ts
Normal file
0
src/renderer/composables/useFilter.ts
Normal file
@ -1,22 +1,24 @@
|
||||
import formatter from 'pg-connection-string'; // parses a connection string
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
import * as formatter from 'pg-connection-string'; // parses a connection string
|
||||
|
||||
const formatHost = host => {
|
||||
const formatHost = (host: string) => {
|
||||
const results = host === 'localhost' ? '127.0.0.1' : host;
|
||||
return results;
|
||||
};
|
||||
|
||||
const checkForSSl = conn => {
|
||||
const checkForSSl = (conn: string) => {
|
||||
return conn.includes('ssl=true');
|
||||
};
|
||||
|
||||
const connStringConstruct = (args) => {
|
||||
const connStringConstruct = (args: ConnectionParams & { pgConnString: string }): ConnectionParams => {
|
||||
if (!args.pgConnString)
|
||||
return args;
|
||||
|
||||
if (typeof args.pgConnString !== 'string')
|
||||
return args;
|
||||
|
||||
const stringArgs = formatter.parse(args.pgConnString);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const stringArgs: any = formatter.parse(args.pgConnString);
|
||||
|
||||
const client = args.client || 'pg';
|
||||
|
@ -1,14 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
/* eslint-disable @typescript-eslint/no-this-alias */
|
||||
/* eslint-disable no-labels */
|
||||
/* eslint-disable no-return-assign */
|
||||
/* eslint-disable no-cond-assign */
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
/* eslint-disable no-mixed-operators */
|
||||
/* eslint-disable */
|
||||
/*
|
||||
Got from 'ace-builds/src-noconflict/ext-language_tools' and edited to support icons.
|
||||
I'm not responsible of this crazy code.
|
||||
I'm not responsible of this crazy code 🤯.
|
||||
*/
|
||||
|
||||
ace.define('ace/snippets', ['require', 'exports', 'module', 'ace/lib/oop', 'ace/lib/event_emitter', 'ace/lib/lang', 'ace/range', 'ace/range_list', 'ace/keyboard/hash_handler', 'ace/tokenizer', 'ace/clipboard', 'ace/lib/dom', 'ace/editor'], function (require, exports, module) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user