feat: modal with all connections

This commit is contained in:
Fabio Di Stasio 2022-07-02 15:30:36 +02:00
parent 36e98e0742
commit a703dcc53e
10 changed files with 394 additions and 105 deletions

94
package-lock.json generated
View File

@ -15,6 +15,7 @@
"@mdi/font": "~6.1.95", "@mdi/font": "~6.1.95",
"@turf/helpers": "~6.5.0", "@turf/helpers": "~6.5.0",
"@vscode/vscode-languagedetection": "~1.0.21", "@vscode/vscode-languagedetection": "~1.0.21",
"@vueuse/core": "~8.7.5",
"ace-builds": "~1.4.13", "ace-builds": "~1.4.13",
"better-sqlite3": "~7.5.0", "better-sqlite3": "~7.5.0",
"electron-log": "~4.4.1", "electron-log": "~4.4.1",
@ -2872,6 +2873,11 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"node_modules/@types/web-bluetooth": {
"version": "0.0.14",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
"integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
},
"node_modules/@types/yargs": { "node_modules/@types/yargs": {
"version": "16.0.4", "version": "16.0.4",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
@ -3205,6 +3211,63 @@
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz",
"integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg=="
}, },
"node_modules/@vueuse/core": {
"version": "8.7.5",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.7.5.tgz",
"integrity": "sha512-tqgzeZGoZcXzoit4kOGLWJibDMLp0vdm6ZO41SSUQhkhtrPhAg6dbIEPiahhUu6sZAmSYvVrZgEr5aKD51nrLA==",
"dependencies": {
"@types/web-bluetooth": "^0.0.14",
"@vueuse/metadata": "8.7.5",
"@vueuse/shared": "8.7.5",
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.1.0",
"vue": "^2.6.0 || ^3.2.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"vue": {
"optional": true
}
}
},
"node_modules/@vueuse/core/node_modules/@vueuse/shared": {
"version": "8.7.5",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.7.5.tgz",
"integrity": "sha512-THXPvMBFmg6Gf6AwRn/EdTh2mhqwjGsB2Yfp374LNQSQVKRHtnJ0I42bsZTn7nuEliBxqUrGQm/lN6qUHmhJLw==",
"dependencies": {
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.1.0",
"vue": "^2.6.0 || ^3.2.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
},
"vue": {
"optional": true
}
}
},
"node_modules/@vueuse/metadata": {
"version": "8.7.5",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.7.5.tgz",
"integrity": "sha512-emJZKRQSaEnVqmlu39NpNp8iaW+bPC2kWykWoWOZMSlO/0QVEmO/rt8A5VhOEJTKLX3vwTevqbiRy9WJRwVOQg==",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@webassemblyjs/ast": { "node_modules/@webassemblyjs/ast": {
"version": "1.11.1", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@ -19790,6 +19853,11 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"@types/web-bluetooth": {
"version": "0.0.14",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.14.tgz",
"integrity": "sha512-5d2RhCard1nQUC3aHcq/gHzWYO6K0WJmAbjO7mQJgCQKtZpgXxv1rOM6O/dBDhDYYVutk1sciOgNSe+5YyfM8A=="
},
"@types/yargs": { "@types/yargs": {
"version": "16.0.4", "version": "16.0.4",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
@ -20029,6 +20097,32 @@
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.33.tgz",
"integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg=="
}, },
"@vueuse/core": {
"version": "8.7.5",
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-8.7.5.tgz",
"integrity": "sha512-tqgzeZGoZcXzoit4kOGLWJibDMLp0vdm6ZO41SSUQhkhtrPhAg6dbIEPiahhUu6sZAmSYvVrZgEr5aKD51nrLA==",
"requires": {
"@types/web-bluetooth": "^0.0.14",
"@vueuse/metadata": "8.7.5",
"@vueuse/shared": "8.7.5",
"vue-demi": "*"
},
"dependencies": {
"@vueuse/shared": {
"version": "8.7.5",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-8.7.5.tgz",
"integrity": "sha512-THXPvMBFmg6Gf6AwRn/EdTh2mhqwjGsB2Yfp374LNQSQVKRHtnJ0I42bsZTn7nuEliBxqUrGQm/lN6qUHmhJLw==",
"requires": {
"vue-demi": "*"
}
}
}
},
"@vueuse/metadata": {
"version": "8.7.5",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-8.7.5.tgz",
"integrity": "sha512-emJZKRQSaEnVqmlu39NpNp8iaW+bPC2kWykWoWOZMSlO/0QVEmO/rt8A5VhOEJTKLX3vwTevqbiRy9WJRwVOQg=="
},
"@webassemblyjs/ast": { "@webassemblyjs/ast": {
"version": "1.11.1", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",

View File

@ -120,6 +120,7 @@
"@mdi/font": "~6.1.95", "@mdi/font": "~6.1.95",
"@turf/helpers": "~6.5.0", "@turf/helpers": "~6.5.0",
"@vscode/vscode-languagedetection": "~1.0.21", "@vscode/vscode-languagedetection": "~1.0.21",
"@vueuse/core": "~8.7.5",
"ace-builds": "~1.4.13", "ace-builds": "~1.4.13",
"better-sqlite3": "~7.5.0", "better-sqlite3": "~7.5.0",
"electron-log": "~4.4.1", "electron-log": "~4.4.1",

View File

@ -2,7 +2,7 @@
<div id="wrapper" :class="[`theme-${applicationTheme}`, !disableBlur || 'no-blur']"> <div id="wrapper" :class="[`theme-${applicationTheme}`, !disableBlur || 'no-blur']">
<TheTitleBar /> <TheTitleBar />
<div id="window-content"> <div id="window-content">
<TheSettingBar /> <TheSettingBar @show-connections-modal="isAllConnectionsModal = true" />
<div id="main-content" class="container"> <div id="main-content" class="container">
<div class="columns col-gapless"> <div class="columns col-gapless">
<Workspace <Workspace
@ -21,13 +21,15 @@
<BaseTextEditor class="d-none" value="" /> <BaseTextEditor class="d-none" value="" />
</div> </div>
</div> </div>
<ModalAllConnections v-if="isAllConnectionsModal" @close="isAllConnectionsModal = false" />
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineAsyncComponent } from 'vue'; import { defineAsyncComponent, onBeforeUnmount, onMounted, Ref, ref } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
import { useI18n } from 'vue-i18n';
import { Menu, getCurrentWindow } from '@electron/remote'; import { Menu, getCurrentWindow } from '@electron/remote';
import { useApplicationStore } from '@/stores/application'; import { useApplicationStore } from '@/stores/application';
import { useConnectionsStore } from '@/stores/connections'; import { useConnectionsStore } from '@/stores/connections';
@ -35,98 +37,88 @@ import { useSettingsStore } from '@/stores/settings';
import { useWorkspacesStore } from '@/stores/workspaces'; import { useWorkspacesStore } from '@/stores/workspaces';
import TheSettingBar from '@/components/TheSettingBar.vue'; import TheSettingBar from '@/components/TheSettingBar.vue';
export default { const { t } = useI18n();
name: 'App',
components: {
TheTitleBar: defineAsyncComponent(() => import(/* webpackChunkName: "TheTitleBar" */'@/components/TheTitleBar.vue')),
TheSettingBar,
TheFooter: defineAsyncComponent(() => import(/* webpackChunkName: "TheFooter" */'@/components/TheFooter.vue')),
TheNotificationsBoard: defineAsyncComponent(() => import(/* webpackChunkName: "TheNotificationsBoard" */'@/components/TheNotificationsBoard.vue')),
Workspace: defineAsyncComponent(() => import(/* webpackChunkName: "Workspace" */'@/components/Workspace.vue')),
WorkspaceAddConnectionPanel: defineAsyncComponent(() => import(/* webpackChunkName: "WorkspaceAddConnectionPanel" */'@/components/WorkspaceAddConnectionPanel.vue')),
ModalSettings: defineAsyncComponent(() => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings.vue')),
TheScratchpad: defineAsyncComponent(() => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad.vue')),
BaseTextEditor: defineAsyncComponent(() => import(/* webpackChunkName: "BaseTextEditor" */'@/components/BaseTextEditor.vue'))
},
setup () {
const applicationStore = useApplicationStore();
const connectionsStore = useConnectionsStore();
const settingsStore = useSettingsStore();
const workspacesStore = useWorkspacesStore();
const { const TheTitleBar = defineAsyncComponent(() => import(/* webpackChunkName: "TheTitleBar" */'@/components/TheTitleBar.vue'));
isLoading, const TheFooter = defineAsyncComponent(() => import(/* webpackChunkName: "TheFooter" */'@/components/TheFooter.vue'));
isSettingModal, const TheNotificationsBoard = defineAsyncComponent(() => import(/* webpackChunkName: "TheNotificationsBoard" */'@/components/TheNotificationsBoard.vue'));
isScratchpad const Workspace = defineAsyncComponent(() => import(/* webpackChunkName: "Workspace" */'@/components/Workspace.vue'));
} = storeToRefs(applicationStore); const WorkspaceAddConnectionPanel = defineAsyncComponent(() => import(/* webpackChunkName: "WorkspaceAddConnectionPanel" */'@/components/WorkspaceAddConnectionPanel.vue'));
const { connections } = storeToRefs(connectionsStore); const ModalSettings = defineAsyncComponent(() => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings.vue'));
const { applicationTheme, disableBlur } = storeToRefs(settingsStore); const ModalAllConnections = defineAsyncComponent(() => import(/* webpackChunkName: "ModalAllConnections" */'@/components/ModalAllConnections.vue'));
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore); const TheScratchpad = defineAsyncComponent(() => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad.vue'));
const BaseTextEditor = defineAsyncComponent(() => import(/* webpackChunkName: "BaseTextEditor" */'@/components/BaseTextEditor.vue'));
const { checkVersionUpdate } = applicationStore; const applicationStore = useApplicationStore();
const { changeApplicationTheme } = settingsStore; const connectionsStore = useConnectionsStore();
const settingsStore = useSettingsStore();
const workspacesStore = useWorkspacesStore();
document.addEventListener('DOMContentLoaded', () => { const {
setTimeout(() => { isSettingModal,
changeApplicationTheme(applicationTheme.value);// Forces persistentStore to save on file and mail process isScratchpad
}, 1000); } = storeToRefs(applicationStore);
}); const { connections } = storeToRefs(connectionsStore);
const { applicationTheme, disableBlur } = storeToRefs(settingsStore);
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
return { const { checkVersionUpdate } = applicationStore;
isLoading, const { changeApplicationTheme } = settingsStore;
isSettingModal,
isScratchpad,
checkVersionUpdate,
changeApplicationTheme,
connections,
applicationTheme,
disableBlur,
selectedWorkspace
};
},
mounted () {
ipcRenderer.send('check-for-updates');
this.checkVersionUpdate();
const InputMenu = Menu.buildFromTemplate([ const isAllConnectionsModal: Ref<boolean> = ref(false);
{
label: this.$t('word.cut'), document.addEventListener('DOMContentLoaded', () => {
role: 'cut' setTimeout(() => {
}, changeApplicationTheme(applicationTheme.value);// Forces persistentStore to save on file and mail process
{ }, 1000);
label: this.$t('word.copy'), });
role: 'copy'
}, onMounted(() => {
{ ipcRenderer.send('check-for-updates');
label: this.$t('word.paste'), checkVersionUpdate();
role: 'paste'
}, const InputMenu = Menu.buildFromTemplate([
{ {
type: 'separator' label: t('word.cut'),
}, role: 'cut'
{ },
label: this.$t('message.selectAll'), {
role: 'selectAll' label: t('word.copy'),
role: 'copy'
},
{
label: t('word.paste'),
role: 'paste'
},
{
type: 'separator'
},
{
label: t('message.selectAll'),
role: 'selectAll'
}
]);
document.body.addEventListener('contextmenu', (e) => {
e.preventDefault();
e.stopPropagation();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let node: any = e.target;
while (node) {
if (node.nodeName.match(/^(input|textarea)$/i) || node.isContentEditable) {
InputMenu.popup({ window: getCurrentWindow() });
break;
} }
]); node = node.parentNode;
}
});
});
document.body.addEventListener('contextmenu', (e) => { onBeforeUnmount(() => {
e.preventDefault(); window.removeEventListener('keydown', console.log);
e.stopPropagation(); });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let node: any = e.target;
while (node) {
if (node.nodeName.match(/^(input|textarea)$/i) || node.isContentEditable) {
InputMenu.popup({ window: getCurrentWindow() });
break;
}
node = node.parentNode;
}
});
}
};
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -0,0 +1,171 @@
<template>
<Teleport to="#window-content">
<div class="modal active">
<a class="modal-overlay" @click.stop="closeModal" />
<div ref="trapRef" class="modal-container p-0 pb-4">
<div class="modal-header pl-2">
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-apps mr-1" />
<span class="cut-text">{{ $t('message.allConnections') }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
</div>
<div class="modal-body py-0">
<div class="columns">
<div
v-for="connection in connections"
:key="connection.uid"
class="column col-md-6 col-lg-4 col-3 p-3"
>
<div class="panel">
<div class="panel-header text-center">
<figure class="avatar avatar-lg">
<i class="settingbar-element-icon dbi" :class="[`dbi-${connection.client}`]" />
</figure>
<div class="panel-title h6 mt-10">
{{ getConnectionName(connection.uid) }}
</div>
<div class="panel-subtitle">
{{ connection.client }}
</div>
</div>
<div class="panel-body text-center">
<div v-if="connection.databasePath">
<div class="pl-1 text-break">
<span class="text-bold">PATH:</span> {{ connection.databasePath }}
</div>
</div>
<div v-else>
<div class="pl-1 text-break">
<span class="text-bold">HOST:</span> {{ connection.host }}
</div>
</div>
<div v-if="connection.user">
<div class="pl-1 text-break">
<span class="text-bold">USER:</span> {{ connection.user }}
</div>
</div>
<div v-if="connection.schema">
<div class="pl-1 text-break">
<span class="text-bold">SCHEMA:</span> {{ connection.schema }}
</div>
</div>
<div v-if="connection.database">
<div class="pl-1 text-break">
<span class="text-bold">DATABASE:</span> {{ connection.database }}
</div>
</div>
</div>
<div class="panel-footer text-center py-0">
<div v-if="connection.ssl" class="chip bg-success mt-2">
SSL
</div>
<div v-if="connection.ssh" class="chip bg-success mt-2">
SSH
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</Teleport>
</template>
<script setup lang="ts">
import { useFocusTrap } from '@/composables/useFocusTrap';
import { useConnectionsStore } from '@/stores/connections';
import { useWorkspacesStore } from '@/stores/workspaces';
import { storeToRefs } from 'pinia';
const connectionsStore = useConnectionsStore();
const workspacesStore = useWorkspacesStore();
const { connections } = storeToRefs(connectionsStore);
const { getConnectionName } = connectionsStore;
const { getWorkspace } = workspacesStore;
const { trapRef } = useFocusTrap();
const emit = defineEmits(['close']);
const closeModal = () => emit('close');
const onKey = (e:KeyboardEvent) => {
e.stopPropagation();
if (e.key === 'Escape')
closeModal();
};
const getStatusBadge = (uid: string) => {
if (getWorkspace(uid)) {
const status = getWorkspace(uid).connectionStatus;
switch (status) {
case 'connected':
return 'badge badge-connected';
case 'connecting':
return 'badge badge-connecting';
case 'failed':
return 'badge badge-failed';
default:
return '';
}
}
};
window.addEventListener('keydown', onKey, { capture: true });
</script>
<style lang="scss" scoped>
.vscroll {
height: 1000px;
overflow: auto;
overflow-anchor: none;
}
.column-resizable {
&:hover,
&:active {
resize: horizontal;
overflow: hidden;
}
}
.table-column-title {
display: flex;
align-items: center;
}
.sort-icon {
font-size: 0.7rem;
line-height: 1;
margin-left: 0.2rem;
}
.result-tabs {
background: transparent !important;
margin: 0;
}
.modal {
align-items: flex-start;
.modal-container {
max-width: 75vw;
margin-top: 10vh;
.modal-body {
height: 80vh;
}
}
}
.processes-toolbar {
display: flex;
justify-content: space-between;
}
</style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div id="settingbar"> <div id="settingbar">
<div class="settingbar-top-elements"> <div ref="sidebarConnections" class="settingbar-top-elements">
<SettingBarContext <SettingBarContext
v-if="isContext" v-if="isContext"
:context-event="contextEvent" :context-event="contextEvent"
@ -24,7 +24,7 @@
@mouseover.self="tooltipPosition" @mouseover.self="tooltipPosition"
> >
<i class="settingbar-element-icon dbi" :class="[`dbi-${element.client}`, getStatusBadge(element.uid), (pinnedConnections.has(element.uid) ? 'settingbar-element-pin' : false)]" /> <i class="settingbar-element-icon dbi" :class="[`dbi-${element.client}`, getStatusBadge(element.uid), (pinnedConnections.has(element.uid) ? 'settingbar-element-pin' : false)]" />
<span v-if="!isDragging" class="ex-tooltip-content">{{ getConnectionName(element.uid) }}</span> <span v-if="!isDragging && !isScrolling" class="ex-tooltip-content">{{ getConnectionName(element.uid) }}</span>
</li> </li>
</template> </template>
</Draggable> </Draggable>
@ -41,7 +41,21 @@
@mouseover.self="tooltipPosition" @mouseover.self="tooltipPosition"
> >
<i class="settingbar-element-icon dbi" :class="[`dbi-${connection.client}`, getStatusBadge(connection.uid)]" /> <i class="settingbar-element-icon dbi" :class="[`dbi-${connection.client}`, getStatusBadge(connection.uid)]" />
<span v-if="!isDragging" class="ex-tooltip-content">{{ getConnectionName(connection.uid) }}</span> <span v-if="!isDragging && !isScrolling" class="ex-tooltip-content">{{ getConnectionName(connection.uid) }}</span>
</li>
</ul>
</div>
<div class="settingbar-middle-elements">
<ul class="settingbar-elements">
<li
v-if="isScrollable"
class="settingbar-element btn btn-link ex-tooltip"
@click="emit('show-connections-modal')"
@mouseover.self="tooltipPosition"
>
<i class="settingbar-element-icon mdi mdi-24px mdi-dots-horizontal text-light" />
<span class="ex-tooltip-content">{{ $t('message.allConnections') }}</span>
</li> </li>
<li <li
class="settingbar-element btn btn-link ex-tooltip" class="settingbar-element btn btn-link ex-tooltip"
@ -79,6 +93,7 @@ import { useWorkspacesStore } from '@/stores/workspaces';
import * as Draggable from 'vuedraggable'; import * as Draggable from 'vuedraggable';
import SettingBarContext from '@/components/SettingBarContext.vue'; import SettingBarContext from '@/components/SettingBarContext.vue';
import { ConnectionParams } from 'common/interfaces/antares'; import { ConnectionParams } from 'common/interfaces/antares';
import { useElementBounding, useScroll } from '@vueuse/core';
const applicationStore = useApplicationStore(); const applicationStore = useApplicationStore();
const connectionsStore = useConnectionsStore(); const connectionsStore = useConnectionsStore();
@ -92,11 +107,18 @@ const { showSettingModal, showScratchpad } = applicationStore;
const { getConnectionName, updatePinnedConnections } = connectionsStore; const { getConnectionName, updatePinnedConnections } = connectionsStore;
const { getWorkspace, selectWorkspace } = workspacesStore; const { getWorkspace, selectWorkspace } = workspacesStore;
const emit = defineEmits(['show-connections-modal']);
const isLinux = process.platform === 'linux'; const isLinux = process.platform === 'linux';
const sidebarConnections: Ref<HTMLDivElement> = ref(null);
const isContext: Ref<boolean> = ref(false); const isContext: Ref<boolean> = ref(false);
const isDragging: Ref<boolean> = ref(false); const isDragging: Ref<boolean> = ref(false);
const isScrollable: Ref<boolean> = ref(false);
const isScrolling = ref(useScroll(sidebarConnections)?.isScrolling);
const contextEvent: Ref<MouseEvent> = ref(null); const contextEvent: Ref<MouseEvent> = ref(null);
const contextConnection: Ref<ConnectionParams> = ref(null); const contextConnection: Ref<ConnectionParams> = ref(null);
const sidebarConnectionsHeight = ref(useElementBounding(sidebarConnections)?.height);
const pinnedConnectionsArr = computed({ const pinnedConnectionsArr = computed({
get: () => [...pinnedConnections.value].map(c => storedConnections.value.find(sc => sc.uid === c)).filter(Boolean), get: () => [...pinnedConnections.value].map(c => storedConnections.value.find(sc => sc.uid === c)).filter(Boolean),
@ -133,11 +155,14 @@ const contextMenu = (event: MouseEvent, connection: ConnectionParams) => {
}; };
const tooltipPosition = (e: Event) => { const tooltipPosition = (e: Event) => {
const el = e.target ? e.target : e; const el = (e.target ? e.target : e) as unknown as HTMLElement;
const fromTop = isLinux const tooltip = el.querySelector<HTMLElement>('.ex-tooltip-content');
? window.scrollY + (el as HTMLElement).getBoundingClientRect().top + ((el as HTMLElement).offsetHeight / 4) if (tooltip) {
: window.scrollY + (el as HTMLElement).getBoundingClientRect().top - ((el as HTMLElement).offsetHeight / 4); const fromTop = isLinux
(el as HTMLElement).querySelector<HTMLElement>('.ex-tooltip-content').style.top = `${fromTop}px`; ? window.scrollY + el.getBoundingClientRect().top + (el.offsetHeight / 4)
: window.scrollY + el.getBoundingClientRect().top - (el.offsetHeight / 4);
tooltip.style.top = `${fromTop}px`;
}
}; };
const getStatusBadge = (uid: string) => { const getStatusBadge = (uid: string) => {
@ -166,6 +191,10 @@ const dragStop = (e: any) => {
}, 200); }, 200);
}; };
watch(sidebarConnectionsHeight, (value) => {
isScrollable.value = value < sidebarConnections.value.scrollHeight;
});
watch(unpinnedConnectionsArr, (newVal, oldVal) => { watch(unpinnedConnectionsArr, (newVal, oldVal) => {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) { if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
setTimeout(() => { setTimeout(() => {
@ -193,7 +222,7 @@ watch(unpinnedConnectionsArr, (newVal, oldVal) => {
height: calc(100vh - #{$excluding-size}); height: calc(100vh - #{$excluding-size});
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; // justify-content: space-between;
align-items: center; align-items: center;
padding: 0; padding: 0;
z-index: 9; z-index: 9;
@ -201,7 +230,7 @@ watch(unpinnedConnectionsArr, (newVal, oldVal) => {
.settingbar-top-elements { .settingbar-top-elements {
overflow-x: hidden; overflow-x: hidden;
overflow-y: overlay; overflow-y: overlay;
max-height: calc((100vh - 3.5rem) - #{$excluding-size}); // max-height: calc((100vh - 3.5rem) - #{$excluding-size});
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 3px; width: 3px;
@ -209,8 +238,8 @@ watch(unpinnedConnectionsArr, (newVal, oldVal) => {
} }
.settingbar-bottom-elements { .settingbar-bottom-elements {
padding-top: 0.5rem;
z-index: 1; z-index: 1;
margin-top: auto;
} }
.settingbar-elements { .settingbar-elements {
@ -273,6 +302,7 @@ watch(unpinnedConnectionsArr, (newVal, oldVal) => {
&::before { &::before {
font: normal normal normal 14px/1 "Material Design Icons"; font: normal normal normal 14px/1 "Material Design Icons";
content: "\F0403"; content: "\F0403";
color: $body-font-color-dark;
transform: rotate(45deg); transform: rotate(45deg);
opacity: .25; opacity: .25;
bottom: -8px; bottom: -8px;

View File

@ -332,7 +332,10 @@ const addField = () => {
collation: defaultCollation.value, collation: defaultCollation.value,
autoIncrement: false, autoIncrement: false,
onUpdate: '', onUpdate: '',
comment: '' comment: '',
alias: '',
tableAlias: '',
orgTable: ''
}); });
setTimeout(() => { setTimeout(() => {

View File

@ -293,7 +293,8 @@ module.exports = {
untrustedConnection: 'Untrusted connection', untrustedConnection: 'Untrusted connection',
missingOrIncompleteTranslation: 'Missing or incomplete translation?', missingOrIncompleteTranslation: 'Missing or incomplete translation?',
findOutHowToContribute: 'Find out how to contribute', findOutHowToContribute: 'Find out how to contribute',
disableFKChecks: 'Disable foreigh key checks' disableFKChecks: 'Disable foreigh key checks',
allConnections: 'All connections'
}, },
faker: { faker: {
address: 'Address', address: 'Address',

View File

@ -400,9 +400,7 @@
} }
.settingbar-bottom-elements { .settingbar-bottom-elements {
padding-top: 0.5rem;
background: $bg-color-light-dark; background: $bg-color-light-dark;
z-index: 1;
} }
.settingbar-elements { .settingbar-elements {

View File

@ -169,9 +169,7 @@
} }
.settingbar-bottom-elements { .settingbar-bottom-elements {
padding-top: 0.5rem;
background: $bg-color-light-dark; background: $bg-color-light-dark;
z-index: 1;
} }
.settingbar-elements { .settingbar-elements {

View File

@ -5,6 +5,7 @@
"./src/renderer/**/*", "./src/renderer/**/*",
"./src/common/interfaces/antares.ts" "./src/common/interfaces/antares.ts"
], ],
"exclude": ["./src/renderer/libs/ext-language_tools.js"],
"compilerOptions": { "compilerOptions": {
"baseUrl": "./", "baseUrl": "./",
"target": "es2021", "target": "es2021",