mirror of https://github.com/Fabio286/antares.git
refactor: ts and composition api on more components
This commit is contained in:
parent
2007305ff0
commit
7fc01227e7
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "antares",
|
||||
"version": "0.5.4",
|
||||
"version": "0.5.5",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "antares",
|
||||
"version": "0.5.4",
|
||||
"version": "0.5.5",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
import * as mysql from 'common/customizations/mysql';
|
||||
import * as postgresql from 'common/customizations/postgresql';
|
||||
import * as sqlite from 'common/customizations/sqlite';
|
||||
import { Customizations } from 'common/interfaces/customizations';
|
||||
|
||||
export default {
|
||||
maria: mysql.customizations,
|
||||
mysql: mysql.customizations,
|
||||
pg: postgresql.customizations,
|
||||
sqlite: sqlite.customizations
|
||||
} as {
|
||||
maria: Customizations;
|
||||
mysql: Customizations;
|
||||
pg: Customizations;
|
||||
sqlite: Customizations;
|
||||
};
|
||||
|
|
|
@ -104,8 +104,6 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||
escapedParam = `"${sqlEscaper(params.content)}"`;
|
||||
break;
|
||||
case 'pg':
|
||||
escapedParam = `'${params.content.replaceAll('\'', '\'\'')}'`;
|
||||
break;
|
||||
case 'sqlite':
|
||||
escapedParam = `'${params.content.replaceAll('\'', '\'\'')}'`;
|
||||
break;
|
||||
|
@ -248,8 +246,7 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||
|
||||
ipcMain.handle('insert-table-rows', async (event, params) => {
|
||||
try { // TODO: move to client classes
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const insertObj: {[key: string]: any} = {};
|
||||
const insertObj: {[key: string]: string | number | boolean | Date | Buffer} = {};
|
||||
for (const key in params.row) {
|
||||
const type = params.fields[key];
|
||||
let escapedParam;
|
||||
|
@ -318,12 +315,10 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||
|
||||
ipcMain.handle('insert-table-fake-rows', async (event, params: InsertRowsParams) => {
|
||||
try { // TODO: move to client classes
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const rows: {[key: string]: any}[] = [];
|
||||
const rows: {[key: string]: string | number | boolean | Date | Buffer}[] = [];
|
||||
|
||||
for (let i = 0; i < +params.repeat; i++) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const insertObj: {[key: string]: any} = {};
|
||||
const insertObj: {[key: string]: string | number | boolean | Date | Buffer} = {};
|
||||
|
||||
for (const key in params.row) {
|
||||
const type = params.fields[key];
|
||||
|
@ -341,6 +336,7 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||
escapedParam = `"${sqlEscaper(params.row[key].value)}"`;
|
||||
break;
|
||||
case 'pg':
|
||||
case 'sqlite':
|
||||
escapedParam = `'${params.row[key].value.replaceAll('\'', '\'\'')}'`;
|
||||
break;
|
||||
}
|
||||
|
@ -381,8 +377,7 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||
insertObj[key] = escapedParam;
|
||||
}
|
||||
else { // Faker value
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const parsedParams: {[key: string]: any} = {};
|
||||
const parsedParams: {[key: string]: string | number | boolean | Date | Buffer} = {};
|
||||
let fakeValue;
|
||||
|
||||
if (params.locale)
|
||||
|
@ -402,7 +397,7 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||
|
||||
if (typeof fakeValue === 'string') {
|
||||
if (params.row[key].length)
|
||||
fakeValue = fakeValue.substr(0, params.row[key].length);
|
||||
fakeValue = fakeValue.substring(0, params.row[key].length);
|
||||
fakeValue = `'${sqlEscaper(fakeValue)}'`;
|
||||
}
|
||||
else if ([...DATE, ...DATETIME].includes(type))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { ipcMain } from 'electron';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import Store from 'electron-store';
|
||||
const persistentStore = new Store({ name: 'settings' });
|
||||
import * as Store from 'electron-store';
|
||||
const persistentStore = new Store({ name: 'settings', clearInvalidConfig: true });
|
||||
const isMacOS = process.platform === 'darwin';
|
||||
|
||||
let mainWindow: Electron.IpcMainEvent;
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
v-if="isOpen"
|
||||
ref="optionList"
|
||||
:class="`select__list-wrapper ${dropdownClass ? dropdownClass : '' }`"
|
||||
@mousedown="isMouseDown = true"
|
||||
@mouseup="handleMouseUpEvent()"
|
||||
>
|
||||
<ul class="select__list" @mousedown.prevent>
|
||||
<li
|
||||
|
@ -136,6 +138,7 @@ export default defineComponent({
|
|||
setup (props, { emit }) {
|
||||
const hightlightedIndex = ref(0);
|
||||
const isOpen = ref(false);
|
||||
const isMouseDown = ref(false);
|
||||
const internalValue = ref(props.modelValue || props.value);
|
||||
const el = ref(null);
|
||||
const searchInput = ref(null);
|
||||
|
@ -151,7 +154,7 @@ export default defineComponent({
|
|||
if (typeof prop === 'function')
|
||||
return prop(item);
|
||||
|
||||
return item[prop] || item;
|
||||
return item[prop] !== undefined ? item[prop] : item;
|
||||
};
|
||||
|
||||
const flattenOptions = computed(() => {
|
||||
|
@ -319,12 +322,24 @@ export default defineComponent({
|
|||
};
|
||||
|
||||
const handleBlurEvent = () => {
|
||||
if (isMouseDown.value) return;
|
||||
deactivate();
|
||||
emit('blur');
|
||||
};
|
||||
|
||||
const handleMouseUpEvent = () => {
|
||||
isMouseDown.value = false;
|
||||
searchInput.value.focus();
|
||||
};
|
||||
|
||||
const handleWheelEvent = (e) => {
|
||||
if (!e.target.className.includes('select__')) deactivate();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', adjustListPosition);
|
||||
window.addEventListener('wheel', handleWheelEvent);
|
||||
|
||||
nextTick(() => {
|
||||
// fix position when the component is created and opened at the same time
|
||||
if (isOpen.value) {
|
||||
|
@ -336,6 +351,7 @@ export default defineComponent({
|
|||
});
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', adjustListPosition);
|
||||
window.removeEventListener('wheel', handleWheelEvent);
|
||||
});
|
||||
|
||||
return {
|
||||
|
@ -351,10 +367,12 @@ export default defineComponent({
|
|||
isSelected,
|
||||
keyArrows,
|
||||
isOpen,
|
||||
isMouseDown,
|
||||
hightlightedIndex,
|
||||
optionList,
|
||||
optionRefs,
|
||||
handleBlurEvent
|
||||
handleBlurEvent,
|
||||
handleMouseUpEvent
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
@ -101,17 +101,10 @@
|
|||
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 { HistoryRecord, useHistoryStore } from '@/stores/history';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
|
||||
|
||||
interface HistoryRow {
|
||||
uid:string;
|
||||
sql: string;
|
||||
schema: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
const { getHistoryByWorkspace, deleteQueryFromHistory } = useHistoryStore();
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
|
||||
|
@ -132,7 +125,7 @@ const searchTerm = ref('');
|
|||
const localSearchTerm = ref('');
|
||||
|
||||
const connectionName = computed(() => getConnectionName(props.connection.uid));
|
||||
const history: ComputedRef<HistoryRow[]> = computed(() => (getHistoryByWorkspace(props.connection.uid) || []));
|
||||
const history: ComputedRef<HistoryRecord[]> = computed(() => (getHistoryByWorkspace(props.connection.uid) || []));
|
||||
const filteredHistory = computed(() => history.value.filter(q => q.sql.toLowerCase().search(searchTerm.value.toLowerCase()) >= 0));
|
||||
|
||||
watch(searchTerm, () => {
|
||||
|
@ -147,7 +140,7 @@ const copyQuery = (sql: string) => {
|
|||
navigator.clipboard.writeText(sql);
|
||||
};
|
||||
|
||||
const deleteQuery = (query: HistoryRow[]) => {
|
||||
const deleteQuery = (query: HistoryRecord[]) => {
|
||||
deleteQueryFromHistory({
|
||||
workspace: props.connection.uid,
|
||||
...query
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, Prop, Ref, ref, toRef, watch } from 'vue';
|
||||
import * as ace from 'ace-builds';
|
||||
import 'ace-builds/webpack-resolver';
|
||||
import '../libs/ext-language_tools';
|
||||
|
@ -16,329 +17,330 @@ import { storeToRefs } from 'pinia';
|
|||
import { uidGen } from 'common/libs/uidGen';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { Workspace } from '@/stores/workspaces';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
|
||||
export default {
|
||||
name: 'QueryEditor',
|
||||
props: {
|
||||
modelValue: String,
|
||||
workspace: Object,
|
||||
isSelected: Boolean,
|
||||
schema: { type: String, default: '' },
|
||||
autoFocus: { type: Boolean, default: false },
|
||||
readOnly: { type: Boolean, default: false },
|
||||
height: { type: Number, default: 200 }
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup () {
|
||||
const editor = null;
|
||||
const applicationStore = useApplicationStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const editor: Ref<ace.Ace.Editor> = ref(null);
|
||||
const applicationStore = useApplicationStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const { setBaseCompleters } = applicationStore;
|
||||
const { setBaseCompleters } = applicationStore;
|
||||
|
||||
const { baseCompleter } = storeToRefs(applicationStore);
|
||||
const {
|
||||
editorTheme,
|
||||
editorFontSize,
|
||||
autoComplete,
|
||||
lineWrap
|
||||
} = storeToRefs(settingsStore);
|
||||
const { baseCompleter } = storeToRefs(applicationStore);
|
||||
const {
|
||||
editorTheme,
|
||||
editorFontSize,
|
||||
autoComplete,
|
||||
lineWrap
|
||||
} = storeToRefs(settingsStore);
|
||||
|
||||
return {
|
||||
editor,
|
||||
baseCompleter,
|
||||
setBaseCompleters,
|
||||
editorTheme,
|
||||
editorFontSize,
|
||||
autoComplete,
|
||||
lineWrap
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
cursorPosition: 0,
|
||||
fields: [],
|
||||
customCompleter: [],
|
||||
id: uidGen(),
|
||||
lastSchema: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
tables () {
|
||||
return this.workspace
|
||||
? this.workspace.structure.filter(schema => schema.name === this.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.tables);
|
||||
return acc;
|
||||
}, []).map(table => {
|
||||
return {
|
||||
name: table.name,
|
||||
type: table.type,
|
||||
fields: []
|
||||
};
|
||||
})
|
||||
: [];
|
||||
},
|
||||
triggers () {
|
||||
return this.workspace
|
||||
? this.workspace.structure.filter(schema => schema.name === this.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.triggers);
|
||||
return acc;
|
||||
}, []).map(trigger => {
|
||||
return {
|
||||
name: trigger.name,
|
||||
type: 'trigger'
|
||||
};
|
||||
})
|
||||
: [];
|
||||
},
|
||||
procedures () {
|
||||
return this.workspace
|
||||
? this.workspace.structure.filter(schema => schema.name === this.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.procedures);
|
||||
return acc;
|
||||
}, []).map(procedure => {
|
||||
return {
|
||||
name: `${procedure.name}()`,
|
||||
type: 'routine'
|
||||
};
|
||||
})
|
||||
: [];
|
||||
},
|
||||
functions () {
|
||||
return this.workspace
|
||||
? this.workspace.structure.filter(schema => schema.name === this.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.functions);
|
||||
return acc;
|
||||
}, []).map(func => {
|
||||
return {
|
||||
name: `${func.name}()`,
|
||||
type: 'function'
|
||||
};
|
||||
})
|
||||
: [];
|
||||
},
|
||||
schedulers () {
|
||||
return this.workspace
|
||||
? this.workspace.structure.filter(schema => schema.name === this.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.schedulers);
|
||||
return acc;
|
||||
}, []).map(scheduler => {
|
||||
return {
|
||||
name: scheduler.name,
|
||||
type: 'scheduler'
|
||||
};
|
||||
})
|
||||
: [];
|
||||
},
|
||||
mode () {
|
||||
switch (this.workspace.client) {
|
||||
case 'mysql':
|
||||
case 'maria':
|
||||
return 'mysql';
|
||||
case 'mssql':
|
||||
return 'sqlserver';
|
||||
case 'pg':
|
||||
return 'pgsql';
|
||||
default:
|
||||
return 'sql';
|
||||
}
|
||||
},
|
||||
lastWord () {
|
||||
const charsBefore = this.modelValue.slice(0, this.cursorPosition);
|
||||
const words = charsBefore.replaceAll('\n', ' ').split(' ').filter(Boolean);
|
||||
return words.pop();
|
||||
},
|
||||
isLastWordATable () {
|
||||
return /\w+\.\w*/gm.test(this.lastWord);
|
||||
},
|
||||
fieldsCompleter () {
|
||||
return {
|
||||
getCompletions: (editor, session, pos, prefix, callback) => {
|
||||
const completions = [];
|
||||
this.fields.forEach(field => {
|
||||
completions.push({
|
||||
value: field,
|
||||
meta: 'column',
|
||||
score: 1000
|
||||
});
|
||||
});
|
||||
callback(null, completions);
|
||||
}
|
||||
};
|
||||
const props = defineProps({
|
||||
modelValue: String,
|
||||
workspace: Object as Prop<Workspace>,
|
||||
isSelected: Boolean,
|
||||
schema: { type: String, default: '' },
|
||||
autoFocus: { type: Boolean, default: false },
|
||||
readOnly: { type: Boolean, default: false },
|
||||
height: { type: Number, default: 200 }
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
|
||||
const cursorPosition = ref(0);
|
||||
const fields = ref([]);
|
||||
const customCompleter = ref([]);
|
||||
const id = ref(uidGen());
|
||||
const lastSchema: Ref<string> = ref(null);
|
||||
|
||||
const tables = computed(() => {
|
||||
return props.workspace
|
||||
? props.workspace.structure.filter(schema => schema.name === props.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.tables);
|
||||
return acc;
|
||||
}, []).map(table => {
|
||||
return {
|
||||
name: table.name as string,
|
||||
type: table.type as string,
|
||||
fields: []
|
||||
};
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
const triggers = computed(() => {
|
||||
return props.workspace
|
||||
? props.workspace.structure.filter(schema => schema.name === props.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.triggers);
|
||||
return acc;
|
||||
}, []).map(trigger => {
|
||||
return {
|
||||
name: trigger.name as string,
|
||||
type: 'trigger'
|
||||
};
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
const procedures = computed(() => {
|
||||
return props.workspace
|
||||
? props.workspace.structure.filter(schema => schema.name === props.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.procedures);
|
||||
return acc;
|
||||
}, []).map(procedure => {
|
||||
return {
|
||||
name: `${procedure.name}()`,
|
||||
type: 'routine'
|
||||
};
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
const functions = computed(() => {
|
||||
return props.workspace
|
||||
? props.workspace.structure.filter(schema => schema.name === props.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.functions);
|
||||
return acc;
|
||||
}, []).map(func => {
|
||||
return {
|
||||
name: `${func.name}()`,
|
||||
type: 'function'
|
||||
};
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
const schedulers = computed(() => {
|
||||
return props.workspace
|
||||
? props.workspace.structure.filter(schema => schema.name === props.schema)
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(...curr.schedulers);
|
||||
return acc;
|
||||
}, []).map(scheduler => {
|
||||
return {
|
||||
name: scheduler.name as string,
|
||||
type: 'scheduler'
|
||||
};
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
const mode = computed(() => {
|
||||
switch (props.workspace.client) {
|
||||
case 'mysql':
|
||||
case 'maria':
|
||||
return 'mysql';
|
||||
case 'mssql':
|
||||
return 'sqlserver';
|
||||
case 'pg':
|
||||
return 'pgsql';
|
||||
default:
|
||||
return 'sql';
|
||||
}
|
||||
});
|
||||
|
||||
const lastWord = computed(() => {
|
||||
const charsBefore = props.modelValue.slice(0, cursorPosition.value);
|
||||
const words = charsBefore.replaceAll('\n', ' ').split(' ').filter(Boolean);
|
||||
return words.pop();
|
||||
});
|
||||
|
||||
const isLastWordATable = computed(() => /\w+\.\w*/gm.test(lastWord.value));
|
||||
|
||||
const fieldsCompleter = computed(() => {
|
||||
return {
|
||||
getCompletions: (editor: never, session: never, pos: never, prefix: never, callback: (err: null, response: ace.Ace.Completion[]) => void) => {
|
||||
const completions: ace.Ace.Completion[] = [];
|
||||
fields.value.forEach(field => {
|
||||
completions.push({
|
||||
value: field,
|
||||
meta: 'column',
|
||||
score: 1000
|
||||
});
|
||||
});
|
||||
callback(null, completions);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue () {
|
||||
this.cursorPosition = this.editor.session.doc.positionToIndex(this.editor.getCursorPosition());
|
||||
},
|
||||
editorTheme () {
|
||||
if (this.editor)
|
||||
this.editor.setTheme(`ace/theme/${this.editorTheme}`);
|
||||
},
|
||||
editorFontSize () {
|
||||
const sizes = {
|
||||
small: '12px',
|
||||
medium: '14px',
|
||||
large: '16px'
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
if (this.editor) {
|
||||
this.editor.setOptions({
|
||||
fontSize: sizes[this.editorFontSize]
|
||||
const setCustomCompleter = () => {
|
||||
editor.value.completers.push({
|
||||
getCompletions: (editor, session, pos, prefix, callback: (err: null, response: ace.Ace.Completion[]) => void) => {
|
||||
const completions: ace.Ace.Completion[] = [];
|
||||
[
|
||||
...tables.value,
|
||||
...triggers.value,
|
||||
...procedures.value,
|
||||
...functions.value,
|
||||
...schedulers.value
|
||||
].forEach(el => {
|
||||
completions.push({
|
||||
value: el.name,
|
||||
meta: el.type,
|
||||
score: 1000
|
||||
});
|
||||
}
|
||||
},
|
||||
autoComplete () {
|
||||
if (this.editor) {
|
||||
this.editor.setOptions({
|
||||
enableLiveAutocompletion: this.autoComplete
|
||||
});
|
||||
}
|
||||
},
|
||||
lineWrap () {
|
||||
if (this.editor) {
|
||||
this.editor.setOptions({
|
||||
wrap: this.lineWrap
|
||||
});
|
||||
}
|
||||
},
|
||||
isSelected () {
|
||||
if (this.isSelected) {
|
||||
this.lastSchema = this.schema;
|
||||
this.editor.resize();
|
||||
}
|
||||
},
|
||||
height () {
|
||||
setTimeout(() => {
|
||||
this.editor.resize();
|
||||
}, 20);
|
||||
},
|
||||
lastSchema () {
|
||||
if (this.editor) {
|
||||
this.editor.completers = this.baseCompleter.map(el => Object.assign({}, el));
|
||||
this.setCustomCompleter();
|
||||
}
|
||||
});
|
||||
callback(null, completions);
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.lastSchema = this.schema;
|
||||
},
|
||||
mounted () {
|
||||
this.editor = ace.edit(`editor-${this.id}`, {
|
||||
mode: `ace/mode/${this.mode}`,
|
||||
theme: `ace/theme/${this.editorTheme}`,
|
||||
value: this.modelValue,
|
||||
fontSize: '14px',
|
||||
printMargin: false,
|
||||
readOnly: this.readOnly
|
||||
});
|
||||
|
||||
customCompleter.value = editor.value.completers;
|
||||
};
|
||||
|
||||
watch(() => props.modelValue, () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
cursorPosition.value = (editor.value.session as any).doc.positionToIndex(editor.value.getCursorPosition());
|
||||
});
|
||||
|
||||
watch(editorTheme, () => {
|
||||
if (editor.value)
|
||||
editor.value.setTheme(`ace/theme/${editorTheme.value}`);
|
||||
});
|
||||
|
||||
watch(editorFontSize, () => {
|
||||
const sizes = {
|
||||
small: '12px',
|
||||
medium: '14px',
|
||||
large: '16px'
|
||||
};
|
||||
|
||||
if (editor.value) {
|
||||
editor.value.setOptions({
|
||||
fontSize: sizes[editorFontSize.value]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.editor.setOptions({
|
||||
enableBasicAutocompletion: true,
|
||||
wrap: this.lineWrap,
|
||||
enableSnippets: true,
|
||||
enableLiveAutocompletion: this.autoComplete
|
||||
watch(autoComplete, () => {
|
||||
if (editor.value) {
|
||||
editor.value.setOptions({
|
||||
enableLiveAutocompletion: autoComplete.value
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.baseCompleter.length)
|
||||
this.setBaseCompleters(this.editor.completers.map(el => Object.assign({}, el)));
|
||||
watch(lineWrap, () => {
|
||||
if (editor.value) {
|
||||
editor.value.setOptions({
|
||||
wrap: lineWrap.value
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.setCustomCompleter();
|
||||
watch(() => props.isSelected, () => {
|
||||
if (props.isSelected) {
|
||||
lastSchema.value = props.schema;
|
||||
editor.value.resize();
|
||||
}
|
||||
});
|
||||
|
||||
this.editor.commands.on('afterExec', e => {
|
||||
if (['insertstring', 'backspace', 'del'].includes(e.command.name)) {
|
||||
if (this.isLastWordATable || e.args === '.') {
|
||||
if (e.args !== ' ') {
|
||||
const table = this.tables.find(t => t.name === this.lastWord.split('.').pop().trim());
|
||||
watch(() => props.height, () => {
|
||||
setTimeout(() => {
|
||||
editor.value.resize();
|
||||
}, 20);
|
||||
});
|
||||
|
||||
if (table) {
|
||||
const params = {
|
||||
uid: this.workspace.uid,
|
||||
schema: this.schema,
|
||||
table: table.name
|
||||
};
|
||||
watch(lastSchema, () => {
|
||||
if (editor.value) {
|
||||
editor.value.completers = baseCompleter.value.map(el => Object.assign({}, el));
|
||||
setCustomCompleter();
|
||||
}
|
||||
});
|
||||
|
||||
Tables.getTableColumns(params).then(res => {
|
||||
if (res.response.length)
|
||||
this.fields = res.response.map(field => field.name);
|
||||
this.editor.completers = [this.fieldsCompleter];
|
||||
this.editor.execCommand('startAutocomplete');
|
||||
}).catch(console.log);
|
||||
}
|
||||
else
|
||||
this.editor.completers = this.customCompleter;
|
||||
lastSchema.value = toRef(props, 'schema').value;
|
||||
|
||||
onMounted(() => {
|
||||
editor.value = ace.edit(`editor-${id.value}`, {
|
||||
mode: `ace/mode/${mode.value}`,
|
||||
theme: `ace/theme/${editorTheme.value}`,
|
||||
value: props.modelValue,
|
||||
fontSize: 14,
|
||||
printMargin: false,
|
||||
readOnly: props.readOnly
|
||||
});
|
||||
|
||||
editor.value.setOptions({
|
||||
enableBasicAutocompletion: true,
|
||||
wrap: lineWrap.value,
|
||||
enableSnippets: true,
|
||||
enableLiveAutocompletion: autoComplete.value
|
||||
});
|
||||
|
||||
if (!baseCompleter.value.length)
|
||||
setBaseCompleters(editor.value.completers.map(el => Object.assign({}, el)));
|
||||
|
||||
setCustomCompleter();
|
||||
|
||||
editor.value.commands.on('afterExec', (e: { args: string; command: { name: string } }) => {
|
||||
if (['insertstring', 'backspace', 'del'].includes(e.command.name)) {
|
||||
if (isLastWordATable.value || e.args === '.') {
|
||||
if (e.args !== ' ') {
|
||||
const table = tables.value.find(t => t.name === lastWord.value.split('.').pop().trim());
|
||||
|
||||
if (table) {
|
||||
const params = {
|
||||
uid: props.workspace.uid,
|
||||
schema: props.schema,
|
||||
table: table.name
|
||||
};
|
||||
|
||||
Tables.getTableColumns(params).then(res => {
|
||||
if (res.response.length)
|
||||
fields.value = res.response.map((field: { name: string }) => field.name);
|
||||
editor.value.completers = [fieldsCompleter.value];
|
||||
editor.value.execCommand('startAutocomplete');
|
||||
}).catch(console.log);
|
||||
}
|
||||
else
|
||||
this.editor.completers = this.customCompleter;
|
||||
editor.value.completers = customCompleter.value;
|
||||
}
|
||||
else
|
||||
this.editor.completers = this.customCompleter;
|
||||
editor.value.completers = customCompleter.value;
|
||||
}
|
||||
});
|
||||
|
||||
this.editor.session.on('change', () => {
|
||||
const content = this.editor.getValue();
|
||||
this.$emit('update:modelValue', content);
|
||||
});
|
||||
|
||||
this.editor.on('guttermousedown', e => {
|
||||
const target = e.domEvent.target;
|
||||
if (target.className.indexOf('ace_gutter-cell') === -1)
|
||||
return;
|
||||
if (e.clientX > 25 + target.getBoundingClientRect().left)
|
||||
return;
|
||||
|
||||
const row = e.getDocumentPosition().row;
|
||||
const breakpoints = e.editor.session.getBreakpoints(row, 0);
|
||||
if (typeof breakpoints[row] === typeof undefined)
|
||||
e.editor.session.setBreakpoint(row);
|
||||
else
|
||||
e.editor.session.clearBreakpoint(row);
|
||||
e.stop();
|
||||
});
|
||||
|
||||
if (this.autoFocus) {
|
||||
setTimeout(() => {
|
||||
this.editor.focus();
|
||||
this.editor.resize();
|
||||
}, 20);
|
||||
editor.value.completers = customCompleter.value;
|
||||
}
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(editor.value.session as any).on('change', () => {
|
||||
const content = editor.value.getValue();
|
||||
emit('update:modelValue', content);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(editor.value as any).on('guttermousedown', (e: any) => {
|
||||
const target = e.domEvent.target;
|
||||
if (target.className.indexOf('ace_gutter-cell') === -1)
|
||||
return;
|
||||
if (e.clientX > 25 + target.getBoundingClientRect().left)
|
||||
return;
|
||||
|
||||
const row = e.getDocumentPosition().row;
|
||||
const breakpoints = e.editor.value.session.getBreakpoints(row, 0);
|
||||
if (typeof breakpoints[row] === typeof undefined)
|
||||
e.editor.value.session.setBreakpoint(row);
|
||||
else
|
||||
e.editor.value.session.clearBreakpoint(row);
|
||||
e.stop();
|
||||
});
|
||||
|
||||
if (props.autoFocus) {
|
||||
setTimeout(() => {
|
||||
this.editor.resize();
|
||||
editor.value.focus();
|
||||
editor.value.resize();
|
||||
}, 20);
|
||||
},
|
||||
methods: {
|
||||
setCustomCompleter () {
|
||||
this.editor.completers.push({
|
||||
getCompletions: (editor, session, pos, prefix, callback) => {
|
||||
const completions = [];
|
||||
[
|
||||
...this.tables,
|
||||
...this.triggers,
|
||||
...this.procedures,
|
||||
...this.functions,
|
||||
...this.schedulers
|
||||
].forEach(el => {
|
||||
completions.push({
|
||||
value: el.name,
|
||||
meta: el.type
|
||||
});
|
||||
});
|
||||
callback(null, completions);
|
||||
}
|
||||
});
|
||||
|
||||
this.customCompleter = this.editor.completers;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setTimeout(() => {
|
||||
editor.value.resize();
|
||||
}, 20);
|
||||
});
|
||||
|
||||
defineExpose({ editor });
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -29,83 +29,66 @@
|
|||
</BaseContextMenu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, Prop, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu.vue';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal.vue';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
|
||||
export default {
|
||||
name: 'SettingBarContext',
|
||||
components: {
|
||||
BaseContextMenu,
|
||||
ConfirmModal
|
||||
},
|
||||
props: {
|
||||
contextEvent: MouseEvent,
|
||||
contextConnection: Object
|
||||
},
|
||||
emits: ['close-context'],
|
||||
setup () {
|
||||
const {
|
||||
getConnectionName,
|
||||
addConnection,
|
||||
deleteConnection
|
||||
} = useConnectionsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const {
|
||||
getConnectionName,
|
||||
addConnection,
|
||||
deleteConnection
|
||||
} = useConnectionsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { selectWorkspace } = workspacesStore;
|
||||
const { selectWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
getConnectionName,
|
||||
addConnection,
|
||||
deleteConnection,
|
||||
selectedWorkspace,
|
||||
selectWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isConfirmModal: false,
|
||||
isEditModal: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
connectionName () {
|
||||
return this.getConnectionName(this.contextConnection.uid);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
confirmDeleteConnection () {
|
||||
if (this.selectedWorkspace === this.contextConnection.uid)
|
||||
this.selectWorkspace();
|
||||
this.deleteConnection(this.contextConnection);
|
||||
this.closeContext();
|
||||
},
|
||||
duplicateConnection () {
|
||||
let connectionCopy = Object.assign({}, this.contextConnection);
|
||||
connectionCopy = {
|
||||
...connectionCopy,
|
||||
uid: uidGen('C'),
|
||||
name: connectionCopy.name ? `${connectionCopy?.name}_copy` : ''
|
||||
};
|
||||
const props = defineProps({
|
||||
contextEvent: MouseEvent,
|
||||
contextConnection: Object as Prop<ConnectionParams>
|
||||
});
|
||||
|
||||
this.addConnection(connectionCopy);
|
||||
this.closeContext();
|
||||
},
|
||||
showConfirmModal () {
|
||||
this.isConfirmModal = true;
|
||||
},
|
||||
hideConfirmModal () {
|
||||
this.isConfirmModal = false;
|
||||
this.closeContext();
|
||||
},
|
||||
closeContext () {
|
||||
this.$emit('close-context');
|
||||
}
|
||||
}
|
||||
const emit = defineEmits(['close-context']);
|
||||
|
||||
const isConfirmModal = ref(false);
|
||||
|
||||
const connectionName = computed(() => getConnectionName(props.contextConnection.uid));
|
||||
|
||||
const confirmDeleteConnection = () => {
|
||||
if (selectedWorkspace.value === props.contextConnection.uid)
|
||||
selectWorkspace(null);
|
||||
deleteConnection(props.contextConnection);
|
||||
closeContext();
|
||||
};
|
||||
|
||||
const duplicateConnection = () => {
|
||||
let connectionCopy = Object.assign({}, props.contextConnection);
|
||||
connectionCopy = {
|
||||
...connectionCopy,
|
||||
uid: uidGen('C'),
|
||||
name: connectionCopy.name ? `${connectionCopy?.name}_copy` : ''
|
||||
};
|
||||
|
||||
addConnection(connectionCopy);
|
||||
closeContext();
|
||||
};
|
||||
|
||||
const showConfirmModal = () => {
|
||||
isConfirmModal.value = true;
|
||||
};
|
||||
|
||||
const hideConfirmModal = () => {
|
||||
isConfirmModal.value = false;
|
||||
closeContext();
|
||||
};
|
||||
|
||||
const closeContext = () => {
|
||||
emit('close-context');
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -29,7 +29,7 @@ const settingsStore = useSettingsStore();
|
|||
const { removeNotification } = notificationsStore;
|
||||
|
||||
const { notifications } = storeToRefs(notificationsStore);
|
||||
const { notificationsTimeout } = storeToRefs(settingsStore) as {notificationsTimeout: Ref<number>};// TODO: temp
|
||||
const { notificationsTimeout } = storeToRefs(settingsStore);
|
||||
|
||||
const timeouts: Ref<{[key: string]: NodeJS.Timeout}> = ref({});
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ const { notes } = storeToRefs(scratchpadStore);
|
|||
const { changeNotes } = scratchpadStore;
|
||||
const { hideScratchpad } = applicationStore;
|
||||
|
||||
const localNotes: Ref<string> = ref(notes.value as string);// TODO: temp
|
||||
const localNotes = ref(notes.value);
|
||||
const debounceTimeout: Ref<NodeJS.Timeout> = ref(null);
|
||||
|
||||
watch(localNotes, () => {
|
||||
|
|
|
@ -86,7 +86,7 @@ const connections = computed({
|
|||
get () {
|
||||
return getConnections.value;
|
||||
},
|
||||
set (value) {
|
||||
set (value: ConnectionParams[]) {
|
||||
updateConnections(value);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -484,246 +484,196 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, Prop, ref, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Draggable from 'vuedraggable';
|
||||
import * as Draggable from 'vuedraggable';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { useWorkspacesStore, WorkspaceTab } from '@/stores/workspaces';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
|
||||
import WorkspaceEmptyState from '@/components/WorkspaceEmptyState';
|
||||
import WorkspaceExploreBar from '@/components/WorkspaceExploreBar';
|
||||
import WorkspaceEditConnectionPanel from '@/components/WorkspaceEditConnectionPanel';
|
||||
import WorkspaceTabQuery from '@/components/WorkspaceTabQuery';
|
||||
import WorkspaceTabTable from '@/components/WorkspaceTabTable';
|
||||
import WorkspaceEmptyState from '@/components/WorkspaceEmptyState.vue';
|
||||
import WorkspaceExploreBar from '@/components/WorkspaceExploreBar.vue';
|
||||
import WorkspaceEditConnectionPanel from '@/components/WorkspaceEditConnectionPanel.vue';
|
||||
import WorkspaceTabQuery from '@/components/WorkspaceTabQuery.vue';
|
||||
import WorkspaceTabTable from '@/components/WorkspaceTabTable.vue';
|
||||
|
||||
import WorkspaceTabNewTable from '@/components/WorkspaceTabNewTable';
|
||||
import WorkspaceTabNewView from '@/components/WorkspaceTabNewView';
|
||||
import WorkspaceTabNewTrigger from '@/components/WorkspaceTabNewTrigger';
|
||||
import WorkspaceTabNewRoutine from '@/components/WorkspaceTabNewRoutine';
|
||||
import WorkspaceTabNewFunction from '@/components/WorkspaceTabNewFunction';
|
||||
import WorkspaceTabNewScheduler from '@/components/WorkspaceTabNewScheduler';
|
||||
import WorkspaceTabNewTriggerFunction from '@/components/WorkspaceTabNewTriggerFunction';
|
||||
import WorkspaceTabNewTable from '@/components/WorkspaceTabNewTable.vue';
|
||||
import WorkspaceTabNewView from '@/components/WorkspaceTabNewView.vue';
|
||||
import WorkspaceTabNewTrigger from '@/components/WorkspaceTabNewTrigger.vue';
|
||||
import WorkspaceTabNewRoutine from '@/components/WorkspaceTabNewRoutine.vue';
|
||||
import WorkspaceTabNewFunction from '@/components/WorkspaceTabNewFunction.vue';
|
||||
import WorkspaceTabNewScheduler from '@/components/WorkspaceTabNewScheduler.vue';
|
||||
import WorkspaceTabNewTriggerFunction from '@/components/WorkspaceTabNewTriggerFunction.vue';
|
||||
|
||||
import WorkspaceTabPropsTable from '@/components/WorkspaceTabPropsTable';
|
||||
import WorkspaceTabPropsView from '@/components/WorkspaceTabPropsView';
|
||||
import WorkspaceTabPropsTrigger from '@/components/WorkspaceTabPropsTrigger';
|
||||
import WorkspaceTabPropsTriggerFunction from '@/components/WorkspaceTabPropsTriggerFunction';
|
||||
import WorkspaceTabPropsRoutine from '@/components/WorkspaceTabPropsRoutine';
|
||||
import WorkspaceTabPropsFunction from '@/components/WorkspaceTabPropsFunction';
|
||||
import WorkspaceTabPropsScheduler from '@/components/WorkspaceTabPropsScheduler';
|
||||
import ModalProcessesList from '@/components/ModalProcessesList';
|
||||
import ModalDiscardChanges from '@/components/ModalDiscardChanges';
|
||||
import WorkspaceTabPropsTable from '@/components/WorkspaceTabPropsTable.vue';
|
||||
import WorkspaceTabPropsView from '@/components/WorkspaceTabPropsView.vue';
|
||||
import WorkspaceTabPropsTrigger from '@/components/WorkspaceTabPropsTrigger.vue';
|
||||
import WorkspaceTabPropsTriggerFunction from '@/components/WorkspaceTabPropsTriggerFunction.vue';
|
||||
import WorkspaceTabPropsRoutine from '@/components/WorkspaceTabPropsRoutine.vue';
|
||||
import WorkspaceTabPropsFunction from '@/components/WorkspaceTabPropsFunction.vue';
|
||||
import WorkspaceTabPropsScheduler from '@/components/WorkspaceTabPropsScheduler.vue';
|
||||
import ModalProcessesList from '@/components/ModalProcessesList.vue';
|
||||
import ModalDiscardChanges from '@/components/ModalDiscardChanges.vue';
|
||||
|
||||
export default {
|
||||
name: 'Workspace',
|
||||
components: {
|
||||
Draggable,
|
||||
WorkspaceEmptyState,
|
||||
WorkspaceExploreBar,
|
||||
WorkspaceEditConnectionPanel,
|
||||
WorkspaceTabQuery,
|
||||
WorkspaceTabTable,
|
||||
WorkspaceTabNewTable,
|
||||
WorkspaceTabPropsTable,
|
||||
WorkspaceTabNewView,
|
||||
WorkspaceTabPropsView,
|
||||
WorkspaceTabNewTrigger,
|
||||
WorkspaceTabPropsTrigger,
|
||||
WorkspaceTabNewTriggerFunction,
|
||||
WorkspaceTabPropsTriggerFunction,
|
||||
WorkspaceTabNewRoutine,
|
||||
WorkspaceTabNewFunction,
|
||||
WorkspaceTabPropsRoutine,
|
||||
WorkspaceTabPropsFunction,
|
||||
WorkspaceTabNewScheduler,
|
||||
WorkspaceTabPropsScheduler,
|
||||
ModalProcessesList,
|
||||
ModalDiscardChanges
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
addWorkspace,
|
||||
connectWorkspace,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTab,
|
||||
updateTabs
|
||||
} = workspacesStore;
|
||||
|
||||
const props = defineProps({
|
||||
connection: Object as Prop<ConnectionParams>
|
||||
});
|
||||
|
||||
const hasWheelEvent = ref(false);
|
||||
const isProcessesModal = ref(false);
|
||||
const unsavedTab = ref(null);
|
||||
const tabWrap = ref(null);
|
||||
|
||||
const workspace = computed(() => getWorkspace(props.connection.uid));
|
||||
|
||||
const draggableTabs = computed<WorkspaceTab[]>({
|
||||
get () {
|
||||
return workspace.value.tabs;
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
setup () {
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
set (val) {
|
||||
updateTabs({ uid: props.connection.uid, tabs: val });
|
||||
}
|
||||
});
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const isSelected = computed(() => {
|
||||
return selectedWorkspace.value === props.connection.uid;
|
||||
});
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
addWorkspace,
|
||||
connectWorkspace,
|
||||
removeConnected,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTab,
|
||||
updateTabs
|
||||
} = workspacesStore;
|
||||
const selectedTab = computed(() => {
|
||||
return workspace.value ? workspace.value.selectedTab : null;
|
||||
});
|
||||
|
||||
return {
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
addWorkspace,
|
||||
connectWorkspace,
|
||||
removeConnected,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTab,
|
||||
updateTabs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
hasWheelEvent: false,
|
||||
isProcessesModal: false,
|
||||
unsavedTab: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
draggableTabs: {
|
||||
get () {
|
||||
return this.workspace.tabs;
|
||||
},
|
||||
set (val) {
|
||||
this.updateTabs({ uid: this.connection.uid, tabs: val });
|
||||
}
|
||||
},
|
||||
isSelected () {
|
||||
return this.selectedWorkspace === this.connection.uid;
|
||||
},
|
||||
isSettingSupported () {
|
||||
if (this.workspace.breadcrumbs.table && this.workspace.customizations.tableSettings) return true;
|
||||
if (this.workspace.breadcrumbs.view && this.workspace.customizations.viewSettings) return true;
|
||||
if (this.workspace.breadcrumbs.trigger && this.workspace.customizations.triggerSettings) return true;
|
||||
if (this.workspace.breadcrumbs.procedure && this.workspace.customizations.routineSettings) return true;
|
||||
if (this.workspace.breadcrumbs.function && this.workspace.customizations.functionSettings) return true;
|
||||
if (this.workspace.breadcrumbs.triggerFunction && this.workspace.customizations.functionSettings) return true;
|
||||
if (this.workspace.breadcrumbs.scheduler && this.workspace.customizations.schedulerSettings) return true;
|
||||
return false;
|
||||
},
|
||||
selectedTab () {
|
||||
return this.workspace ? this.workspace.selectedTab : null;
|
||||
},
|
||||
queryTabs () {
|
||||
return this.workspace ? this.workspace.tabs.filter(tab => tab.type === 'query') : [];
|
||||
},
|
||||
schemaChild () {
|
||||
for (const key in this.workspace.breadcrumbs) {
|
||||
if (key === 'schema') continue;
|
||||
if (this.workspace.breadcrumbs[key]) return this.workspace.breadcrumbs[key];
|
||||
}
|
||||
return false;
|
||||
},
|
||||
hasTools () {
|
||||
if (!this.workspace.customizations) return false;
|
||||
else {
|
||||
return this.workspace.customizations.processesList ||
|
||||
this.workspace.customizations.usersManagement ||
|
||||
this.workspace.customizations.variables;
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
queryTabs: {
|
||||
handler (newVal, oldVal) {
|
||||
if (newVal.length > oldVal.length) {
|
||||
setTimeout(() => {
|
||||
const scroller = this.$refs.tabWrap;
|
||||
if (scroller) scroller.$el.scrollLeft = scroller.$el.scrollWidth;
|
||||
}, 0);
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
await this.addWorkspace(this.connection.uid);
|
||||
const isInitiated = await Connection.checkConnection(this.connection.uid);
|
||||
if (isInitiated)
|
||||
this.connectWorkspace(this.connection);
|
||||
},
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
addQueryTab () {
|
||||
this.newTab({ uid: this.connection.uid, type: 'query' });
|
||||
},
|
||||
getSelectedTab () {
|
||||
return this.workspace.tabs.find(tab => tab.uid === this.selectedTab);
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
const queryTabs = computed(() => {
|
||||
return workspace.value ? workspace.value.tabs.filter(tab => tab.type === 'query') : [];
|
||||
});
|
||||
|
||||
if (!this.isSelected)
|
||||
return;
|
||||
const hasTools = computed(() => {
|
||||
if (!workspace.value.customizations) return false;
|
||||
else {
|
||||
return workspace.value.customizations.processesList ||
|
||||
workspace.value.customizations.usersManagement ||
|
||||
workspace.value.customizations.variables;
|
||||
}
|
||||
});
|
||||
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode === 84 && !e.altKey) { // CTRL|Command + t
|
||||
this.addQueryTab();
|
||||
}
|
||||
watch(queryTabs, (newVal, oldVal) => {
|
||||
if (newVal.length > oldVal.length) {
|
||||
setTimeout(() => {
|
||||
const scroller = tabWrap.value;
|
||||
if (scroller) scroller.$el.scrollLeft = scroller.$el.scrollWidth;
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode === 87 && !e.altKey) { // CTRL|Command + w
|
||||
const currentTab = this.getSelectedTab();
|
||||
if (currentTab)
|
||||
this.closeTab(currentTab);
|
||||
}
|
||||
},
|
||||
openAsPermanentTab (tab) {
|
||||
const permanentTabs = {
|
||||
table: 'data',
|
||||
view: 'data',
|
||||
trigger: 'trigger-props',
|
||||
triggerFunction: 'trigger-function-props',
|
||||
function: 'function-props',
|
||||
routine: 'routine-props',
|
||||
scheduler: 'scheduler-props'
|
||||
};
|
||||
const addQueryTab = () => {
|
||||
newTab({ uid: props.connection.uid, type: 'query' });
|
||||
};
|
||||
|
||||
this.newTab({
|
||||
uid: this.connection.uid,
|
||||
schema: tab.schema,
|
||||
elementName: tab.elementName,
|
||||
type: permanentTabs[tab.elementType],
|
||||
elementType: tab.elementType
|
||||
});
|
||||
},
|
||||
closeTab (tab, force) {
|
||||
this.unsavedTab = null;
|
||||
// if (tab.type === 'query' && this.queryTabs.length === 1) return;
|
||||
if (!force && tab.isChanged) {
|
||||
this.unsavedTab = tab;
|
||||
return;
|
||||
}
|
||||
const getSelectedTab = () => {
|
||||
return workspace.value.tabs.find(tab => tab.uid === selectedTab.value);
|
||||
};
|
||||
|
||||
this.removeTab({ uid: this.connection.uid, tab: tab.uid });
|
||||
},
|
||||
showProcessesModal () {
|
||||
this.isProcessesModal = true;
|
||||
},
|
||||
hideProcessesModal () {
|
||||
this.isProcessesModal = false;
|
||||
},
|
||||
addWheelEvent () {
|
||||
if (!this.hasWheelEvent) {
|
||||
this.$refs.tabWrap.$el.addEventListener('wheel', e => {
|
||||
if (e.deltaY > 0) this.$refs.tabWrap.$el.scrollLeft += 50;
|
||||
else this.$refs.tabWrap.$el.scrollLeft -= 50;
|
||||
});
|
||||
this.hasWheelEvent = true;
|
||||
}
|
||||
},
|
||||
cutText (string) {
|
||||
const limit = 20;
|
||||
const escapedString = string.replace(/\s{2,}/g, ' ');
|
||||
if (escapedString.length > limit)
|
||||
return `${escapedString.substr(0, limit)}...`;
|
||||
return escapedString;
|
||||
}
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (!isSelected.value)
|
||||
return;
|
||||
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 't' && !e.altKey) { // CTRL|Command + t
|
||||
addQueryTab();
|
||||
}
|
||||
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'w' && !e.altKey) { // CTRL|Command + w
|
||||
const currentTab = getSelectedTab();
|
||||
if (currentTab)
|
||||
closeTab(currentTab);
|
||||
}
|
||||
};
|
||||
|
||||
const openAsPermanentTab = (tab: WorkspaceTab) => {
|
||||
const permanentTabs = {
|
||||
table: 'data',
|
||||
view: 'data',
|
||||
trigger: 'trigger-props',
|
||||
triggerFunction: 'trigger-function-props',
|
||||
function: 'function-props',
|
||||
routine: 'routine-props',
|
||||
procedure: 'routine-props',
|
||||
scheduler: 'scheduler-props'
|
||||
} as {[key: string]: string};
|
||||
|
||||
newTab({
|
||||
uid: props.connection.uid,
|
||||
schema: tab.schema,
|
||||
elementName: tab.elementName,
|
||||
type: permanentTabs[tab.elementType],
|
||||
elementType: tab.elementType
|
||||
});
|
||||
};
|
||||
|
||||
const closeTab = (tab: WorkspaceTab, force = false) => {
|
||||
unsavedTab.value = null;
|
||||
// if (tab.type === 'query' && this.queryTabs.length === 1) return;
|
||||
if (!force && tab.isChanged) {
|
||||
unsavedTab.value = tab;
|
||||
return;
|
||||
}
|
||||
|
||||
removeTab({ uid: props.connection.uid, tab: tab.uid });
|
||||
};
|
||||
|
||||
const showProcessesModal = () => {
|
||||
isProcessesModal.value = true;
|
||||
};
|
||||
|
||||
const hideProcessesModal = () => {
|
||||
isProcessesModal.value = false;
|
||||
};
|
||||
|
||||
const addWheelEvent = () => {
|
||||
if (!hasWheelEvent.value) {
|
||||
tabWrap.value.$el.addEventListener('wheel', (e: WheelEvent) => {
|
||||
if (e.deltaY > 0) tabWrap.value.$el.scrollLeft += 50;
|
||||
else tabWrap.value.$el.scrollLeft -= 50;
|
||||
});
|
||||
hasWheelEvent.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const cutText = (string: string) => {
|
||||
const limit = 20;
|
||||
const escapedString = string.replace(/\s{2,}/g, ' ');
|
||||
if (escapedString.length > limit)
|
||||
return `${escapedString.substr(0, limit)}...`;
|
||||
return escapedString;
|
||||
};
|
||||
|
||||
(async () => {
|
||||
window.addEventListener('keydown', onKey);
|
||||
await addWorkspace(props.connection.uid);
|
||||
const isInitiated = await Connection.checkConnection(props.connection.uid);
|
||||
if (isInitiated)
|
||||
connectWorkspace(props.connection);
|
||||
})();
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -8,23 +8,23 @@
|
|||
:class="{'active': selectedTab === 'general'}"
|
||||
@click="selectTab('general')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.general') }}</a>
|
||||
<a class="tab-link">{{ t('word.general') }}</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="customizations.sslConnection"
|
||||
v-if="clientCustomizations.sslConnection"
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssl'}"
|
||||
@click="selectTab('ssl')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.ssl') }}</a>
|
||||
<a class="tab-link">{{ t('word.ssl') }}</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="customizations.sshConnection"
|
||||
v-if="clientCustomizations.sshConnection"
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssh'}"
|
||||
@click="selectTab('ssh')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.sshTunnel') }}</a>
|
||||
<a class="tab-link">{{ t('word.sshTunnel') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@
|
|||
<fieldset class="m-0" :disabled="isBusy">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.connectionName') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.connectionName') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -47,7 +47,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.client') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseSelect
|
||||
|
@ -61,7 +61,7 @@
|
|||
</div>
|
||||
<div v-if="connection.client === 'pg'" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.connectionString') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.connectionString') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -72,9 +72,9 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.hostName') }}/IP</label>
|
||||
<label class="form-label cut-text">{{ t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -84,22 +84,22 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.database') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.database') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="connection.databasePath"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('databasePath')"
|
||||
@change="pathSelection($event, 'databasePath')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.port') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -111,9 +111,9 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.database" class="form-group columns">
|
||||
<div v-if="clientCustomizations.database" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.database') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.database') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -123,9 +123,9 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.user') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -136,9 +136,9 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.password') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -149,32 +149,32 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.connectionSchema" class="form-group columns">
|
||||
<div v-if="clientCustomizations.connectionSchema" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.schema') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.schema') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.schema"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:placeholder="$t('word.all')"
|
||||
:placeholder="t('word.all')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.readOnlyMode" class="form-group columns">
|
||||
<div v-if="clientCustomizations.readOnlyMode" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12" />
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-checkbox form-inline">
|
||||
<input v-model="connection.readonly" type="checkbox"><i class="form-icon" /> {{ $t('message.readOnlyMode') }}
|
||||
<input v-model="connection.readonly" type="checkbox"><i class="form-icon" /> {{ t('message.readOnlyMode') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12" />
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-checkbox form-inline">
|
||||
<input v-model="connection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
|
||||
<input v-model="connection.ask" type="checkbox"><i class="form-icon" /> {{ t('message.askCredentials') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -188,7 +188,7 @@
|
|||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">
|
||||
{{ $t('message.enableSsl') }}
|
||||
{{ t('message.enableSsl') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
|
@ -201,12 +201,12 @@
|
|||
<fieldset class="m-0" :disabled="isBusy || !connection.ssl">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.privateKey') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="connection.key"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('key')"
|
||||
@change="pathSelection($event, 'key')"
|
||||
/>
|
||||
|
@ -214,12 +214,12 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.certificate') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.certificate') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="connection.cert"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('cert')"
|
||||
@change="pathSelection($event, 'cert')"
|
||||
/>
|
||||
|
@ -227,12 +227,12 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.caCertificate') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.caCertificate') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="connection.ca"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('ca')"
|
||||
@change="pathSelection($event, 'ca')"
|
||||
/>
|
||||
|
@ -240,7 +240,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.ciphers') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.ciphers') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -255,7 +255,7 @@
|
|||
<div class="column col-4 col-sm-12" />
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-checkbox form-inline">
|
||||
<input v-model="connection.untrustedConnection" type="checkbox"><i class="form-icon" /> {{ $t('message.untrustedConnection') }}
|
||||
<input v-model="connection.untrustedConnection" type="checkbox"><i class="form-icon" /> {{ t('message.untrustedConnection') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -269,7 +269,7 @@
|
|||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">
|
||||
{{ $t('message.enableSsh') }}
|
||||
{{ t('message.enableSsh') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
|
@ -282,7 +282,7 @@
|
|||
<fieldset class="m-0" :disabled="isBusy || !connection.ssh">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.hostName') }}/IP</label>
|
||||
<label class="form-label cut-text">{{ t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -294,7 +294,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.user') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -306,7 +306,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.password') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -318,7 +318,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.port') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -332,12 +332,12 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.privateKey') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="connection.sshKey"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('sshKey')"
|
||||
@change="pathSelection($event, 'sshKey')"
|
||||
/>
|
||||
|
@ -345,7 +345,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.passphrase') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.passphrase') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -368,7 +368,7 @@
|
|||
@click="startTest"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-lightning-bolt mr-1" />
|
||||
{{ $t('message.testConnection') }}
|
||||
{{ t('message.testConnection') }}
|
||||
</button>
|
||||
<button
|
||||
id="connection-save"
|
||||
|
@ -377,7 +377,7 @@
|
|||
@click="saveConnection"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
{{ $t('word.save') }}
|
||||
{{ t('word.save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -389,188 +389,171 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, Ref, ref, watch } from 'vue';
|
||||
import customizations from 'common/customizations';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials.vue';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput.vue';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceAddConnectionPanel',
|
||||
components: {
|
||||
ModalAskCredentials,
|
||||
BaseUploadInput,
|
||||
BaseSelect
|
||||
},
|
||||
setup () {
|
||||
const { addConnection } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
const { connectWorkspace, selectWorkspace } = workspacesStore;
|
||||
const { addConnection } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
return {
|
||||
addConnection,
|
||||
addNotification,
|
||||
connectWorkspace,
|
||||
selectWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
clients: [
|
||||
{ name: 'MySQL', slug: 'mysql' },
|
||||
{ name: 'MariaDB', slug: 'maria' },
|
||||
{ name: 'PostgreSQL', slug: 'pg' },
|
||||
{ name: 'SQLite', slug: 'sqlite' }
|
||||
],
|
||||
connection: {
|
||||
name: '',
|
||||
client: 'mysql',
|
||||
host: '127.0.0.1',
|
||||
database: null,
|
||||
databasePath: '',
|
||||
port: null,
|
||||
user: null,
|
||||
password: '',
|
||||
ask: false,
|
||||
readonly: false,
|
||||
uid: uidGen('C'),
|
||||
ssl: false,
|
||||
cert: '',
|
||||
key: '',
|
||||
ca: '',
|
||||
ciphers: '',
|
||||
untrustedConnection: false,
|
||||
ssh: false,
|
||||
sshHost: '',
|
||||
sshUser: '',
|
||||
sshPass: '',
|
||||
sshKey: '',
|
||||
sshPort: 22,
|
||||
pgConnString: ''
|
||||
},
|
||||
isConnecting: false,
|
||||
isTesting: false,
|
||||
isAsking: false,
|
||||
selectedTab: 'general'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
customizations () {
|
||||
return customizations[this.connection.client];
|
||||
},
|
||||
isBusy () {
|
||||
return this.isConnecting || this.isTesting;
|
||||
const { connectWorkspace, selectWorkspace } = workspacesStore;
|
||||
|
||||
const clients = ref([
|
||||
{ name: 'MySQL', slug: 'mysql' },
|
||||
{ name: 'MariaDB', slug: 'maria' },
|
||||
{ name: 'PostgreSQL', slug: 'pg' },
|
||||
{ name: 'SQLite', slug: 'sqlite' }
|
||||
]);
|
||||
|
||||
const connection = ref({
|
||||
name: '',
|
||||
client: 'mysql',
|
||||
host: '127.0.0.1',
|
||||
database: null,
|
||||
databasePath: '',
|
||||
port: null,
|
||||
user: null,
|
||||
password: '',
|
||||
ask: false,
|
||||
readonly: false,
|
||||
uid: uidGen('C'),
|
||||
ssl: false,
|
||||
cert: '',
|
||||
key: '',
|
||||
ca: '',
|
||||
ciphers: '',
|
||||
untrustedConnection: false,
|
||||
ssh: false,
|
||||
sshHost: '',
|
||||
sshUser: '',
|
||||
sshPass: '',
|
||||
sshKey: '',
|
||||
sshPort: 22,
|
||||
pgConnString: ''
|
||||
}) as Ref<ConnectionParams & { pgConnString: string }>;
|
||||
|
||||
const firstInput: Ref<HTMLInputElement> = ref(null);
|
||||
const isConnecting = ref(false);
|
||||
const isTesting = ref(false);
|
||||
const isAsking = ref(false);
|
||||
const selectedTab = ref('general');
|
||||
|
||||
const clientCustomizations = computed(() => {
|
||||
return customizations[connection.value.client];
|
||||
});
|
||||
|
||||
const isBusy = computed(() => {
|
||||
return isConnecting.value || isTesting.value;
|
||||
});
|
||||
|
||||
watch(() => connection.value.client, () => {
|
||||
connection.value.user = clientCustomizations.value.defaultUser;
|
||||
connection.value.port = clientCustomizations.value.defaultPort;
|
||||
connection.value.database = clientCustomizations.value.defaultDatabase;
|
||||
});
|
||||
|
||||
const setDefaults = () => {
|
||||
connection.value.user = clientCustomizations.value.defaultUser;
|
||||
connection.value.port = clientCustomizations.value.defaultPort;
|
||||
connection.value.database = clientCustomizations.value.defaultDatabase;
|
||||
};
|
||||
|
||||
const startTest = async () => {
|
||||
isTesting.value = true;
|
||||
|
||||
if (connection.value.ask)
|
||||
isAsking.value = true;
|
||||
else {
|
||||
try {
|
||||
const res = await Connection.makeTest(connection);
|
||||
if (res.status === 'error')
|
||||
addNotification({ status: 'error', message: res.response.message || res.response.toString() });
|
||||
else
|
||||
addNotification({ status: 'success', message: t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'connection.client' () {
|
||||
this.connection.user = this.customizations.defaultUser;
|
||||
this.connection.port = this.customizations.defaultPort;
|
||||
this.connection.database = this.customizations.defaultDatabase;
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.setDefaults();
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.$refs.firstInput) this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
methods: {
|
||||
setDefaults () {
|
||||
this.connection.user = this.customizations.defaultUser;
|
||||
this.connection.port = this.customizations.defaultPort;
|
||||
this.connection.database = this.customizations.defaultDatabase;
|
||||
},
|
||||
async startConnection () {
|
||||
await this.saveConnection();
|
||||
this.isConnecting = true;
|
||||
|
||||
if (this.connection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
await this.connectWorkspace(this.connection);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
},
|
||||
async startTest () {
|
||||
this.isTesting = true;
|
||||
|
||||
if (this.connection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
try {
|
||||
const res = await Connection.makeTest(this.connection);
|
||||
if (res.status === 'error')
|
||||
this.addNotification({ status: 'error', message: res.response.message || res.response.toString() });
|
||||
else
|
||||
this.addNotification({ status: 'success', message: this.$t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
}
|
||||
},
|
||||
async continueTest (credentials) { // if "Ask for credentials" is true
|
||||
this.isAsking = false;
|
||||
const params = Object.assign({}, this.connection, credentials);
|
||||
try {
|
||||
if (this.isConnecting) {
|
||||
const params = Object.assign({}, this.connection, credentials);
|
||||
await this.connectWorkspace(params);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
else {
|
||||
const res = await Connection.makeTest(params);
|
||||
if (res.status === 'error')
|
||||
this.addNotification({ status: 'error', message: res.response.message || res.response.toString() });
|
||||
else
|
||||
this.addNotification({ status: 'success', message: this.$t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
},
|
||||
saveConnection () {
|
||||
this.selectWorkspace(this.connection.uid);
|
||||
return this.addConnection(this.connection);
|
||||
},
|
||||
closeAsking () {
|
||||
this.isTesting = false;
|
||||
this.isAsking = false;
|
||||
},
|
||||
selectTab (tab) {
|
||||
this.selectedTab = tab;
|
||||
},
|
||||
toggleSsl () {
|
||||
this.connection.ssl = !this.connection.ssl;
|
||||
},
|
||||
toggleSsh () {
|
||||
this.connection.ssh = !this.connection.ssh;
|
||||
},
|
||||
pathSelection (event, name) {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
this.connection[name] = files[0].path;
|
||||
},
|
||||
pathClear (name) {
|
||||
this.connection[name] = '';
|
||||
}
|
||||
isTesting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const continueTest = async (credentials: { user: string; password: string }) => { // if "Ask for credentials" is true
|
||||
isAsking.value = false;
|
||||
const params = Object.assign({}, connection.value, credentials);
|
||||
|
||||
try {
|
||||
if (isConnecting.value) {
|
||||
await connectWorkspace(params);
|
||||
isConnecting.value = false;
|
||||
}
|
||||
else {
|
||||
const res = await Connection.makeTest(params);
|
||||
if (res.status === 'error')
|
||||
addNotification({ status: 'error', message: res.response.message || res.response.toString() });
|
||||
else
|
||||
addNotification({ status: 'success', message: t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
isTesting.value = false;
|
||||
};
|
||||
|
||||
const saveConnection = () => {
|
||||
selectWorkspace(connection.value.uid);
|
||||
return addConnection(connection.value);
|
||||
};
|
||||
|
||||
const closeAsking = () => {
|
||||
isTesting.value = false;
|
||||
isAsking.value = false;
|
||||
};
|
||||
|
||||
const selectTab = (tab: string) => {
|
||||
selectedTab.value = tab;
|
||||
};
|
||||
|
||||
const toggleSsl = () => {
|
||||
connection.value.ssl = !connection.value.ssl;
|
||||
};
|
||||
|
||||
const toggleSsh = () => {
|
||||
connection.value.ssh = !connection.value.ssh;
|
||||
};
|
||||
|
||||
const pathSelection = (event: Event & {target: {files: {path: string}[]}}, name: keyof ConnectionParams) => {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
(connection.value as unknown as {[key: string]: string})[name] = files[0].path as string;
|
||||
};
|
||||
|
||||
const pathClear = (name: keyof ConnectionParams) => {
|
||||
(connection.value as unknown as {[key: string]: string})[name] = '';
|
||||
};
|
||||
|
||||
setDefaults();
|
||||
|
||||
setTimeout(() => {
|
||||
if (firstInput.value) firstInput.value.focus();
|
||||
}, 20);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -8,23 +8,23 @@
|
|||
:class="{'active': selectedTab === 'general'}"
|
||||
@click="selectTab('general')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.general') }}</a>
|
||||
<a class="tab-link">{{ t('word.general') }}</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="customizations.sslConnection"
|
||||
v-if="clientCustomizations.sslConnection"
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssl'}"
|
||||
@click="selectTab('ssl')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.ssl') }}</a>
|
||||
<a class="tab-link">{{ t('word.ssl') }}</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="customizations.sshConnection"
|
||||
v-if="clientCustomizations.sshConnection"
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssh'}"
|
||||
@click="selectTab('ssh')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.sshTunnel') }}</a>
|
||||
<a class="tab-link">{{ t('word.sshTunnel') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@
|
|||
<fieldset class="m-0" :disabled="isBusy">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.connectionName') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.connectionName') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -47,7 +47,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.client') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseSelect
|
||||
|
@ -63,7 +63,7 @@
|
|||
</div>
|
||||
<div v-if="connection.client === 'pg'" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.connectionString') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.connectionString') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -74,9 +74,9 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.hostName') }}/IP</label>
|
||||
<label class="form-label cut-text">{{ t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -86,22 +86,22 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.database') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.database') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="localConnection.databasePath"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('databasePath')"
|
||||
@change="pathSelection($event, 'databasePath')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.port') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -113,9 +113,9 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.database" class="form-group columns">
|
||||
<div v-if="clientCustomizations.database" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.database') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.database') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -125,9 +125,9 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.user') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -138,9 +138,9 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.password') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -151,32 +151,32 @@
|
|||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.connectionSchema" class="form-group columns">
|
||||
<div v-if="clientCustomizations.connectionSchema" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.schema') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.schema') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.schema"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:placeholder="$t('word.all')"
|
||||
:placeholder="t('word.all')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.readOnlyMode" class="form-group columns">
|
||||
<div v-if="clientCustomizations.readOnlyMode" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12" />
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-checkbox form-inline">
|
||||
<input v-model="localConnection.readonly" type="checkbox"><i class="form-icon" /> {{ $t('message.readOnlyMode') }}
|
||||
<input v-model="localConnection.readonly" type="checkbox"><i class="form-icon" /> {{ t('message.readOnlyMode') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!customizations.fileConnection" class="form-group columns">
|
||||
<div v-if="!clientCustomizations.fileConnection" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12" />
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-checkbox form-inline">
|
||||
<input v-model="localConnection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
|
||||
<input v-model="localConnection.ask" type="checkbox"><i class="form-icon" /> {{ t('message.askCredentials') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -190,7 +190,7 @@
|
|||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">
|
||||
{{ $t('message.enableSsl') }}
|
||||
{{ t('message.enableSsl') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
|
@ -203,12 +203,12 @@
|
|||
<fieldset class="m-0" :disabled="isBusy || !localConnection.ssl">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.privateKey') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="localConnection.key"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('key')"
|
||||
@change="pathSelection($event, 'key')"
|
||||
/>
|
||||
|
@ -216,12 +216,12 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.certificate') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.certificate') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="localConnection.cert"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('cert')"
|
||||
@change="pathSelection($event, 'cert')"
|
||||
/>
|
||||
|
@ -229,12 +229,12 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.caCertificate') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.caCertificate') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="localConnection.ca"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('ca')"
|
||||
@change="pathSelection($event, 'ca')"
|
||||
/>
|
||||
|
@ -242,7 +242,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.ciphers') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.ciphers') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -263,7 +263,7 @@
|
|||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">
|
||||
{{ $t('message.enableSsh') }}
|
||||
{{ t('message.enableSsh') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
|
@ -276,7 +276,7 @@
|
|||
<fieldset class="m-0" :disabled="isBusy || !localConnection.ssh">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.hostName') }}/IP</label>
|
||||
<label class="form-label cut-text">{{ t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -288,7 +288,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.user') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -300,7 +300,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.password') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -312,7 +312,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.port') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -326,12 +326,12 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.privateKey') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:model-value="localConnection.sshKey"
|
||||
:message="$t('word.browse')"
|
||||
:message="t('word.browse')"
|
||||
@clear="pathClear('sshKey')"
|
||||
@change="pathSelection($event, 'sshKey')"
|
||||
/>
|
||||
|
@ -339,7 +339,7 @@
|
|||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label cut-text">{{ $t('word.passphrase') }}</label>
|
||||
<label class="form-label cut-text">{{ t('word.passphrase') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
|
@ -362,7 +362,7 @@
|
|||
@click="startTest"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-lightning-bolt mr-1" />
|
||||
{{ $t('message.testConnection') }}
|
||||
{{ t('message.testConnection') }}
|
||||
</button>
|
||||
<button
|
||||
id="connection-save"
|
||||
|
@ -371,7 +371,7 @@
|
|||
@click="saveConnection"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
{{ $t('word.save') }}
|
||||
{{ t('word.save') }}
|
||||
</button>
|
||||
<button
|
||||
id="connection-connect"
|
||||
|
@ -381,7 +381,7 @@
|
|||
@click="startConnection"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-connection mr-1" />
|
||||
{{ $t('word.connect') }}
|
||||
{{ t('word.connect') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -393,154 +393,150 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed, Prop, Ref, ref, watch } from 'vue';
|
||||
import customizations from 'common/customizations';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials.vue';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput.vue';
|
||||
import BaseSelect from '@/components/BaseSelect.vue';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceEditConnectionPanel',
|
||||
components: {
|
||||
ModalAskCredentials,
|
||||
BaseUploadInput,
|
||||
BaseSelect
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
setup () {
|
||||
const { editConnection } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const { connectWorkspace } = useWorkspacesStore();
|
||||
const { t } = useI18n();
|
||||
|
||||
return {
|
||||
editConnection,
|
||||
addNotification,
|
||||
connectWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
clients: [
|
||||
{ name: 'MySQL', slug: 'mysql' },
|
||||
{ name: 'MariaDB', slug: 'maria' },
|
||||
{ name: 'PostgreSQL', slug: 'pg' },
|
||||
{ name: 'SQLite', slug: 'sqlite' }
|
||||
],
|
||||
isConnecting: false,
|
||||
isTesting: false,
|
||||
isAsking: false,
|
||||
localConnection: null,
|
||||
selectedTab: 'general'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
customizations () {
|
||||
return customizations[this.localConnection.client];
|
||||
},
|
||||
isBusy () {
|
||||
return this.isConnecting || this.isTesting;
|
||||
},
|
||||
hasChanges () {
|
||||
return JSON.stringify(this.connection) !== JSON.stringify(this.localConnection);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
connection () {
|
||||
this.localConnection = JSON.parse(JSON.stringify(this.connection));
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.localConnection = JSON.parse(JSON.stringify(this.connection));
|
||||
},
|
||||
methods: {
|
||||
async startConnection () {
|
||||
await this.saveConnection();
|
||||
this.isConnecting = true;
|
||||
const props = defineProps({
|
||||
connection: Object as Prop<ConnectionParams>
|
||||
});
|
||||
|
||||
if (this.localConnection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
await this.connectWorkspace(this.localConnection);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
},
|
||||
async startTest () {
|
||||
this.isTesting = true;
|
||||
const { editConnection } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const { connectWorkspace } = useWorkspacesStore();
|
||||
|
||||
if (this.localConnection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
try {
|
||||
const res = await Connection.makeTest(this.localConnection);
|
||||
if (res.status === 'error')
|
||||
this.addNotification({ status: 'error', message: res.response.message || res.response.toString() });
|
||||
else
|
||||
this.addNotification({ status: 'success', message: this.$t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
const clients = ref([
|
||||
{ name: 'MySQL', slug: 'mysql' },
|
||||
{ name: 'MariaDB', slug: 'maria' },
|
||||
{ name: 'PostgreSQL', slug: 'pg' },
|
||||
{ name: 'SQLite', slug: 'sqlite' }
|
||||
]);
|
||||
|
||||
this.isTesting = false;
|
||||
}
|
||||
},
|
||||
async continueTest (credentials) { // if "Ask for credentials" is true
|
||||
this.isAsking = false;
|
||||
const params = Object.assign({}, this.localConnection, credentials);
|
||||
try {
|
||||
if (this.isConnecting) {
|
||||
const params = Object.assign({}, this.connection, credentials);
|
||||
await this.connectWorkspace(params);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
else {
|
||||
const res = await Connection.makeTest(params);
|
||||
if (res.status === 'error')
|
||||
this.addNotification({ status: 'error', message: res.response.message || res.response.toString() });
|
||||
else
|
||||
this.addNotification({ status: 'success', message: this.$t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
const firstInput: Ref<HTMLInputElement> = ref(null);
|
||||
const localConnection: Ref<ConnectionParams & { pgConnString: string }> = ref(null);
|
||||
const isConnecting = ref(false);
|
||||
const isTesting = ref(false);
|
||||
const isAsking = ref(false);
|
||||
const selectedTab = ref('general');
|
||||
|
||||
this.isTesting = false;
|
||||
},
|
||||
saveConnection () {
|
||||
return this.editConnection(this.localConnection);
|
||||
},
|
||||
closeAsking () {
|
||||
this.isTesting = false;
|
||||
this.isAsking = false;
|
||||
this.isConnecting = false;
|
||||
},
|
||||
selectTab (tab) {
|
||||
this.selectedTab = tab;
|
||||
},
|
||||
toggleSsl () {
|
||||
this.localConnection.ssl = !this.localConnection.ssl;
|
||||
},
|
||||
toggleSsh () {
|
||||
this.localConnection.ssh = !this.localConnection.ssh;
|
||||
},
|
||||
pathSelection (event, name) {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
const clientCustomizations = computed(() => {
|
||||
return customizations[localConnection.value.client];
|
||||
});
|
||||
|
||||
this.localConnection[name] = files[0].path;
|
||||
},
|
||||
pathClear (name) {
|
||||
this.localConnection[name] = '';
|
||||
}
|
||||
const isBusy = computed(() => {
|
||||
return isConnecting.value || isTesting.value;
|
||||
});
|
||||
|
||||
const hasChanges = computed(() => {
|
||||
return JSON.stringify(props.connection) !== JSON.stringify(localConnection.value);
|
||||
});
|
||||
|
||||
watch(() => props.connection, () => {
|
||||
localConnection.value = JSON.parse(JSON.stringify(props.connection));
|
||||
});
|
||||
|
||||
const startConnection = async () => {
|
||||
await saveConnection();
|
||||
isConnecting.value = true;
|
||||
|
||||
if (localConnection.value.ask)
|
||||
isAsking.value = true;
|
||||
else {
|
||||
await connectWorkspace(localConnection.value);
|
||||
isConnecting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const startTest = async () => {
|
||||
isTesting.value = true;
|
||||
|
||||
if (localConnection.value.ask)
|
||||
isAsking.value = true;
|
||||
else {
|
||||
try {
|
||||
const res = await Connection.makeTest(localConnection.value);
|
||||
if (res.status === 'error')
|
||||
addNotification({ status: 'error', message: res.response.message || res.response.toString() });
|
||||
else
|
||||
addNotification({ status: 'success', message: t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
isTesting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const continueTest = async (credentials: {user: string; password: string }) => { // if "Ask for credentials" is true
|
||||
isAsking.value = false;
|
||||
const params = Object.assign({}, localConnection.value, credentials);
|
||||
try {
|
||||
if (isConnecting.value) {
|
||||
const params = Object.assign({}, props.connection, credentials);
|
||||
await connectWorkspace(params);
|
||||
isConnecting.value = false;
|
||||
}
|
||||
else {
|
||||
const res = await Connection.makeTest(params);
|
||||
if (res.status === 'error')
|
||||
addNotification({ status: 'error', message: res.response.message || res.response.toString() });
|
||||
else
|
||||
addNotification({ status: 'success', message: t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
isTesting.value = false;
|
||||
};
|
||||
|
||||
const saveConnection = () => {
|
||||
return editConnection(localConnection.value);
|
||||
};
|
||||
|
||||
const closeAsking = () => {
|
||||
isTesting.value = false;
|
||||
isAsking.value = false;
|
||||
isConnecting.value = false;
|
||||
};
|
||||
|
||||
const selectTab = (tab: string) => {
|
||||
selectedTab.value = tab;
|
||||
};
|
||||
|
||||
const toggleSsl = () => {
|
||||
localConnection.value.ssl = !localConnection.value.ssl;
|
||||
};
|
||||
|
||||
const toggleSsh = () => {
|
||||
localConnection.value.ssh = !localConnection.value.ssh;
|
||||
};
|
||||
|
||||
const pathSelection = (event: Event & {target: {files: {path: string}[]}}, name: keyof ConnectionParams) => {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
(localConnection.value as unknown as {[key: string]: string})[name] = files[0].path;
|
||||
};
|
||||
|
||||
const pathClear = (name: keyof ConnectionParams) => {
|
||||
(localConnection.value as unknown as {[key: string]: string})[name] = '';
|
||||
};
|
||||
|
||||
localConnection.value = JSON.parse(JSON.stringify(props.connection));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -1,61 +1,48 @@
|
|||
<template>
|
||||
<div class="column col-12 empty">
|
||||
<div class="empty-icon">
|
||||
<img
|
||||
v-if="applicationTheme === 'dark'"
|
||||
src="../images/logo-dark.svg"
|
||||
width="200"
|
||||
>
|
||||
<img
|
||||
v-if="applicationTheme === 'light'"
|
||||
src="../images/logo-light.svg"
|
||||
width="200"
|
||||
>
|
||||
<img :src="logos[applicationTheme]" width="200">
|
||||
</div>
|
||||
<p class="h6 empty-subtitle">
|
||||
{{ $t('message.noOpenTabs') }}
|
||||
{{ t('message.noOpenTabs') }}
|
||||
</p>
|
||||
<div class="empty-action">
|
||||
<button class="btn btn-gray d-flex" @click="$emit('new-tab')">
|
||||
<button class="btn btn-gray d-flex" @click="emit('new-tab')">
|
||||
<i class="mdi mdi-24px mdi-tab-plus mr-2" />
|
||||
{{ $t('message.openNewTab') }}
|
||||
{{ t('message.openNewTab') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { storeToRefs } from 'pinia';
|
||||
export default {
|
||||
name: 'WorkspaceEmptyState',
|
||||
emits: ['new-tab'],
|
||||
setup () {
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { applicationTheme } = storeToRefs(settingsStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const { t } = useI18n();
|
||||
|
||||
const { getWorkspace, changeBreadcrumbs } = workspacesStore;
|
||||
const emit = defineEmits(['new-tab']);
|
||||
|
||||
return {
|
||||
applicationTheme,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
changeBreadcrumbs
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.changeBreadcrumbs({ schema: this.workspace.breadcrumbs.schema });
|
||||
}
|
||||
const logos = {
|
||||
light: require('../images/logo-light.svg') as string,
|
||||
dark: require('../images/logo-dark.svg') as string
|
||||
};
|
||||
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { applicationTheme } = storeToRefs(settingsStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, changeBreadcrumbs } = workspacesStore;
|
||||
|
||||
const workspace = computed(() => {
|
||||
return getWorkspace(selectedWorkspace.value);
|
||||
});
|
||||
|
||||
changeBreadcrumbs({ schema: workspace.value.breadcrumbs.schema });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workspace-explorebar-body" @click="$refs.explorebar.focus()">
|
||||
<div class="workspace-explorebar-body" @click="explorebar.focus()">
|
||||
<WorkspaceExploreBarSchema
|
||||
v-for="db of workspace.structure"
|
||||
:key="db.name"
|
||||
|
@ -115,7 +115,8 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { Component, computed, onMounted, Ref, ref, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
|
@ -125,428 +126,291 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import Views from '@/ipc-api/Views';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
import Schedulers from '@/ipc-api/Schedulers';
|
||||
|
||||
import WorkspaceExploreBarSchema from '@/components/WorkspaceExploreBarSchema';
|
||||
import DatabaseContext from '@/components/WorkspaceExploreBarSchemaContext';
|
||||
import TableContext from '@/components/WorkspaceExploreBarTableContext';
|
||||
import MiscContext from '@/components/WorkspaceExploreBarMiscContext';
|
||||
import MiscFolderContext from '@/components/WorkspaceExploreBarMiscFolderContext';
|
||||
import ModalNewSchema from '@/components/ModalNewSchema';
|
||||
import WorkspaceExploreBarSchema from '@/components/WorkspaceExploreBarSchema.vue';
|
||||
import DatabaseContext from '@/components/WorkspaceExploreBarSchemaContext.vue';
|
||||
import TableContext from '@/components/WorkspaceExploreBarTableContext.vue';
|
||||
import MiscContext from '@/components/WorkspaceExploreBarMiscContext.vue';
|
||||
import MiscFolderContext from '@/components/WorkspaceExploreBarMiscFolderContext.vue';
|
||||
import ModalNewSchema from '@/components/ModalNewSchema.vue';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceExploreBar',
|
||||
components: {
|
||||
WorkspaceExploreBarSchema,
|
||||
DatabaseContext,
|
||||
TableContext,
|
||||
MiscContext,
|
||||
MiscFolderContext,
|
||||
ModalNewSchema
|
||||
},
|
||||
props: {
|
||||
connection: Object,
|
||||
isSelected: Boolean
|
||||
},
|
||||
setup () {
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const props = defineProps({
|
||||
connection: Object,
|
||||
isSelected: Boolean
|
||||
});
|
||||
|
||||
const { explorebarSize } = storeToRefs(settingsStore);
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { changeExplorebarSize } = settingsStore;
|
||||
const {
|
||||
getWorkspace,
|
||||
removeConnected: disconnectWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTabs,
|
||||
setSearchTerm,
|
||||
addLoadingElement,
|
||||
removeLoadingElement
|
||||
} = workspacesStore;
|
||||
const { explorebarSize } = storeToRefs(settingsStore);
|
||||
|
||||
return {
|
||||
getConnectionName,
|
||||
addNotification,
|
||||
explorebarSize,
|
||||
changeExplorebarSize,
|
||||
getWorkspace,
|
||||
disconnectWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTabs,
|
||||
setSearchTerm,
|
||||
addLoadingElement,
|
||||
removeLoadingElement
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isRefreshing: false,
|
||||
const { changeExplorebarSize } = settingsStore;
|
||||
const {
|
||||
getWorkspace,
|
||||
removeConnected: disconnectWorkspace,
|
||||
refreshStructure,
|
||||
newTab,
|
||||
removeTabs,
|
||||
setSearchTerm,
|
||||
addLoadingElement,
|
||||
removeLoadingElement
|
||||
} = workspacesStore;
|
||||
|
||||
isNewDBModal: false,
|
||||
isNewViewModal: false,
|
||||
isNewTriggerModal: false,
|
||||
isNewRoutineModal: false,
|
||||
isNewFunctionModal: false,
|
||||
isNewTriggerFunctionModal: false,
|
||||
isNewSchedulerModal: false,
|
||||
const searchInput: Ref<HTMLInputElement> = ref(null);
|
||||
const explorebar: Ref<HTMLInputElement> = ref(null);
|
||||
const resizer: Ref<HTMLInputElement> = ref(null);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const schema: Ref<Component & { selectSchema: (name: string) => void; $refs: any }[]> = ref(null);
|
||||
const isRefreshing = ref(false);
|
||||
const isNewDBModal = ref(false);
|
||||
const localWidth = ref(null);
|
||||
const explorebarWidthInterval = ref(null);
|
||||
const searchTermInterval = ref(null);
|
||||
const isDatabaseContext = ref(false);
|
||||
const isTableContext = ref(false);
|
||||
const isMiscContext = ref(false);
|
||||
const isMiscFolderContext = ref(false);
|
||||
const databaseContextEvent = ref(null);
|
||||
const tableContextEvent = ref(null);
|
||||
const miscContextEvent = ref(null);
|
||||
const selectedSchema = ref('');
|
||||
const selectedTable = ref(null);
|
||||
const selectedMisc = ref(null);
|
||||
const searchTerm = ref('');
|
||||
|
||||
localWidth: null,
|
||||
explorebarWidthInterval: null,
|
||||
searchTermInterval: null,
|
||||
isDatabaseContext: false,
|
||||
isTableContext: false,
|
||||
isMiscContext: false,
|
||||
isMiscFolderContext: false,
|
||||
const workspace = computed(() => {
|
||||
return getWorkspace(props.connection.uid);
|
||||
});
|
||||
|
||||
databaseContextEvent: null,
|
||||
tableContextEvent: null,
|
||||
miscContextEvent: null,
|
||||
const connectionName = computed(() => {
|
||||
return getConnectionName(props.connection.uid);
|
||||
});
|
||||
|
||||
selectedSchema: '',
|
||||
selectedTable: null,
|
||||
selectedMisc: null,
|
||||
searchTerm: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
connectionName () {
|
||||
return this.getConnectionName(this.connection.uid);
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
localWidth (val) {
|
||||
clearTimeout(this.explorebarWidthInterval);
|
||||
const customizations = computed(() => {
|
||||
return workspace.value.customizations;
|
||||
});
|
||||
|
||||
this.explorebarWidthInterval = setTimeout(() => {
|
||||
this.changeExplorebarSize(val);
|
||||
}, 500);
|
||||
},
|
||||
isSelected (val) {
|
||||
if (val) this.localWidth = this.explorebarSize;
|
||||
},
|
||||
searchTerm () {
|
||||
clearTimeout(this.searchTermInterval);
|
||||
watch(localWidth, (val: number) => {
|
||||
clearTimeout(explorebarWidthInterval.value);
|
||||
|
||||
this.searchTermInterval = setTimeout(() => {
|
||||
this.setSearchTerm(this.searchTerm);
|
||||
}, 200);
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.localWidth = this.explorebarSize;
|
||||
},
|
||||
mounted () {
|
||||
const resizer = this.$refs.resizer;
|
||||
explorebarWidthInterval.value = setTimeout(() => {
|
||||
changeExplorebarSize(val);
|
||||
}, 500);
|
||||
});
|
||||
|
||||
resizer.addEventListener('mousedown', e => {
|
||||
e.preventDefault();
|
||||
watch(() => props.isSelected, (val: boolean) => {
|
||||
if (val) localWidth.value = explorebarSize.value;
|
||||
});
|
||||
|
||||
window.addEventListener('mousemove', this.resize);
|
||||
window.addEventListener('mouseup', this.stopResize);
|
||||
});
|
||||
watch(searchTerm, () => {
|
||||
clearTimeout(searchTermInterval.value);
|
||||
|
||||
if (this.workspace.structure.length === 1) { // Auto-open if juust one schema
|
||||
this.$refs.schema[0].selectSchema(this.workspace.structure[0].name);
|
||||
this.$refs.schema[0].$refs.schemaAccordion.open = true;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async refresh () {
|
||||
if (!this.isRefreshing) {
|
||||
this.isRefreshing = true;
|
||||
await this.refreshStructure(this.connection.uid);
|
||||
this.isRefreshing = false;
|
||||
}
|
||||
},
|
||||
explorebarSearch (e) {
|
||||
if (e.code === 'Backspace') {
|
||||
e.preventDefault();
|
||||
if (this.searchTerm.length)
|
||||
this.searchTerm = this.searchTerm.slice(0, -1);
|
||||
else
|
||||
return;
|
||||
}
|
||||
else if (e.key.length > 1)// Prevent non-alphanumerics
|
||||
return;
|
||||
searchTermInterval.value = setTimeout(() => {
|
||||
setSearchTerm(searchTerm.value);
|
||||
}, 200);
|
||||
});
|
||||
|
||||
this.$refs.searchInput.focus();
|
||||
},
|
||||
resize (e) {
|
||||
const el = this.$refs.explorebar;
|
||||
let explorebarWidth = e.pageX - el.getBoundingClientRect().left;
|
||||
if (explorebarWidth > 500) explorebarWidth = 500;
|
||||
if (explorebarWidth < 150) explorebarWidth = 150;
|
||||
this.localWidth = explorebarWidth;
|
||||
},
|
||||
stopResize () {
|
||||
window.removeEventListener('mousemove', this.resize);
|
||||
},
|
||||
showNewDBModal () {
|
||||
this.isNewDBModal = true;
|
||||
},
|
||||
hideNewDBModal () {
|
||||
this.isNewDBModal = false;
|
||||
},
|
||||
openCreateElementTab (element) {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
localWidth.value = explorebarSize.value;
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: '',
|
||||
elementType: element,
|
||||
type: `new-${element}`
|
||||
});
|
||||
},
|
||||
openSchemaContext (payload) {
|
||||
this.selectedSchema = payload.schema;
|
||||
this.databaseContextEvent = payload.event;
|
||||
this.isDatabaseContext = true;
|
||||
},
|
||||
closeDatabaseContext () {
|
||||
this.isDatabaseContext = false;
|
||||
},
|
||||
openTableContext (payload) {
|
||||
this.selectedTable = payload.table;
|
||||
this.selectedSchema = payload.schema;
|
||||
this.tableContextEvent = payload.event;
|
||||
this.isTableContext = true;
|
||||
},
|
||||
closeTableContext () {
|
||||
this.isTableContext = false;
|
||||
},
|
||||
openMiscContext (payload) {
|
||||
this.selectedMisc = payload.misc;
|
||||
this.selectedSchema = payload.schema;
|
||||
this.miscContextEvent = payload.event;
|
||||
this.isMiscContext = true;
|
||||
},
|
||||
openMiscFolderContext (payload) {
|
||||
this.selectedMisc = payload.type;
|
||||
this.selectedSchema = payload.schema;
|
||||
this.miscContextEvent = payload.event;
|
||||
this.isMiscFolderContext = true;
|
||||
},
|
||||
closeMiscContext () {
|
||||
this.isMiscContext = false;
|
||||
},
|
||||
closeMiscFolderContext () {
|
||||
this.isMiscFolderContext = false;
|
||||
},
|
||||
showCreateTriggerModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewTriggerModal = true;
|
||||
},
|
||||
hideCreateTriggerModal () {
|
||||
this.isNewTriggerModal = false;
|
||||
},
|
||||
showCreateRoutineModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewRoutineModal = true;
|
||||
},
|
||||
hideCreateRoutineModal () {
|
||||
this.isNewRoutineModal = false;
|
||||
},
|
||||
showCreateFunctionModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewFunctionModal = true;
|
||||
},
|
||||
hideCreateFunctionModal () {
|
||||
this.isNewFunctionModal = false;
|
||||
},
|
||||
showCreateTriggerFunctionModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewTriggerFunctionModal = true;
|
||||
},
|
||||
hideCreateTriggerFunctionModal () {
|
||||
this.isNewTriggerFunctionModal = false;
|
||||
},
|
||||
showCreateSchedulerModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewSchedulerModal = true;
|
||||
},
|
||||
hideCreateSchedulerModal () {
|
||||
this.isNewSchedulerModal = false;
|
||||
},
|
||||
async deleteTable (payload) {
|
||||
this.closeTableContext();
|
||||
onMounted(() => {
|
||||
resizer.value.addEventListener('mousedown', (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
this.addLoadingElement({
|
||||
name: payload.table.name,
|
||||
schema: payload.schema,
|
||||
type: 'table'
|
||||
});
|
||||
window.addEventListener('mousemove', resize);
|
||||
window.addEventListener('mouseup', stopResize);
|
||||
});
|
||||
|
||||
try {
|
||||
let res;
|
||||
if (workspace.value.structure.length === 1) { // Auto-open if juust one schema
|
||||
schema.value[0].selectSchema(workspace.value.structure[0].name);
|
||||
schema.value[0].$refs.schemaAccordion.open = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (payload.table.type === 'table') {
|
||||
res = await Tables.dropTable({
|
||||
uid: this.connection.uid,
|
||||
table: payload.table.name,
|
||||
schema: payload.schema
|
||||
});
|
||||
}
|
||||
else if (payload.table.type === 'view') {
|
||||
res = await Views.dropView({
|
||||
uid: this.connection.uid,
|
||||
view: payload.table.name,
|
||||
schema: payload.schema
|
||||
});
|
||||
}
|
||||
|
||||
const { status, response } = res;
|
||||
|
||||
if (status === 'success') {
|
||||
this.refresh();
|
||||
|
||||
this.removeTabs({
|
||||
uid: this.connection.uid,
|
||||
elementName: payload.table.name,
|
||||
elementType: payload.table.type,
|
||||
schema: payload.schema
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.removeLoadingElement({
|
||||
name: payload.table.name,
|
||||
schema: payload.schema,
|
||||
type: 'table'
|
||||
});
|
||||
},
|
||||
async duplicateTable (payload) {
|
||||
this.closeTableContext();
|
||||
|
||||
this.addLoadingElement({
|
||||
name: payload.table.name,
|
||||
schema: payload.schema,
|
||||
type: 'table'
|
||||
});
|
||||
|
||||
try {
|
||||
const { status, response } = await Tables.duplicateTable({
|
||||
uid: this.connection.uid,
|
||||
table: payload.table.name,
|
||||
schema: payload.schema
|
||||
});
|
||||
|
||||
if (status === 'success')
|
||||
this.refresh();
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.removeLoadingElement({
|
||||
name: payload.table.name,
|
||||
schema: payload.schema,
|
||||
type: 'table'
|
||||
});
|
||||
},
|
||||
async openCreateFunctionEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
const { status, response } = await Functions.createFunction(params);
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, function: payload.name });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'function',
|
||||
type: 'function-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
},
|
||||
async openCreateTriggerFunctionEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
const { status, response } = await Functions.createTriggerFunction(params);
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, triggerFunction: payload.name });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'triggerFunction',
|
||||
type: 'trigger-function-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
},
|
||||
async openCreateSchedulerEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
const { status, response } = await Schedulers.createScheduler(params);
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, scheduler: payload.name });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'scheduler',
|
||||
type: 'scheduler-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
const refresh = async () => {
|
||||
if (!isRefreshing.value) {
|
||||
isRefreshing.value = true;
|
||||
await refreshStructure(props.connection.uid);
|
||||
isRefreshing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const explorebarSearch = (e: KeyboardEvent) => {
|
||||
if (e.code === 'Backspace') {
|
||||
e.preventDefault();
|
||||
if (searchTerm.value.length)
|
||||
searchTerm.value = searchTerm.value.slice(0, -1);
|
||||
else
|
||||
return;
|
||||
}
|
||||
else if (e.key.length > 1)// Prevent non-alphanumerics
|
||||
return;
|
||||
|
||||
searchInput.value.focus();
|
||||
};
|
||||
|
||||
const resize = (e: MouseEvent) => {
|
||||
const el = explorebar.value;
|
||||
let explorebarWidth = e.pageX - el.getBoundingClientRect().left;
|
||||
if (explorebarWidth > 500) explorebarWidth = 500;
|
||||
if (explorebarWidth < 150) explorebarWidth = 150;
|
||||
localWidth.value = explorebarWidth;
|
||||
};
|
||||
|
||||
const stopResize = () => {
|
||||
window.removeEventListener('mousemove', resize);
|
||||
};
|
||||
|
||||
const showNewDBModal = () => {
|
||||
isNewDBModal.value = true;
|
||||
};
|
||||
|
||||
const hideNewDBModal = () => {
|
||||
isNewDBModal.value = false;
|
||||
};
|
||||
|
||||
const openCreateElementTab = (element: string) => {
|
||||
closeDatabaseContext();
|
||||
closeMiscFolderContext();
|
||||
|
||||
newTab({
|
||||
uid: workspace.value.uid,
|
||||
schema: selectedSchema.value,
|
||||
elementName: '',
|
||||
elementType: element,
|
||||
type: `new-${element}`
|
||||
});
|
||||
};
|
||||
|
||||
const openSchemaContext = (payload: { schema: string; event: PointerEvent }) => {
|
||||
selectedSchema.value = payload.schema;
|
||||
databaseContextEvent.value = payload.event;
|
||||
isDatabaseContext.value = true;
|
||||
};
|
||||
|
||||
const closeDatabaseContext = () => {
|
||||
isDatabaseContext.value = false;
|
||||
};
|
||||
|
||||
const openTableContext = (payload: { schema: string; table: string; event: PointerEvent }) => {
|
||||
selectedTable.value = payload.table;
|
||||
selectedSchema.value = payload.schema;
|
||||
tableContextEvent.value = payload.event;
|
||||
isTableContext.value = true;
|
||||
};
|
||||
|
||||
const closeTableContext = () => {
|
||||
isTableContext.value = false;
|
||||
};
|
||||
|
||||
const openMiscContext = (payload: { schema: string; misc: string; event: PointerEvent }) => {
|
||||
selectedMisc.value = payload.misc;
|
||||
selectedSchema.value = payload.schema;
|
||||
miscContextEvent.value = payload.event;
|
||||
isMiscContext.value = true;
|
||||
};
|
||||
|
||||
const openMiscFolderContext = (payload: { schema: string; type: string; event: PointerEvent }) => {
|
||||
selectedMisc.value = payload.type;
|
||||
selectedSchema.value = payload.schema;
|
||||
miscContextEvent.value = payload.event;
|
||||
isMiscFolderContext.value = true;
|
||||
};
|
||||
|
||||
const closeMiscContext = () => {
|
||||
isMiscContext.value = false;
|
||||
};
|
||||
|
||||
const closeMiscFolderContext = () => {
|
||||
isMiscFolderContext.value = false;
|
||||
};
|
||||
|
||||
const deleteTable = async (payload: { schema: string; table: { name: string; type: string }; event: PointerEvent }) => {
|
||||
closeTableContext();
|
||||
|
||||
addLoadingElement({
|
||||
name: payload.table.name,
|
||||
schema: payload.schema,
|
||||
type: 'table'
|
||||
});
|
||||
|
||||
try {
|
||||
let res;
|
||||
|
||||
if (payload.table.type === 'table') {
|
||||
res = await Tables.dropTable({
|
||||
uid: props.connection.uid,
|
||||
table: payload.table.name,
|
||||
schema: payload.schema
|
||||
});
|
||||
}
|
||||
else if (payload.table.type === 'view') {
|
||||
res = await Views.dropView({
|
||||
uid: props.connection.uid,
|
||||
view: payload.table.name,
|
||||
schema: payload.schema
|
||||
});
|
||||
}
|
||||
|
||||
const { status, response } = res;
|
||||
|
||||
if (status === 'success') {
|
||||
refresh();
|
||||
|
||||
removeTabs({
|
||||
uid: props.connection.uid as string,
|
||||
elementName: payload.table.name as string,
|
||||
elementType: payload.table.type,
|
||||
schema: payload.schema as string
|
||||
});
|
||||
}
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
removeLoadingElement({
|
||||
name: payload.table.name,
|
||||
schema: payload.schema,
|
||||
type: 'table'
|
||||
});
|
||||
};
|
||||
|
||||
const duplicateTable = async (payload: { schema: string; table: { name: string }; event: PointerEvent }) => {
|
||||
closeTableContext();
|
||||
|
||||
addLoadingElement({
|
||||
name: payload.table.name,
|
||||
schema: payload.schema,
|
||||
type: 'table'
|
||||
});
|
||||
|
||||
try {
|
||||
const { status, response } = await Tables.duplicateTable({
|
||||
uid: props.connection.uid,
|
||||
table: payload.table.name,
|
||||
schema: payload.schema
|
||||
});
|
||||
|
||||
if (status === 'success')
|
||||
refresh();
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
removeLoadingElement({
|
||||
name: payload.table.name,
|
||||
schema: payload.schema,
|
||||
type: 'table'
|
||||
});
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -248,6 +248,8 @@ import { useWorkspacesStore } from '@/stores/workspaces';
|
|||
import { formatBytes } from 'common/libs/formatBytes';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
// TODO: expose selectSchema & schemaAccordion
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceExploreBarSchema',
|
||||
props: {
|
||||
|
|
|
@ -132,7 +132,7 @@
|
|||
<input
|
||||
v-model="localRow.unsigned"
|
||||
type="checkbox"
|
||||
:disabled="!fieldType.unsigned"
|
||||
:disabled="!fieldType?.unsigned"
|
||||
>
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
|
|
|
@ -151,7 +151,7 @@
|
|||
|
||||
<BaseSelect
|
||||
v-model="selectedSchema"
|
||||
:options="[{value: 'null', label: $t('message.noSchema')}, ...databaseSchemas.map(el => ({label: el, value: el}))]"
|
||||
:options="[{value: null, label: $t('message.noSchema')}, ...databaseSchemas.map(el => ({label: el, value: el}))]"
|
||||
class="form-select select-sm text-bold"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -29,7 +29,7 @@ createApp(App)
|
|||
.mount('#app');
|
||||
|
||||
const { locale } = useSettingsStore();
|
||||
i18n.global.locale = locale as string;// TODO: temp
|
||||
i18n.global.locale = locale;
|
||||
|
||||
// IPC exceptions
|
||||
ipcRenderer.on('unhandled-exception', (event, error) => {
|
||||
|
|
|
@ -34,7 +34,7 @@ export const useApplicationStore = defineStore('application', {
|
|||
setLoadingStatus (payload: boolean) {
|
||||
this.isLoading = payload;
|
||||
},
|
||||
setBaseCompleters (payload: boolean) {
|
||||
setBaseCompleters (payload: Ace.Completer[]) {
|
||||
this.baseCompleter = payload;
|
||||
},
|
||||
// Modals
|
||||
|
|
|
@ -60,7 +60,7 @@ export const useConnectionsStore = defineStore('connections', {
|
|||
this.selected_conection = {};
|
||||
persistentStore.set('connections', this.connections);
|
||||
},
|
||||
updateConnections (connections: ConnectionParams) {
|
||||
updateConnections (connections: ConnectionParams[]) {
|
||||
this.connections = connections;
|
||||
persistentStore.set('connections', this.connections);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ const defaultAppTheme = isDarkTheme.matches ? 'dark' : 'light';
|
|||
const defaultEditorTheme = isDarkTheme.matches ? 'twilight' : 'sqlserver';
|
||||
|
||||
export type EditorFontSize = 'small' | 'medium' | 'large';
|
||||
export type ApplicationTheme = 'light' | 'dark';
|
||||
|
||||
export const useSettingsStore = defineStore('settings', {
|
||||
state: () => ({
|
||||
|
@ -17,7 +18,7 @@ export const useSettingsStore = defineStore('settings', {
|
|||
dataTabLimit: persistentStore.get('data_tab_limit', 1000) as number,
|
||||
autoComplete: persistentStore.get('auto_complete', true) as boolean,
|
||||
lineWrap: persistentStore.get('line_wrap', true) as boolean,
|
||||
applicationTheme: persistentStore.get('application_theme', defaultAppTheme) as string,
|
||||
applicationTheme: persistentStore.get('application_theme', defaultAppTheme) as ApplicationTheme,
|
||||
editorTheme: persistentStore.get('editor_theme', defaultEditorTheme) as string,
|
||||
editorFontSize: persistentStore.get('editor_font_size', 'medium') as EditorFontSize,
|
||||
restoreTabs: persistentStore.get('restore_tabs', true) as boolean,
|
||||
|
|
|
@ -25,16 +25,16 @@ import { Customizations } from 'common/interfaces/customizations';
|
|||
export interface WorkspaceTab {
|
||||
uid: string;
|
||||
tab?: string;
|
||||
index: number;
|
||||
selected: boolean;
|
||||
type: string;
|
||||
index?: number;
|
||||
selected?: boolean;
|
||||
type?: string;
|
||||
schema?: string;
|
||||
elementName?: string;
|
||||
elementNewName?: string;
|
||||
elementType?: string;
|
||||
isChanged?: boolean;
|
||||
content?: string;
|
||||
autorun: boolean;
|
||||
autorun?: boolean;
|
||||
}
|
||||
|
||||
export interface WorkspaceStructure {
|
||||
|
@ -70,7 +70,7 @@ export interface Workspace {
|
|||
variables: { name: string; value: string }[];
|
||||
collations: CollationInfos[];
|
||||
users: { host: string; name: string; password: string }[];
|
||||
breadcrumbs: Breadcrumb[];
|
||||
breadcrumbs: Breadcrumb;
|
||||
loadingElements: { name: string; schema: string; type: string }[];
|
||||
loadedSchemas: Set<string>;
|
||||
dataTypes?: { [key: string]: TypesGroup[] };
|
||||
|
@ -171,18 +171,18 @@ export const useWorkspacesStore = defineStore('workspaces', {
|
|||
switch (connection.client) {
|
||||
case 'mysql':
|
||||
case 'maria':
|
||||
dataTypes = require('common/data-types/mysql');
|
||||
indexTypes = require('common/index-types/mysql');
|
||||
dataTypes = require('common/data-types/mysql').default;
|
||||
indexTypes = require('common/index-types/mysql').default;
|
||||
clientCustomizations = customizations.mysql;
|
||||
break;
|
||||
case 'pg':
|
||||
dataTypes = require('common/data-types/postgresql');
|
||||
indexTypes = require('common/index-types/postgresql');
|
||||
dataTypes = require('common/data-types/postgresql').default;
|
||||
indexTypes = require('common/index-types/postgresql').default;
|
||||
clientCustomizations = customizations.pg;
|
||||
break;
|
||||
case 'sqlite':
|
||||
dataTypes = require('common/data-types/sqlite');
|
||||
indexTypes = require('common/index-types/sqlite');
|
||||
dataTypes = require('common/data-types/sqlite').default;
|
||||
indexTypes = require('common/index-types/sqlite').default;
|
||||
clientCustomizations = customizations.sqlite;
|
||||
break;
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ export const useWorkspacesStore = defineStore('workspaces', {
|
|||
variables: [],
|
||||
collations: [],
|
||||
users: [],
|
||||
breadcrumbs: [],
|
||||
breadcrumbs: {},
|
||||
loadingElements: [],
|
||||
loadedSchemas: new Set()
|
||||
};
|
||||
|
@ -684,7 +684,7 @@ export const useWorkspacesStore = defineStore('workspaces', {
|
|||
: workspace
|
||||
);
|
||||
},
|
||||
updateTabs ({ uid, tabs }: {uid: string; tabs: string[]}) {
|
||||
updateTabs ({ uid, tabs }: {uid: string; tabs: WorkspaceTab[]}) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? { ...workspace, tabs }
|
||||
: workspace
|
||||
|
|
Loading…
Reference in New Issue