mirror of
https://github.com/Fabio286/mizar.git
synced 2025-03-12 06:50:04 +01:00
utility commit
This commit is contained in:
parent
9f945c4b8f
commit
f556bd3a8f
@ -4,9 +4,9 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
const unzip = require('unzip-crx-3');
|
||||
const { antares } = require('../package.json');
|
||||
const { mizar } = require('../package.json');
|
||||
|
||||
const extensionID = antares.devtoolsId;
|
||||
const extensionID = mizar.devtoolsId;
|
||||
const destFolder = path.resolve(__dirname, `../misc/${extensionID}`);
|
||||
const filePath = path.resolve(__dirname, `${destFolder}${extensionID}.crx`);
|
||||
const fileUrl = `https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D${extensionID}%26uc&prodversion=32`;
|
||||
|
@ -31,7 +31,7 @@ async function createMainWindow () {
|
||||
x: mainWindowState.x,
|
||||
y: mainWindowState.y,
|
||||
minWidth: 900,
|
||||
minHeight: 550,
|
||||
minHeight: 500,
|
||||
show: !isWindows,
|
||||
title: 'Mizar',
|
||||
icon: nativeImage.createFromDataURL(icon.default),
|
||||
@ -124,8 +124,8 @@ else {
|
||||
if (isWindows)
|
||||
mainWindow.show();
|
||||
|
||||
// if (isDevelopment)
|
||||
// mainWindow.webContents.openDevTools();
|
||||
if (isDevelopment)
|
||||
mainWindow.webContents.openDevTools();
|
||||
|
||||
process.on('uncaughtException', error => {
|
||||
mainWindow.webContents.send('unhandled-exception', error);
|
||||
|
@ -1,179 +1,59 @@
|
||||
<template>
|
||||
<div id="wrapper" :class="[`theme-${applicationTheme}`, !disableBlur || 'no-blur']">
|
||||
<TheTitleBar />
|
||||
<div id="window-content">
|
||||
<TheSettingBar @show-connections-modal="isAllConnectionsModal = true" />
|
||||
<div id="main-content" class="container">
|
||||
<div class="columns col-gapless">
|
||||
<Workspace
|
||||
v-for="connection in connections"
|
||||
:key="connection.uid"
|
||||
:connection="connection"
|
||||
/>
|
||||
<div class="connection-panel-wrapper p-relative">
|
||||
<WorkspaceAddConnectionPanel v-if="selectedWorkspace === 'NEW'" />
|
||||
</div>
|
||||
</div>
|
||||
<TheFooter />
|
||||
<TheNotificationsBoard />
|
||||
<TheScratchpad v-if="isScratchpad" />
|
||||
<ModalSettings v-if="isSettingModal" />
|
||||
<BaseTextEditor class="d-none" value="" />
|
||||
</div>
|
||||
<div id="wrapper">
|
||||
<AppHeader
|
||||
ref="header"
|
||||
:sel-tab="selTab"
|
||||
:client-status="clientStatus"
|
||||
:server-status="serverStatus"
|
||||
@select-tab="selectTab"
|
||||
/>
|
||||
<div id="main">
|
||||
<Client
|
||||
v-show="selTab === 0"
|
||||
ref="client"
|
||||
@client-status="clientUpdateStatus"
|
||||
/>
|
||||
<Server
|
||||
v-show="selTab === 1"
|
||||
ref="server"
|
||||
@server-status="serverUpdateStatus"
|
||||
/>
|
||||
</div>
|
||||
<ModalAllConnections v-if="isAllConnectionsModal" @close="isAllConnectionsModal = false" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineAsyncComponent, onMounted, Ref, ref } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { Menu, getCurrentWindow } from '@electron/remote';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import TheSettingBar from '@/components/TheSettingBar.vue';
|
||||
import AppHeader from '@/components/app-header.vue';
|
||||
import Client from '@/components/client.vue';
|
||||
import Server from '@/components/server.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const TheTitleBar = defineAsyncComponent(() => import(/* webpackChunkName: "TheTitleBar" */'@/components/TheTitleBar.vue'));
|
||||
const TheFooter = defineAsyncComponent(() => import(/* webpackChunkName: "TheFooter" */'@/components/TheFooter.vue'));
|
||||
const TheNotificationsBoard = defineAsyncComponent(() => import(/* webpackChunkName: "TheNotificationsBoard" */'@/components/TheNotificationsBoard.vue'));
|
||||
const Workspace = defineAsyncComponent(() => import(/* webpackChunkName: "Workspace" */'@/components/Workspace.vue'));
|
||||
const WorkspaceAddConnectionPanel = defineAsyncComponent(() => import(/* webpackChunkName: "WorkspaceAddConnectionPanel" */'@/components/WorkspaceAddConnectionPanel.vue'));
|
||||
const ModalSettings = defineAsyncComponent(() => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings.vue'));
|
||||
const ModalAllConnections = defineAsyncComponent(() => import(/* webpackChunkName: "ModalAllConnections" */'@/components/ModalAllConnections.vue'));
|
||||
const TheScratchpad = defineAsyncComponent(() => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad.vue'));
|
||||
const BaseTextEditor = defineAsyncComponent(() => import(/* webpackChunkName: "BaseTextEditor" */'@/components/BaseTextEditor.vue'));
|
||||
const selTab = ref(0);
|
||||
const clientStatus = ref(0);
|
||||
const serverStatus = ref(0);
|
||||
|
||||
const applicationStore = useApplicationStore();
|
||||
const connectionsStore = useConnectionsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const selectTab = (value: number) => {
|
||||
selTab.value = value;
|
||||
};
|
||||
|
||||
const {
|
||||
isSettingModal,
|
||||
isScratchpad
|
||||
} = storeToRefs(applicationStore);
|
||||
const { connections } = storeToRefs(connectionsStore);
|
||||
const { applicationTheme, disableBlur } = storeToRefs(settingsStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
const clientUpdateStatus = (value: number) => {
|
||||
clientStatus.value = value;
|
||||
};
|
||||
|
||||
const { checkVersionUpdate } = applicationStore;
|
||||
const { changeApplicationTheme } = settingsStore;
|
||||
const serverUpdateStatus = (value: number) => {
|
||||
serverStatus.value = value;
|
||||
};
|
||||
|
||||
const isAllConnectionsModal: Ref<boolean> = ref(false);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
setTimeout(() => {
|
||||
changeApplicationTheme(applicationTheme.value);// Forces persistentStore to save on file and mail process
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
ipcRenderer.on('open-all-connections', () => {
|
||||
isAllConnectionsModal.value = true;
|
||||
});
|
||||
|
||||
ipcRenderer.on('open-scratchpad', () => {
|
||||
isScratchpad.value = true;
|
||||
});
|
||||
|
||||
ipcRenderer.on('open-settings', () => {
|
||||
isSettingModal.value = true;
|
||||
});
|
||||
|
||||
ipcRenderer.on('create-connection', () => {
|
||||
workspacesStore.selectWorkspace('NEW');
|
||||
});
|
||||
|
||||
ipcRenderer.send('check-for-updates');
|
||||
checkVersionUpdate();
|
||||
|
||||
const InputMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: t('word.cut'),
|
||||
role: 'cut'
|
||||
},
|
||||
{
|
||||
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.addEventListener('keydown', e => {
|
||||
if (e.altKey && e.key === 'Alt') { // Prevent Alt key to trigger hidden shortcut menu
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#wrapper {
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#window-content {
|
||||
display: flex;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#main-content {
|
||||
padding: 0;
|
||||
justify-content: flex-start;
|
||||
height: calc(100vh - #{$excluding-size});
|
||||
width: calc(100% - #{$settingbar-width});
|
||||
|
||||
> .columns {
|
||||
height: calc(100vh - #{$footer-height});
|
||||
}
|
||||
|
||||
.connection-panel-wrapper {
|
||||
height: calc(100vh - #{$excluding-size});
|
||||
width: 100%;
|
||||
padding-top: 10vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .2s;
|
||||
}
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,65 +0,0 @@
|
||||
<style>
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .2s;
|
||||
}
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div id="wrapper">
|
||||
<AppHeader
|
||||
ref="header"
|
||||
:sel-tab="selTab"
|
||||
:client-status="clientStatus"
|
||||
:server-status="serverStatus"
|
||||
@selectTab="selectTab"
|
||||
/>
|
||||
<div id="main">
|
||||
<Client
|
||||
v-show="selTab === 0"
|
||||
ref="client"
|
||||
@clientStatus="clientUpdateStatus"
|
||||
/>
|
||||
<Server
|
||||
v-show="selTab === 1"
|
||||
ref="server"
|
||||
@serverStatus="serverUpdateStatus"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppHeader from './app-header.vue';
|
||||
import Client from './client.vue';
|
||||
import Server from './server.vue';
|
||||
|
||||
export default {
|
||||
name: 'Main',
|
||||
components: {
|
||||
AppHeader,
|
||||
Client,
|
||||
Server
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
selTab: 0,
|
||||
clientStatus: 0,
|
||||
serverStatus: 0
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
selectTab (value) {
|
||||
this.selTab = value;
|
||||
},
|
||||
clientUpdateStatus (value) {
|
||||
this.clientStatus = value;
|
||||
},
|
||||
serverUpdateStatus (value) {
|
||||
this.serverStatus = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,30 +1,10 @@
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import { enUS } from './en-US';
|
||||
import { itIT } from './it-IT';
|
||||
import { arSA } from './ar-SA';
|
||||
import { esES } from './es-ES';
|
||||
import { frFR } from './fr-FR';
|
||||
import { ptBR } from './pt-BR';
|
||||
import { deDE } from './de-DE';
|
||||
import { viVN } from './vi-VN';
|
||||
import { jaJP } from './ja-JP';
|
||||
import { zhCN } from './zh-CN';
|
||||
import { ruRU } from './ru-RU';
|
||||
import { idID } from './id-ID';
|
||||
|
||||
const messages = {
|
||||
'en-US': enUS,
|
||||
'it-IT': itIT,
|
||||
'ar-SA': arSA,
|
||||
'es-ES': esES,
|
||||
'fr-FR': frFR,
|
||||
'pt-BR': ptBR,
|
||||
'de-DE': deDE,
|
||||
'vi-VN': viVN,
|
||||
'ja-JP': jaJP,
|
||||
'zh-CN': zhCN,
|
||||
'ru-RU': ruRU,
|
||||
'id-ID': idID
|
||||
'it-IT': itIT
|
||||
};
|
||||
|
||||
type NestedPartial<T> = {
|
||||
|
@ -1,14 +1,4 @@
|
||||
export const localesNames: {[key: string]: string} = {
|
||||
'en-US': 'English',
|
||||
'it-IT': 'Italiano',
|
||||
'ar-SA': 'العربية',
|
||||
'es-ES': 'Español',
|
||||
'fr-FR': 'Français',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
'de-DE': 'Deutsch (Deutschland)',
|
||||
'vi-VN': 'Tiếng Việt',
|
||||
'ja-JP': '日本語',
|
||||
'zh-CN': '简体中文',
|
||||
'ru-RU': 'Русский',
|
||||
'id-ID': 'Bahasa Indonesia'
|
||||
'it-IT': 'Italiano'
|
||||
};
|
||||
|
@ -2,31 +2,19 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { createApp } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import { VueMaskDirective } from 'v-mask';
|
||||
import * as FloatingVue from 'floating-vue';
|
||||
import '@mdi/font/css/materialdesignicons.css';
|
||||
import 'floating-vue/dist/style.css';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import '@/scss/main.scss';
|
||||
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useConsoleStore } from '@/stores/console';
|
||||
|
||||
import App from '@/App.vue';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
// https://github.com/probil/v-mask/issues/498#issuecomment-827027834
|
||||
const vMaskV2 = VueMaskDirective;
|
||||
const vMaskV3 = {
|
||||
beforeMount: vMaskV2.bind,
|
||||
updated: vMaskV2.componentUpdated,
|
||||
unmounted: vMaskV2.unbind
|
||||
};
|
||||
|
||||
createApp(App)
|
||||
.directive('mask', vMaskV3)
|
||||
.use(createPinia())
|
||||
.use(i18n)
|
||||
.use(FloatingVue)
|
||||
@ -40,15 +28,6 @@ ipcRenderer.on('unhandled-exception', (event, error) => {
|
||||
useNotificationsStore().addNotification({ status: 'error', message: error.message });
|
||||
});
|
||||
|
||||
// IPC query logs
|
||||
ipcRenderer.on('query-log', (event, logRecord) => {
|
||||
useConsoleStore().putLog(logRecord);
|
||||
});
|
||||
|
||||
ipcRenderer.on('toggle-console', () => {
|
||||
useConsoleStore().toggleConsole();
|
||||
});
|
||||
|
||||
// IPC app updates
|
||||
ipcRenderer.on('checking-for-update', () => {
|
||||
useApplicationStore().updateStatus = 'checking';
|
||||
@ -92,7 +71,3 @@ ipcRenderer.on('open-updates-preferences', () => {
|
||||
useApplicationStore().showSettingModal('update');
|
||||
ipcRenderer.send('check-for-updates');
|
||||
});
|
||||
|
||||
ipcRenderer.on('update-shortcuts', (event, shortcuts) => {
|
||||
useSettingsStore().updateShortcuts(shortcuts);
|
||||
});
|
||||
|
3
src/renderer/libs/uidGen.ts
Normal file
3
src/renderer/libs/uidGen.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function uidGen (prefix?: string) {
|
||||
return (prefix ? `${prefix}:` : '') + Math.random().toString(36).substring(2, 11).toUpperCase();
|
||||
}
|
@ -1,425 +0,0 @@
|
||||
/* stylelint-disable selector-class-pattern */
|
||||
@import "~spectre.css/src/variables";
|
||||
@import "variables";
|
||||
@import "transitions";
|
||||
@import "data-types";
|
||||
@import "table-keys";
|
||||
@import "fake-tables";
|
||||
@import "mdi-additions";
|
||||
@import "db-icons";
|
||||
@import "themes/dark-theme";
|
||||
@import "themes/light-theme";
|
||||
@import "~spectre.css/src/spectre";
|
||||
@import "~spectre.css/src/spectre-exp";
|
||||
|
||||
body {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
::selection,
|
||||
option:hover,
|
||||
option:focus,
|
||||
option:active,
|
||||
option:checked {
|
||||
background-color: $primary-color;
|
||||
color: $light-color;
|
||||
}
|
||||
|
||||
/* Additions */
|
||||
@include margin-variant(3, $unit-3);
|
||||
@include margin-variant(4, $unit-4);
|
||||
@include padding-variant(3, $unit-3);
|
||||
@include padding-variant(4, $unit-4);
|
||||
|
||||
.p-vcentered {
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.c-help {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.no-outline {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.no-radius {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.no-border {
|
||||
outline: none !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.cut-text {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.cancellable {
|
||||
color: transparent !important;
|
||||
min-height: 0.8rem;
|
||||
position: relative;
|
||||
|
||||
> .mdi,
|
||||
> .span {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "\2715";
|
||||
color: $light-color;
|
||||
font-weight: 700;
|
||||
top: 36%;
|
||||
display: block;
|
||||
height: 0.8rem;
|
||||
left: 50%;
|
||||
margin-left: -0.4rem;
|
||||
margin-top: -0.4rem;
|
||||
opacity: 1;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 0.8rem;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-query-results {
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
|
||||
.table {
|
||||
width: auto;
|
||||
border-collapse: separate;
|
||||
|
||||
.th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
border: 2px solid;
|
||||
border-left: none;
|
||||
border-bottom-width: 2px;
|
||||
padding: 0;
|
||||
font-weight: 700;
|
||||
font-size: 0.7rem;
|
||||
z-index: 1;
|
||||
|
||||
> div {
|
||||
padding: 0.1rem 0.2rem;
|
||||
/* stylelint-disable-next-line value-no-vendor-prefix */
|
||||
min-width: -webkit-fill-available;
|
||||
}
|
||||
}
|
||||
|
||||
.td {
|
||||
border-right: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
padding: 0 0.2rem;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-size: 0.7rem;
|
||||
position: relative;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-tabs {
|
||||
align-content: baseline;
|
||||
|
||||
.workspace-query-runner {
|
||||
.workspace-query-runner-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.3rem 0.6rem 0.4rem;
|
||||
align-items: center;
|
||||
|
||||
.workspace-query-buttons {
|
||||
display: flex;
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-query-info {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
> div + div {
|
||||
padding-left: 0.6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.process-row .td:last-child {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Scrollbars */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
|
||||
.rotate {
|
||||
animation: rotation 0.8s infinite linear;
|
||||
}
|
||||
|
||||
/* Override */
|
||||
.modal {
|
||||
.modal-container,
|
||||
.modal-sm .modal-container {
|
||||
padding: 0;
|
||||
border-radius: $border-radius;
|
||||
|
||||
.modal-header {
|
||||
padding: 0.4rem 0.8rem;
|
||||
text-transform: uppercase;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-radius: $border-radius $border-radius 0 0;
|
||||
|
||||
.modal-title {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-overlay {
|
||||
background: rgb(255 255 255 / 10%);
|
||||
box-shadow: 0 8px 32px 0 rgb(31 38 135 / 37%);
|
||||
}
|
||||
}
|
||||
|
||||
#wrapper:not(.no-blur) {
|
||||
.modal-overlay {
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
.tab-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.tab-link {
|
||||
min-width: 0;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.tab-link {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
&::after {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
height: 2px;
|
||||
width: 0;
|
||||
transition: width 0.2s;
|
||||
background-color: $primary-color;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.btn-clear {
|
||||
margin-top: -0.1rem;
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tooltip:hover {
|
||||
&::after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
&[data-badge],
|
||||
&:not([data-badge]) {
|
||||
&::after {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.badge-connected::after {
|
||||
background: $success-color;
|
||||
}
|
||||
|
||||
&.badge-connecting::after {
|
||||
background: $warning-color;
|
||||
animation-name: pulse;
|
||||
animation-duration: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
&.badge-failed::after {
|
||||
background: $error-color;
|
||||
}
|
||||
}
|
||||
|
||||
.form-select {
|
||||
cursor: pointer;
|
||||
|
||||
&.small-select {
|
||||
height: 21px;
|
||||
font-size: 0.7rem;
|
||||
padding: 1px 0.4rem 0;
|
||||
}
|
||||
|
||||
&.select {
|
||||
&.select--open {
|
||||
border-color: $primary-color !important;
|
||||
|
||||
@include control-shadow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select__list {
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0.3rem 0.8rem;
|
||||
|
||||
.select-sm &,
|
||||
.small-select & {
|
||||
padding: 0.05rem 0.3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select__list-wrapper {
|
||||
z-index: 401 !important;
|
||||
border: 1px solid transparent;
|
||||
border-radius: $border-radius;
|
||||
box-shadow: 0 8px 17px 0 rgb(0 0 0 / 20%), 0 6px 20px 0 rgb(0 0 0 / 19%);
|
||||
}
|
||||
|
||||
.select__option--selected {
|
||||
background: rgba($primary-color, 0.25);
|
||||
}
|
||||
|
||||
.select__option--highlight {
|
||||
background: $primary-color;
|
||||
}
|
||||
|
||||
.form-input[type="file"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.input-group .input-group-addon {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.menu {
|
||||
font-size: 0.7rem;
|
||||
|
||||
.menu-item {
|
||||
+ .menu-item {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.accordion-body {
|
||||
max-height: 5000rem !important;
|
||||
}
|
||||
|
||||
.btn {
|
||||
&:focus {
|
||||
box-shadow: 0 0 3px 1px rgba($primary-color, 90%);
|
||||
}
|
||||
|
||||
&.btn-success:focus {
|
||||
border-color: $primary-color;
|
||||
box-shadow: 0 0 3px 1px rgba($primary-color, 90%);
|
||||
}
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.btn.loading {
|
||||
> .mdi,
|
||||
> span {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 0.15rem 0.3rem;
|
||||
}
|
||||
|
||||
.table-dropdown {
|
||||
.menu {
|
||||
min-width: 100%;
|
||||
padding: 0;
|
||||
|
||||
.menu-item {
|
||||
padding: 0;
|
||||
|
||||
> a {
|
||||
margin: 0.2rem;
|
||||
padding: 0.1rem 0.3rem;
|
||||
|
||||
&:hover {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ace Editor */
|
||||
.ace_editor {
|
||||
&.ace_autocomplete {
|
||||
border-radius: $border-radius;
|
||||
|
||||
.ace_marker-layer {
|
||||
.ace_active-line,
|
||||
.ace_line-hover {
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import * as Store from 'electron-store';
|
||||
import { Ace } from 'ace-builds';
|
||||
const persistentStore = new Store({ name: 'settings' });
|
||||
|
||||
export const useApplicationStore = defineStore('application', {
|
||||
@ -15,11 +14,9 @@ export const useApplicationStore = defineStore('application', {
|
||||
selectedSettingTab: 'general',
|
||||
selectedConection: {},
|
||||
updateStatus: 'noupdate', // 'noupdate' | 'available' | 'checking' | 'nocheck' | 'downloading' | 'downloaded' | 'disabled'
|
||||
downloadProgress: 0,
|
||||
baseCompleter: [] as Ace.Completer[] // Needed to reset ace editor, due global-only ace completer
|
||||
downloadProgress: 0
|
||||
}),
|
||||
getters: {
|
||||
getBaseCompleter: state => state.baseCompleter,
|
||||
getSelectedConnection: state => state.selectedConection,
|
||||
getDownloadProgress: state => Number(state.downloadProgress.toFixed(1))
|
||||
},
|
||||
@ -34,9 +31,6 @@ export const useApplicationStore = defineStore('application', {
|
||||
setLoadingStatus (payload: boolean) {
|
||||
this.isLoading = payload;
|
||||
},
|
||||
setBaseCompleters (payload: Ace.Completer[]) {
|
||||
this.baseCompleter = payload;
|
||||
},
|
||||
// Modals
|
||||
showNewConnModal () {
|
||||
this.isNewModal = true;
|
||||
|
@ -1,224 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import * as Store from 'electron-store';
|
||||
import * as crypto from 'crypto';
|
||||
import { ConnectionParams } from 'common/interfaces/antares';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
const key = localStorage.getItem('key');
|
||||
|
||||
export interface SidebarElement {
|
||||
isFolder: boolean;
|
||||
uid: string;
|
||||
client?: string;
|
||||
connections?: string[];
|
||||
color?: string;
|
||||
name?: string;
|
||||
icon?: null | string;
|
||||
}
|
||||
|
||||
if (!key)
|
||||
localStorage.setItem('key', crypto.randomBytes(16).toString('hex'));
|
||||
else
|
||||
localStorage.setItem('key', key);
|
||||
|
||||
const persistentStore = new Store({
|
||||
name: 'connections',
|
||||
encryptionKey: key,
|
||||
clearInvalidConfig: true
|
||||
});
|
||||
|
||||
export const useConnectionsStore = defineStore('connections', {
|
||||
state: () => ({
|
||||
connections: persistentStore.get('connections', []) as ConnectionParams[],
|
||||
lastConnections: persistentStore.get('lastConnections', []) as {uid: string; time: number}[],
|
||||
connectionsOrder: persistentStore.get('connectionsOrder', []) as SidebarElement[]
|
||||
}),
|
||||
getters: {
|
||||
getConnectionByUid: state => (uid:string) => state.connections.find(connection => connection.uid === uid),
|
||||
getConnectionName: state => (uid: string) => {
|
||||
const connection = state.connections.find(connection => connection.uid === uid);
|
||||
let connectionName = '';
|
||||
if (connection) {
|
||||
if (connection.name)
|
||||
connectionName = connection.name;
|
||||
else if (connection.ask)
|
||||
connectionName = `${connection.host}:${connection.port}`;
|
||||
else if (connection.databasePath) {
|
||||
let string = connection.databasePath.split(/[/\\]+/).pop();
|
||||
|
||||
if (string.length >= 30)
|
||||
string = `...${string.slice(-30)}`;
|
||||
|
||||
connectionName = string;
|
||||
}
|
||||
else
|
||||
connectionName = `${connection.user + '@'}${connection.host}:${connection.port}`;
|
||||
}
|
||||
|
||||
return connectionName;
|
||||
},
|
||||
getConnectionOrderByUid: state => (uid:string) => state.connectionsOrder
|
||||
.find(connection => connection.uid === uid),
|
||||
getFolders: state => state.connectionsOrder.filter(conn => conn.isFolder),
|
||||
getConnectionFolder: state => (uid:string) => state.connectionsOrder
|
||||
.find(folder => folder.isFolder && folder.connections.includes(uid))
|
||||
},
|
||||
actions: {
|
||||
addConnection (connection: ConnectionParams) {
|
||||
this.connections.push(connection);
|
||||
persistentStore.set('connections', this.connections);
|
||||
|
||||
this.connectionsOrder.push({
|
||||
isFolder: false,
|
||||
uid: connection.uid,
|
||||
client: connection.client,
|
||||
icon: null,
|
||||
name: null
|
||||
});
|
||||
persistentStore.set('connectionsOrder', this.connectionsOrder);
|
||||
},
|
||||
addFolder (params: {after: string; connections: [string, string]}) {
|
||||
const index = this.connectionsOrder.findIndex((conn: SidebarElement) => conn.uid === params.after);
|
||||
|
||||
this.connectionsOrder.splice(index, 0, {
|
||||
isFolder: true,
|
||||
uid: uidGen('F'),
|
||||
name: '',
|
||||
color: '#E36929',
|
||||
connections: params.connections
|
||||
});
|
||||
persistentStore.set('connectionsOrder', this.connectionsOrder);
|
||||
},
|
||||
addToFolder (params: {folder: string; connection: string}) {
|
||||
this.connectionsOrder = this.connectionsOrder.map((conn: SidebarElement) => {
|
||||
if (conn.uid === params.folder)
|
||||
conn.connections.push(params.connection);
|
||||
|
||||
return conn;
|
||||
});
|
||||
persistentStore.set('connectionsOrder', this.connectionsOrder);
|
||||
this.clearEmptyFolders();
|
||||
},
|
||||
deleteConnection (connection: SidebarElement | ConnectionParams) {
|
||||
this.connectionsOrder = (this.connectionsOrder as SidebarElement[]).map(el => { // Removes connection from folders
|
||||
if (el.isFolder && el.connections.includes(connection.uid))
|
||||
el.connections = el.connections.filter(uid => uid !== connection.uid);
|
||||
return el;
|
||||
});
|
||||
this.connectionsOrder = (this.connectionsOrder as SidebarElement[]).filter(el => el.uid !== connection.uid);
|
||||
|
||||
this.connections = (this.connections as SidebarElement[]).filter(el => el.uid !== connection.uid);
|
||||
persistentStore.set('connections', this.connections);
|
||||
this.clearEmptyFolders();
|
||||
},
|
||||
editConnection (connection: ConnectionParams) {
|
||||
const editedConnections = (this.connections as ConnectionParams[]).map(conn => {
|
||||
if (conn.uid === connection.uid) return connection;
|
||||
return conn;
|
||||
});
|
||||
|
||||
this.connections = editedConnections;
|
||||
persistentStore.set('connections', this.connections);
|
||||
|
||||
const editedConnectionsOrder = (this.connectionsOrder as SidebarElement[]).map(conn => {
|
||||
if (conn.uid === connection.uid) {
|
||||
return {
|
||||
isFolder: false,
|
||||
uid: connection.uid,
|
||||
client: connection.client,
|
||||
icon: conn.icon,
|
||||
name: conn.name
|
||||
};
|
||||
}
|
||||
return conn;
|
||||
});
|
||||
|
||||
this.connectionsOrder = editedConnectionsOrder;
|
||||
persistentStore.set('connectionsOrder', this.connectionsOrder);
|
||||
},
|
||||
updateConnections (connections: ConnectionParams[]) {
|
||||
this.connections = connections;
|
||||
persistentStore.set('connections', this.connections);
|
||||
},
|
||||
initConnectionsOrder () {
|
||||
this.connectionsOrder = (this.connections as ConnectionParams[]).map<SidebarElement>(conn => {
|
||||
return {
|
||||
isFolder: false,
|
||||
uid: conn.uid,
|
||||
client: conn.client,
|
||||
icon: null,
|
||||
name: null
|
||||
};
|
||||
});
|
||||
persistentStore.set('connectionsOrder', this.connectionsOrder);
|
||||
},
|
||||
updateConnectionsOrder (connections: SidebarElement[]) {
|
||||
const invalidElements = connections.reduce<{index: number; uid: string}[]>((acc, curr, i) => {
|
||||
if (typeof curr === 'string')
|
||||
acc.push({ index: i, uid: curr });
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
if (invalidElements.length) {
|
||||
invalidElements.forEach(el => {
|
||||
let connIndex = connections.findIndex(conn => conn.uid === el.uid);
|
||||
const conn = connections[connIndex];
|
||||
|
||||
if (connIndex === -1) return;
|
||||
|
||||
connections.splice(el.index, 1, { // Move to new position
|
||||
isFolder: false,
|
||||
client: conn.client,
|
||||
uid: conn.uid,
|
||||
icon: conn.icon,
|
||||
name: conn.name
|
||||
});
|
||||
|
||||
connIndex = connections.findIndex((conn, i) => conn.uid === el.uid && i !== el.index);
|
||||
connections.splice(connIndex, 1);// Delete old object
|
||||
});
|
||||
}
|
||||
|
||||
// Clear empty folders
|
||||
const emptyFolders = connections.reduce<string[]>((acc, curr) => {
|
||||
if (curr.connections && curr.connections.length === 0)
|
||||
acc.push(curr.uid);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
connections = connections.filter(el => !emptyFolders.includes(el.uid));
|
||||
|
||||
this.connectionsOrder = connections;
|
||||
persistentStore.set('connectionsOrder', this.connectionsOrder);
|
||||
},
|
||||
updateConnectionOrder (element: SidebarElement) {
|
||||
this.connectionsOrder = (this.connectionsOrder as SidebarElement[]).map(el => {
|
||||
if (el.uid === element.uid)
|
||||
el = element;
|
||||
return el;
|
||||
});
|
||||
persistentStore.set('connectionsOrder', this.connectionsOrder);
|
||||
},
|
||||
updateLastConnection (uid: string) {
|
||||
const cIndex = (this.lastConnections as {uid: string; time: number}[]).findIndex((c) => c.uid === uid);
|
||||
|
||||
if (cIndex >= 0)
|
||||
this.lastConnections[cIndex].time = new Date().getTime();
|
||||
else
|
||||
this.lastConnections.push({ uid, time: new Date().getTime() });
|
||||
|
||||
persistentStore.set('lastConnections', this.lastConnections);
|
||||
},
|
||||
clearEmptyFolders () {
|
||||
// Clear empty folders
|
||||
const emptyFolders = (this.connectionsOrder as SidebarElement[]).reduce<string[]>((acc, curr) => {
|
||||
if (curr.connections && curr.connections.length === 0)
|
||||
acc.push(curr.uid);
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
this.connectionsOrder = (this.connectionsOrder as SidebarElement[]).filter(el => !emptyFolders.includes(el.uid));
|
||||
persistentStore.set('connectionsOrder', this.connectionsOrder);
|
||||
}
|
||||
}
|
||||
});
|
@ -1,58 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { useWorkspacesStore } from './workspaces';
|
||||
const logsSize = 1000;
|
||||
|
||||
export interface ConsoleRecord {
|
||||
cUid: string;
|
||||
sql: string;
|
||||
date: Date;
|
||||
}
|
||||
|
||||
export const useConsoleStore = defineStore('console', {
|
||||
state: () => ({
|
||||
records: [] as ConsoleRecord[],
|
||||
consolesHeight: new Map<string, number>(),
|
||||
consolesOpened: new Set([])
|
||||
}),
|
||||
getters: {
|
||||
getLogsByWorkspace: state => (uid: string) => state.records.filter(r => r.cUid === uid),
|
||||
isConsoleOpen: state => (uid: string) => state.consolesOpened.has(uid),
|
||||
consoleHeight: state => {
|
||||
const uid = useWorkspacesStore().getSelected;
|
||||
return state.consolesHeight.get(uid) || 0;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
putLog (record: ConsoleRecord) {
|
||||
this.records.push(record);
|
||||
|
||||
if (this.records.length > logsSize)
|
||||
this.records = this.records.slice(0, logsSize);
|
||||
},
|
||||
openConsole () {
|
||||
const uid = useWorkspacesStore().getSelected;
|
||||
this.consolesOpened.add(uid);
|
||||
this.consolesHeight.set(uid, 250);
|
||||
},
|
||||
closeConsole () {
|
||||
const uid = useWorkspacesStore().getSelected;
|
||||
this.consolesOpened.delete(uid);
|
||||
this.consolesHeight.set(uid, 0);
|
||||
},
|
||||
resizeConsole (height: number) {
|
||||
const uid = useWorkspacesStore().getSelected;
|
||||
if (height < 30)
|
||||
this.closeConsole();
|
||||
else
|
||||
this.consolesHeight.set(uid, height);
|
||||
},
|
||||
toggleConsole () {
|
||||
const uid = useWorkspacesStore().getSelected;
|
||||
|
||||
if (this.consolesOpened.has(uid))
|
||||
this.closeConsole();
|
||||
else
|
||||
this.openConsole();
|
||||
}
|
||||
}
|
||||
});
|
@ -1,52 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import * as Store from 'electron-store';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
const persistentStore = new Store({ name: 'history' });
|
||||
const historySize = 1000;
|
||||
|
||||
export interface HistoryRecord {
|
||||
uid: string;
|
||||
sql: string;
|
||||
date: Date;
|
||||
schema?: string;
|
||||
}
|
||||
|
||||
export const useHistoryStore = defineStore('history', {
|
||||
state: () => ({
|
||||
history: persistentStore.get('history', {}) as {[key: string]: HistoryRecord[]},
|
||||
favorites: persistentStore.get('favorites', {})
|
||||
}),
|
||||
getters: {
|
||||
getHistoryByWorkspace: state => (uid: string) => state.history[uid]
|
||||
},
|
||||
actions: {
|
||||
saveHistory (args: { uid: string; query: string; schema: string; tabUid: string }) {
|
||||
if (this.getHistoryByWorkspace(args.uid) &&
|
||||
this.getHistoryByWorkspace(args.uid).length &&
|
||||
this.getHistoryByWorkspace(args.uid)[0].sql === args.query
|
||||
) return;
|
||||
|
||||
if (!(args.uid in this.history))
|
||||
this.history[args.uid] = [];
|
||||
|
||||
this.history[args.uid] = [
|
||||
{
|
||||
uid: uidGen('H'),
|
||||
sql: args.query,
|
||||
date: new Date(),
|
||||
schema: args.schema
|
||||
},
|
||||
...this.history[args.uid]
|
||||
];
|
||||
|
||||
if (this.history[args.uid].length > historySize)
|
||||
this.history[args.uid] = this.history[args.uid].slice(0, historySize);
|
||||
|
||||
persistentStore.set('history', this.history);
|
||||
},
|
||||
deleteQueryFromHistory (query: Partial<HistoryRecord> & { workspace: string}) {
|
||||
this.history[query.workspace] = (this.history[query.workspace] as HistoryRecord[]).filter(q => q.uid !== query.uid);
|
||||
persistentStore.set('history', this.history);
|
||||
}
|
||||
}
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import { uidGen } from '../libs/uidGen';
|
||||
|
||||
export interface Notification {
|
||||
uid: string;
|
||||
|
@ -1,15 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import * as Store from 'electron-store';
|
||||
const persistentStore = new Store({ name: 'notes' });
|
||||
|
||||
export const useScratchpadStore = defineStore('scratchpad', {
|
||||
state: () => ({
|
||||
notes: persistentStore.get('notes', '# HOW TO SUPPORT ANTARES\n\n- [ ] Leave a star to Antares [GitHub repo](https://github.com/antares-sql/antares)\n- [ ] Send feedbacks and advices\n- [ ] Report for bugs\n- [ ] If you enjoy, share Antares with friends\n\n# ABOUT SCRATCHPAD\n\nThis is a scratchpad where you can save your **personal notes**. It supports `markdown` format, but you are free to use plain text.\nThis content is just a placeholder, feel free to clear it to make space for your notes.\n') as string
|
||||
}),
|
||||
actions: {
|
||||
changeNotes (notes: string) {
|
||||
this.notes = notes;
|
||||
persistentStore.set('notes', this.notes);
|
||||
}
|
||||
}
|
||||
});
|
@ -2,10 +2,8 @@ import { defineStore } from 'pinia';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { i18n, AvailableLocale } from '@/i18n';
|
||||
import * as Store from 'electron-store';
|
||||
import { ShortcutRecord } from 'common/shortcuts';
|
||||
|
||||
const settingsStore = new Store({ name: 'settings' });
|
||||
const shortcutsStore = new Store({ name: 'shortcuts' });
|
||||
const isDarkTheme = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const defaultAppTheme = isDarkTheme.matches ? 'dark' : 'light';
|
||||
const defaultEditorTheme = isDarkTheme.matches ? 'twilight' : 'sqlserver';
|
||||
@ -30,7 +28,6 @@ export const useSettingsStore = defineStore('settings', {
|
||||
restoreTabs: settingsStore.get('restore_tabs', true) as boolean,
|
||||
disableBlur: settingsStore.get('disable_blur', false) as boolean,
|
||||
disableScratchpad: settingsStore.get('disable_scratchpad', false) as boolean,
|
||||
shortcuts: shortcutsStore.get('shortcuts', []) as ShortcutRecord[],
|
||||
defaultCopyType: settingsStore.get('default_copy_type', 'cell') as string
|
||||
}),
|
||||
actions: {
|
||||
@ -96,9 +93,6 @@ export const useSettingsStore = defineStore('settings', {
|
||||
this.disableScratchpad = val;
|
||||
settingsStore.set('disable_scratchpad', this.disableScratchpad);
|
||||
},
|
||||
updateShortcuts (shortcuts: ShortcutRecord[]) {
|
||||
this.shortcuts = shortcuts;
|
||||
},
|
||||
changeDefaultCopyType (type: string) {
|
||||
this.defaultCopyType = type;
|
||||
settingsStore.set('default_copy_type', this.defaultCopyType);
|
||||
|
@ -1,745 +0,0 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import * as Store from 'electron-store';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import Users from '@/ipc-api/Users';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
|
||||
import customizations from 'common/customizations';
|
||||
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import {
|
||||
ClientCode,
|
||||
CollationInfos,
|
||||
ConnectionParams,
|
||||
EventInfos,
|
||||
FunctionInfos,
|
||||
RoutineInfos,
|
||||
TableInfos,
|
||||
TriggerFunctionInfos,
|
||||
TriggerInfos,
|
||||
TypesGroup
|
||||
} from 'common/interfaces/antares';
|
||||
import { Customizations } from 'common/interfaces/customizations';
|
||||
|
||||
export interface WorkspaceTab {
|
||||
uid: string;
|
||||
tab?: string;
|
||||
index?: number;
|
||||
selected?: boolean;
|
||||
type?: string;
|
||||
schema?: string;
|
||||
elementName?: string;
|
||||
elementNewName?: string;
|
||||
elementType?: string;
|
||||
isChanged?: boolean;
|
||||
content?: string;
|
||||
autorun?: boolean;
|
||||
}
|
||||
|
||||
export interface WorkspaceStructure {
|
||||
name: string;
|
||||
functions: FunctionInfos[];
|
||||
procedures: RoutineInfos[];
|
||||
schedulers: EventInfos[];
|
||||
tables: TableInfos[];
|
||||
triggers: TriggerInfos[];
|
||||
triggerFunctions: TriggerFunctionInfos[];
|
||||
size: number;
|
||||
}
|
||||
|
||||
export interface Breadcrumb {
|
||||
function?: string;
|
||||
routine?: string;
|
||||
query?: string;
|
||||
scheduler?: string;
|
||||
schema?: string;
|
||||
table?: string;
|
||||
trigger?: string;
|
||||
triggerFunction?: string;
|
||||
view?: string;
|
||||
}
|
||||
|
||||
export interface Workspace {
|
||||
uid: string;
|
||||
client?: ClientCode;
|
||||
connectionStatus: string;
|
||||
selectedTab: string | number;
|
||||
searchTerm: string;
|
||||
tabs: WorkspaceTab[];
|
||||
structure: WorkspaceStructure[];
|
||||
variables: { name: string; value: string }[];
|
||||
collations: CollationInfos[];
|
||||
users: { host: string; name: string; password?: string }[];
|
||||
breadcrumbs: Breadcrumb;
|
||||
loadingElements: { name: string; schema: string; type: string }[];
|
||||
loadedSchemas: Set<string>;
|
||||
dataTypes?: { [key: string]: TypesGroup[] };
|
||||
indexTypes?: string[];
|
||||
customizations?: Customizations;
|
||||
version?: {
|
||||
number: string;
|
||||
name: string;
|
||||
arch: string;
|
||||
os: string;
|
||||
};
|
||||
engines?: {[key: string]: string | boolean | number}[];
|
||||
}
|
||||
|
||||
const persistentStore = new Store({ name: 'tabs' });
|
||||
const tabIndex: {[key: string]: number} = {};
|
||||
|
||||
export const useWorkspacesStore = defineStore('workspaces', {
|
||||
state: () => ({
|
||||
workspaces: [] as Workspace[],
|
||||
selectedWorkspace: null as string
|
||||
}),
|
||||
getters: {
|
||||
getSelected: state => {
|
||||
if (!state.workspaces.length) return 'NEW';
|
||||
if (state.selectedWorkspace) return state.selectedWorkspace;
|
||||
const connectionsStore = useConnectionsStore();
|
||||
if (connectionsStore.lastConnections.length) {
|
||||
return connectionsStore.lastConnections.sort((a, b) => {
|
||||
if (a.time < b.time) return 1;
|
||||
else if (a.time > b.time) return -1;
|
||||
return 0;
|
||||
})[0].uid;
|
||||
}
|
||||
|
||||
return state.workspaces[0].uid;
|
||||
},
|
||||
getWorkspace: state => (uid: string) => {
|
||||
return state.workspaces.find(workspace => workspace.uid === uid);
|
||||
},
|
||||
getDatabaseVariable: state => (uid: string, name: string) => {
|
||||
return state.workspaces.find(workspace => workspace.uid === uid).variables.find(variable => variable.name === name);
|
||||
},
|
||||
getWorkspaceTab (state) {
|
||||
return (tUid: string) => {
|
||||
if (!this.getSelected) return;
|
||||
const workspace = state.workspaces.find(workspace => workspace.uid === this.getSelected);
|
||||
if ('tabs' in workspace)
|
||||
return workspace.tabs.find(tab => tab.uid === tUid);
|
||||
return {};
|
||||
};
|
||||
},
|
||||
getConnected: state => {
|
||||
return state.workspaces
|
||||
.filter(workspace => workspace.connectionStatus === 'connected')
|
||||
.map(workspace => workspace.uid);
|
||||
},
|
||||
getLoadedSchemas: state => (uid: string) => {
|
||||
return state.workspaces.find(workspace => workspace.uid === uid).loadedSchemas;
|
||||
},
|
||||
getSearchTerm: state => (uid: string) => {
|
||||
return state.workspaces.find(workspace => workspace.uid === uid).searchTerm;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
selectWorkspace (uid: string) {
|
||||
if (!uid)
|
||||
this.selectedWorkspace = this.workspaces.length ? this.workspaces[0].uid : 'NEW';
|
||||
else
|
||||
this.selectedWorkspace = uid;
|
||||
},
|
||||
async connectWorkspace (connection: ConnectionParams & { pgConnString?: string }) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === connection.uid
|
||||
? {
|
||||
...workspace,
|
||||
structure: {},
|
||||
breadcrumbs: {},
|
||||
loadedSchemas: new Set(),
|
||||
connectionStatus: 'connecting'
|
||||
}
|
||||
: workspace);
|
||||
|
||||
const connectionsStore = useConnectionsStore();
|
||||
const notificationsStore = useNotificationsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
try {
|
||||
const { status, response } = await Connection.connect(connection);
|
||||
|
||||
if (status === 'error') {
|
||||
notificationsStore.addNotification({ status, message: response });
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === connection.uid
|
||||
? {
|
||||
...workspace,
|
||||
structure: {},
|
||||
breadcrumbs: {},
|
||||
loadedSchemas: new Set(),
|
||||
connectionStatus: 'failed'
|
||||
}
|
||||
: workspace);
|
||||
}
|
||||
else {
|
||||
let clientCustomizations: Customizations;
|
||||
const { updateLastConnection } = connectionsStore;
|
||||
|
||||
updateLastConnection(connection.uid);
|
||||
|
||||
switch (connection.client) {
|
||||
case 'mysql':
|
||||
case 'maria':
|
||||
clientCustomizations = customizations.mysql;
|
||||
break;
|
||||
case 'pg':
|
||||
clientCustomizations = customizations.pg;
|
||||
break;
|
||||
case 'sqlite':
|
||||
clientCustomizations = customizations.sqlite;
|
||||
break;
|
||||
case 'firebird':
|
||||
clientCustomizations = customizations.firebird;
|
||||
break;
|
||||
}
|
||||
const dataTypes = clientCustomizations.dataTypes;
|
||||
const indexTypes = clientCustomizations.indexTypes;
|
||||
|
||||
const { status, response: version } = await Schema.getVersion(connection.uid);
|
||||
|
||||
if (status === 'error')
|
||||
notificationsStore.addNotification({ status, message: version });
|
||||
|
||||
// Check if Maria or MySQL
|
||||
const isMySQL = version.name.includes('MySQL');
|
||||
const isMaria = version.name.includes('Maria');
|
||||
|
||||
if (isMySQL && connection.client !== 'mysql') {
|
||||
const connProxy = Object.assign({}, connection);
|
||||
connProxy.client = 'mysql';
|
||||
connectionsStore.editConnection(connProxy);
|
||||
}
|
||||
else if (isMaria && connection.client === 'mysql') {
|
||||
const connProxy = Object.assign({}, connection);
|
||||
connProxy.client = 'maria';
|
||||
connectionsStore.editConnection(connProxy);
|
||||
}
|
||||
|
||||
const cachedTabs: WorkspaceTab[] = settingsStore.restoreTabs ? persistentStore.get(connection.uid, []) as WorkspaceTab[] : [];
|
||||
|
||||
if (cachedTabs.length) {
|
||||
tabIndex[connection.uid] = cachedTabs.reduce((acc: number, curr) => {
|
||||
if (curr.index > acc) acc = curr.index;
|
||||
return acc;
|
||||
}, null);
|
||||
}
|
||||
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === connection.uid
|
||||
? {
|
||||
...workspace,
|
||||
client: connection.client,
|
||||
dataTypes,
|
||||
indexTypes,
|
||||
customizations: clientCustomizations,
|
||||
structure: response,
|
||||
connectionStatus: 'connected',
|
||||
tabs: cachedTabs,
|
||||
selectedTab: cachedTabs.length ? cachedTabs[0].uid : null,
|
||||
version
|
||||
}
|
||||
: workspace);
|
||||
|
||||
this.refreshCollations(connection.uid);
|
||||
this.refreshVariables(connection.uid);
|
||||
this.refreshEngines(connection.uid);
|
||||
this.refreshUsers(connection.uid);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
notificationsStore.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
async refreshStructure (uid: string) {
|
||||
const notificationsStore = useNotificationsStore();
|
||||
|
||||
try {
|
||||
const { status, response } = await Schema.getStructure({ uid, schemas: this.getLoadedSchemas(uid) });
|
||||
|
||||
if (status === 'error')
|
||||
notificationsStore.addNotification({ status, message: response });
|
||||
else {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? {
|
||||
...workspace,
|
||||
structure: response
|
||||
}
|
||||
: workspace);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
notificationsStore.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
async refreshSchema ({ uid, schema }: {uid: string; schema: string}) {
|
||||
const notificationsStore = useNotificationsStore();
|
||||
|
||||
try {
|
||||
const { status, response } = await Schema.getStructure({ uid, schemas: new Set([schema]) });
|
||||
if (status === 'error')
|
||||
notificationsStore.addNotification({ status, message: response });
|
||||
else {
|
||||
const schemaElements = (response as WorkspaceStructure[]).find(_schema => _schema.name === schema);
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
const schemaIndex = workspace.structure.findIndex(s => s.name === schema);
|
||||
|
||||
if (schemaIndex !== -1)
|
||||
workspace.structure[schemaIndex] = schemaElements;
|
||||
else
|
||||
workspace.structure.push(schemaElements);
|
||||
}
|
||||
return workspace;
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
notificationsStore.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
async refreshCollations (uid: string) {
|
||||
const notificationsStore = useNotificationsStore();
|
||||
|
||||
try {
|
||||
const { status, response } = await Schema.getCollations(uid);
|
||||
if (status === 'error')
|
||||
notificationsStore.addNotification({ status, message: response });
|
||||
else {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? {
|
||||
...workspace,
|
||||
collations: response
|
||||
}
|
||||
: workspace);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
notificationsStore.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
async refreshVariables (uid: string) {
|
||||
const notificationsStore = useNotificationsStore();
|
||||
|
||||
try {
|
||||
const { status, response } = await Schema.getVariables(uid);
|
||||
if (status === 'error')
|
||||
notificationsStore.addNotification({ status, message: response });
|
||||
else {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? {
|
||||
...workspace,
|
||||
variables: response
|
||||
}
|
||||
: workspace);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
notificationsStore.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
async refreshEngines (uid: string) {
|
||||
const notificationsStore = useNotificationsStore();
|
||||
|
||||
try {
|
||||
const { status, response } = await Schema.getEngines(uid);
|
||||
if (status === 'error')
|
||||
notificationsStore.addNotification({ status, message: response });
|
||||
else {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? {
|
||||
...workspace,
|
||||
engines: response
|
||||
}
|
||||
: workspace);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
notificationsStore.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
async refreshUsers (uid: string) {
|
||||
const notificationsStore = useNotificationsStore();
|
||||
|
||||
try {
|
||||
const { status, response } = await Users.getUsers(uid);
|
||||
if (status === 'error')
|
||||
notificationsStore.addNotification({ status, message: response });
|
||||
else {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? {
|
||||
...workspace,
|
||||
users: response
|
||||
}
|
||||
: workspace);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
notificationsStore.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
},
|
||||
removeConnected (uid: string) {
|
||||
Connection.disconnect(uid);
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? {
|
||||
...workspace,
|
||||
structure: {},
|
||||
breadcrumbs: {},
|
||||
loadedSchemas: new Set(),
|
||||
connectionStatus: 'disconnected'
|
||||
}
|
||||
: workspace);
|
||||
|
||||
this.selectTab({ uid, tab: 0 });
|
||||
},
|
||||
addWorkspace (uid: string) {
|
||||
const workspace: Workspace = {
|
||||
uid,
|
||||
connectionStatus: 'disconnected',
|
||||
selectedTab: 0,
|
||||
searchTerm: '',
|
||||
tabs: [],
|
||||
structure: [],
|
||||
variables: [],
|
||||
collations: [],
|
||||
users: [],
|
||||
breadcrumbs: {},
|
||||
loadingElements: [],
|
||||
loadedSchemas: new Set()
|
||||
};
|
||||
|
||||
this.workspaces.push(workspace);
|
||||
},
|
||||
changeBreadcrumbs (payload: Breadcrumb) {
|
||||
const breadcrumbsObj: Breadcrumb = {
|
||||
schema: null,
|
||||
table: null,
|
||||
trigger: null,
|
||||
triggerFunction: null,
|
||||
routine: null,
|
||||
function: null,
|
||||
scheduler: null,
|
||||
view: null,
|
||||
query: null
|
||||
};
|
||||
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === this.getSelected
|
||||
? {
|
||||
...workspace,
|
||||
breadcrumbs: { ...breadcrumbsObj, ...payload }
|
||||
}
|
||||
: workspace);
|
||||
},
|
||||
addLoadedSchema (schema: string) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === this.getSelected)
|
||||
workspace.loadedSchemas.add(schema);
|
||||
return workspace;
|
||||
});
|
||||
},
|
||||
addLoadingElement (element: { name: string; schema: string; type: string }) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === this.getSelected)
|
||||
workspace.loadingElements.push(element);
|
||||
return workspace;
|
||||
});
|
||||
},
|
||||
removeLoadingElement (element: { name: string; schema: string; type: string }) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === this.getSelected) {
|
||||
const loadingElements = workspace.loadingElements.filter(el =>
|
||||
el.schema !== element.schema &&
|
||||
el.name !== element.name &&
|
||||
el.type !== element.type
|
||||
);
|
||||
|
||||
workspace = { ...workspace, loadingElements };
|
||||
}
|
||||
return workspace;
|
||||
});
|
||||
},
|
||||
setSearchTerm (term: string) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === this.getSelected
|
||||
? {
|
||||
...workspace,
|
||||
searchTerm: term
|
||||
}
|
||||
: workspace);
|
||||
},
|
||||
_addTab ({ uid, tab, content, type, autorun, schema, elementName, elementType }: WorkspaceTab) {
|
||||
if (type === 'query')
|
||||
tabIndex[uid] = tabIndex[uid] ? ++tabIndex[uid] : 1;
|
||||
|
||||
const newTab: WorkspaceTab = {
|
||||
uid: tab,
|
||||
index: type === 'query' ? tabIndex[uid] : null,
|
||||
selected: false,
|
||||
type,
|
||||
schema,
|
||||
elementName,
|
||||
elementType,
|
||||
content: content || '',
|
||||
autorun: !!autorun
|
||||
};
|
||||
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: [...workspace.tabs, newTab]
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
_replaceTab ({ uid, tab: tUid, type, schema, content, elementName, elementType }: WorkspaceTab) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.map(tab => {
|
||||
if (tab.uid === tUid)
|
||||
return { ...tab, type, schema, content, elementName, elementType };
|
||||
|
||||
return tab;
|
||||
})
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
newTab ({ uid, content, type, autorun, schema, elementName, elementType }: WorkspaceTab) {
|
||||
let tabUid;
|
||||
const workspaceTabs = (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid);
|
||||
|
||||
switch (type) {
|
||||
case 'new-table':
|
||||
case 'new-trigger':
|
||||
case 'new-trigger-function':
|
||||
case 'new-function':
|
||||
case 'new-routine':
|
||||
case 'new-scheduler':
|
||||
tabUid = uidGen('T');
|
||||
this._addTab({
|
||||
uid,
|
||||
tab: tabUid,
|
||||
content,
|
||||
type,
|
||||
autorun,
|
||||
schema,
|
||||
elementName,
|
||||
elementType
|
||||
});
|
||||
break;
|
||||
case 'temp-data':
|
||||
case 'temp-trigger-props':
|
||||
case 'temp-trigger-function-props':
|
||||
case 'temp-function-props':
|
||||
case 'temp-routine-props':
|
||||
case 'temp-scheduler-props': {
|
||||
const existentTab = workspaceTabs
|
||||
? workspaceTabs.tabs.find(tab =>
|
||||
tab.schema === schema &&
|
||||
tab.elementName === elementName &&
|
||||
tab.elementType === elementType &&
|
||||
[type, type.replace('temp-', '')].includes(tab.type))
|
||||
: false;
|
||||
|
||||
if (existentTab) { // if tab exists
|
||||
tabUid = existentTab.uid;
|
||||
}
|
||||
else {
|
||||
const tempTabs = workspaceTabs ? workspaceTabs.tabs.filter(tab => tab.type.includes('temp-')) : false;
|
||||
|
||||
if (tempTabs && tempTabs.length) { // if temp tab already opened
|
||||
for (const tab of tempTabs) {
|
||||
if (tab.isChanged) {
|
||||
this._replaceTab({ // make permanent a temp table with unsaved changes
|
||||
uid,
|
||||
tab: tab.uid,
|
||||
type: tab.type.replace('temp-', ''),
|
||||
schema: tab.schema,
|
||||
elementName: tab.elementName,
|
||||
elementType: tab.elementType
|
||||
});
|
||||
|
||||
tabUid = uidGen('T');
|
||||
this._addTab({ uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
else {
|
||||
this._replaceTab({ uid, tab: tab.uid, type, schema, elementName, elementType });
|
||||
tabUid = tab.uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
tabUid = uidGen('T');
|
||||
this._addTab({ uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'data':
|
||||
case 'table-props':
|
||||
case 'trigger-props':
|
||||
case 'trigger-function-props':
|
||||
case 'function-props':
|
||||
case 'routine-props':
|
||||
case 'scheduler-props': {
|
||||
const existentTab = workspaceTabs
|
||||
? workspaceTabs.tabs.find(tab =>
|
||||
tab.schema === schema &&
|
||||
tab.elementName === elementName &&
|
||||
tab.elementType === elementType &&
|
||||
[`temp-${type}`, type].includes(tab.type))
|
||||
: false;
|
||||
|
||||
if (existentTab) {
|
||||
this._replaceTab({ uid, tab: existentTab.uid, type, schema, elementName, elementType });
|
||||
tabUid = existentTab.uid;
|
||||
}
|
||||
else {
|
||||
tabUid = uidGen('T');
|
||||
this._addTab({ uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
tabUid = uidGen('T');
|
||||
this._addTab({ uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
break;
|
||||
}
|
||||
|
||||
this.selectTab({ uid, tab: tabUid });
|
||||
},
|
||||
checkSelectedTabExists (uid: string) {
|
||||
const workspace = (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid);
|
||||
const isSelectedExistent = workspace
|
||||
? workspace.tabs.some(tab => tab.uid === workspace.selectedTab)
|
||||
: false;
|
||||
|
||||
if (!isSelectedExistent && workspace.tabs.length)
|
||||
this.selectTab({ uid, tab: workspace.tabs[workspace.tabs.length - 1].uid });
|
||||
},
|
||||
updateTabContent ({ uid, tab, type, schema, content }: WorkspaceTab) {
|
||||
this._replaceTab({ uid, tab, type, schema, content });
|
||||
},
|
||||
renameTabs ({ uid, schema, elementName, elementNewName }: WorkspaceTab) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.map(tab => {
|
||||
if (tab.elementName === elementName && tab.schema === schema) {
|
||||
return {
|
||||
...tab,
|
||||
elementName: elementNewName
|
||||
};
|
||||
}
|
||||
|
||||
return tab;
|
||||
})
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
removeTab ({ uid, tab: tUid }: {uid: string; tab: string}) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.filter(tab => tab.uid !== tUid)
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs);
|
||||
this.checkSelectedTabExists(uid);
|
||||
},
|
||||
removeTabs ({ uid, schema, elementName, elementType }: WorkspaceTab) { // Multiple tabs based on schema and element name
|
||||
if (elementType === 'procedure') elementType = 'routine'; // TODO: pass directly "routine"
|
||||
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.filter(tab =>
|
||||
tab.schema !== schema ||
|
||||
tab.elementName !== elementName ||
|
||||
tab.elementType !== elementType
|
||||
)
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs);
|
||||
this.checkSelectedTabExists(uid);
|
||||
},
|
||||
selectTab ({ uid, tab }: {uid: string; tab: string}) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? { ...workspace, selectedTab: tab }
|
||||
: workspace
|
||||
);
|
||||
},
|
||||
selectNextTab ({ uid }: {uid: string }) {
|
||||
const workspace = (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid);
|
||||
|
||||
let newIndex = workspace.tabs.findIndex(tab => tab.selected || tab.uid === workspace.selectedTab) + 1;
|
||||
|
||||
if (newIndex > workspace.tabs.length -1)
|
||||
newIndex = 0;
|
||||
|
||||
this.selectTab({ uid, tab: workspace.tabs[newIndex].uid });
|
||||
},
|
||||
selectPrevTab ({ uid }: {uid: string }) {
|
||||
const workspace = (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid);
|
||||
|
||||
let newIndex = workspace.tabs.findIndex(tab => tab.selected || tab.uid === workspace.selectedTab) - 1;
|
||||
|
||||
if (newIndex < 0)
|
||||
newIndex = workspace.tabs.length -1;
|
||||
|
||||
this.selectTab({ uid, tab: workspace.tabs[newIndex].uid });
|
||||
},
|
||||
updateTabs ({ uid, tabs }: {uid: string; tabs: WorkspaceTab[]}) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === uid
|
||||
? { ...workspace, tabs }
|
||||
: workspace
|
||||
);
|
||||
persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
setUnsavedChanges ({ uid, tUid, isChanged }: { uid: string; tUid: string; isChanged: boolean }) {
|
||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.map(tab => {
|
||||
if (tab.uid === tUid)
|
||||
return { ...tab, isChanged };
|
||||
|
||||
return tab;
|
||||
})
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -2,10 +2,8 @@
|
||||
"include": [
|
||||
"./tests/**/*",
|
||||
"./src/main/**/*",
|
||||
"./src/renderer/**/*",
|
||||
"./src/common/**/*",
|
||||
"./src/renderer/**/*"
|
||||
],
|
||||
"exclude": ["./src/renderer/libs/ext-language_tools.js"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"target": "es2021",
|
||||
@ -21,7 +19,6 @@
|
||||
"resolveJsonModule": true,
|
||||
"removeComments": true,
|
||||
"paths": {
|
||||
"common/*": ["./src/common/*"],
|
||||
"@/*": ["./src/renderer/*"],
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user