mirror of https://github.com/Fabio286/antares.git
commit
75aa299f8d
|
@ -7,7 +7,7 @@
|
|||
"extends": [
|
||||
"standard",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:vue/recommended"
|
||||
"plugin:vue/vue3-recommended"
|
||||
],
|
||||
"parser": "vue-eslint-parser",
|
||||
"parserOptions": {
|
||||
|
@ -17,6 +17,7 @@
|
|||
"requireConfigFile": false
|
||||
},
|
||||
"plugins": [
|
||||
"vue",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
.DS_Store
|
||||
dist
|
||||
build
|
||||
misc/*
|
||||
!misc/.gitkeep
|
||||
node_modules
|
||||
thumbs.db
|
||||
NOTES.md
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
"sourceMaps": true,
|
||||
"type": "node",
|
||||
"timeout": 1000000
|
||||
},
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Antares SQL is an application based on [Electron.js](https://www.electronjs.org/) that uses [Vue.js](https://vuejs.org/) and [Spectre.css](https://picturepan2.github.io/spectre/) as frontend frameworks.
|
||||
For the build process it takes advantage of [electron-builder](https://www.electron.build/).
|
||||
This application uses [Vuex](https://vuex.vuejs.org/) as application state manager and [electron-store](https://github.com/sindresorhus/electron-store) to save the various settings on disc.
|
||||
This application uses [Pinia🍍](https://pinia.vuejs.org/) as application state manager and [electron-store](https://github.com/sindresorhus/electron-store) to save the various settings on disc.
|
||||
This guide aims to provide useful information and guidelines to everyone wants to contribute with this open-source project.
|
||||
For every other question related to this project please [contact me](https://github.com/Fabio286).
|
||||
|
||||
|
@ -14,7 +14,7 @@ The main files of the application are located inside `src` folder and are groupp
|
|||
|
||||
This folder contains small libraries, classes and objects. The purpose of `common` folder is to group together utilities used by **renderer** and **main** processes.
|
||||
Noteworthy is the `customizations` folder that contains clients related customizations. Those settings are merged with `default.js` that lists every option.
|
||||
Client related customizations are stored on Vuex and can be accessed by `customizations` property of current workspace object, or importing `common/customizations`.
|
||||
Client related customizations are stored on Pinia and can be accessed by `customizations` property of current workspace object, or importing `common/customizations`.
|
||||
|
||||
An use case of customizations object can be the following:
|
||||
|
||||
|
@ -62,12 +62,6 @@ The command to build Antares SQL locally is `npm run build:local`.
|
|||
- [Order of words in component names](https://vuejs.org/v2/style-guide/#Order-of-words-in-component-names-strongly-recommended).
|
||||
- **kebab-case** in templates for property and event names.
|
||||
|
||||
### Vuex
|
||||
|
||||
- **snake_case** for state names.
|
||||
- **camelCase** for getter and action names.
|
||||
- **SNAKE_CASE (all caps)** for mutation names.
|
||||
|
||||
### Code Style
|
||||
|
||||
The project includes [ESlint](https://eslint.org/) and [StyleLint](https://stylelint.io/) config files with style rules. I recommend to set the lint on-save option in your code editor.
|
||||
|
|
32
package.json
32
package.json
|
@ -18,8 +18,10 @@
|
|||
"rebuild:electron": "rimraf ./dist && npm run postinstall",
|
||||
"release": "standard-version",
|
||||
"release:pre": "npm run release -- --prerelease alpha",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"test": "npm run compile && node tests/app.spec.js",
|
||||
"devtools:install": "node scripts/devtoolsInstaller",
|
||||
"postinstall": "electron-builder install-app-deps && npm run devtools:install",
|
||||
"test": "npm run compile && npm run test:dry",
|
||||
"test:dry": "xvfb-maybe -- playwright test",
|
||||
"lint": "eslint . --ext .js,.vue && stylelint \"./src/**/*.{css,scss,sass,vue}\"",
|
||||
"lint:fix": "eslint . --ext .js,.vue --fix && stylelint \"./src/**/*.{css,scss,sass,vue}\" --fix",
|
||||
"contributors:add": "all-contributors add",
|
||||
|
@ -27,6 +29,9 @@
|
|||
},
|
||||
"author": "Fabio Di Stasio <fabio286@gmail.com>",
|
||||
"main": "./dist/main.js",
|
||||
"antares": {
|
||||
"devtoolsId": "nhdogjmejiglipccpnnnanhbledajbpd"
|
||||
},
|
||||
"build": {
|
||||
"appId": "com.fabio286.antares",
|
||||
"artifactName": "${productName}-${version}-${os}_${arch}.${ext}",
|
||||
|
@ -115,7 +120,7 @@
|
|||
"electron-store": "^8.0.1",
|
||||
"electron-updater": "^4.6.1",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"faker": "^5.5.3",
|
||||
"encoding": "^0.1.13",
|
||||
"leaflet": "^1.7.1",
|
||||
"marked": "^4.0.0",
|
||||
"moment": "^2.29.1",
|
||||
|
@ -123,24 +128,27 @@
|
|||
"pg": "^8.7.1",
|
||||
"pg-query-stream": "^4.2.3",
|
||||
"pgsql-ast-parser": "^7.2.1",
|
||||
"pinia": "^2.0.13",
|
||||
"source-map-support": "^0.5.20",
|
||||
"spectre.css": "^0.5.9",
|
||||
"sql-formatter": "^4.0.2",
|
||||
"ssh2-promise": "^1.0.2",
|
||||
"v-mask": "^2.3.0",
|
||||
"vue-i18n": "^8.26.5",
|
||||
"vuedraggable": "^2.24.3",
|
||||
"vuex": "^3.6.2"
|
||||
"vue": "^3.2.33",
|
||||
"vue-i18n": "^9.1.9",
|
||||
"vuedraggable": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.15.7",
|
||||
"@babel/preset-env": "^7.15.8",
|
||||
"@babel/preset-typescript": "^7.16.7",
|
||||
"@playwright/test": "^1.21.1",
|
||||
"@types/better-sqlite3": "^7.5.0",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/pg": "^8.6.5",
|
||||
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"@vue/compiler-sfc": "^3.2.33",
|
||||
"all-contributors-cli": "^6.20.0",
|
||||
"babel-loader": "^8.2.3",
|
||||
"chalk": "^4.1.2",
|
||||
|
@ -148,7 +156,6 @@
|
|||
"css-loader": "^6.5.0",
|
||||
"electron": "^17.0.1",
|
||||
"electron-builder": "^22.14.11",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
|
@ -159,7 +166,8 @@
|
|||
"html-webpack-plugin": "^5.5.0",
|
||||
"mini-css-extract-plugin": "~2.4.5",
|
||||
"node-loader": "^2.0.0",
|
||||
"playwright": "^1.18.1",
|
||||
"playwright": "^1.21.1",
|
||||
"playwright-core": "^1.21.1",
|
||||
"progress-webpack-plugin": "^1.0.12",
|
||||
"rimraf": "^3.0.2",
|
||||
"sass": "^1.42.1",
|
||||
|
@ -172,12 +180,12 @@
|
|||
"tree-kill": "^1.2.2",
|
||||
"ts-loader": "^9.2.8",
|
||||
"typescript": "^4.6.3",
|
||||
"vue": "^2.6.14",
|
||||
"unzip-crx-3": "^0.2.0",
|
||||
"vue-eslint-parser": "^8.3.0",
|
||||
"vue-loader": "^15.9.8",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"vue-loader": "^16.8.3",
|
||||
"webpack": "^5.60.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-dev-server": "^4.4.0"
|
||||
"webpack-dev-server": "^4.4.0",
|
||||
"xvfb-maybe": "^0.2.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
process.env.NODE_ENV = 'development';
|
||||
// process.env.ELECTRON_ENABLE_LOGGING = true
|
||||
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = false;
|
||||
|
||||
const chalk = require('chalk');
|
||||
const electron = require('electron');
|
||||
|
@ -19,7 +20,7 @@ let manualRestart = null;
|
|||
const remoteDebugging = process.argv.includes('--remote-debug');
|
||||
|
||||
if (remoteDebugging) {
|
||||
// disable dvtools open in electron
|
||||
// disable devtools open in electron
|
||||
process.env.RENDERER_REMOTE_DEBUGGING = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// @ts-check
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
const unzip = require('unzip-crx-3');
|
||||
const { antares } = require('../package.json');
|
||||
|
||||
const extensionID = antares.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`;
|
||||
const fileStream = fs.createWriteStream(filePath);
|
||||
|
||||
const downloadFile = url => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = https.get(url);
|
||||
|
||||
request.on('response', response => {
|
||||
if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
||||
return downloadFile(response.headers.location)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
}
|
||||
|
||||
response.pipe(fileStream);
|
||||
|
||||
response.on('close', () => {
|
||||
console.log('Devtools download completed!');
|
||||
resolve();
|
||||
});
|
||||
response.on('error', reject);
|
||||
});
|
||||
request.on('error', reject);
|
||||
request.end();
|
||||
});
|
||||
};
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
await downloadFile(fileUrl);
|
||||
await unzip(filePath, destFolder);
|
||||
fs.unlinkSync(filePath);
|
||||
fs.unlinkSync(`${destFolder}/package.json`);// <- Avoid to display annoyng npm script in vscode
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
})();
|
|
@ -43,4 +43,4 @@ export function mimeFromHex (hex) {
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
*/
|
||||
export function uidGen (prefix) {
|
||||
return (prefix ? `${prefix}:` : '') + Math.random().toString(36).substr(2, 9).toUpperCase();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ export default () => {
|
|||
event.returnValue = key;
|
||||
});
|
||||
|
||||
ipcMain.handle('showOpenDialog', (event, options) => {
|
||||
ipcMain.handle('show-open-dialog', (event, options) => {
|
||||
return dialog.showOpenDialog(options);
|
||||
});
|
||||
|
||||
|
|
|
@ -135,9 +135,6 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||
|
||||
await connection.connect();
|
||||
|
||||
// TODO: temporary
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
const structure = await connection.getStructure(new Set());
|
||||
|
||||
connections[conn.uid] = connection;
|
||||
|
|
|
@ -47,22 +47,8 @@ async function createMainWindow () {
|
|||
remoteMain.enable(window.webContents);
|
||||
|
||||
try {
|
||||
if (isDevelopment) {
|
||||
const { default: installExtension, VUEJS3_DEVTOOLS } = require('electron-devtools-installer');
|
||||
const options = {
|
||||
loadExtensionOptions: { allowFileAccess: true }
|
||||
};
|
||||
|
||||
try {
|
||||
const name = await installExtension(VUEJS3_DEVTOOLS, options);
|
||||
console.log(`Added Extension: ${name}`);
|
||||
}
|
||||
catch (err) {
|
||||
console.log('An error occurred: ', err);
|
||||
}
|
||||
|
||||
if (isDevelopment)
|
||||
await window.loadURL('http://localhost:9080');
|
||||
}
|
||||
else {
|
||||
const indexPath = path.resolve(__dirname, 'index.html');
|
||||
await window.loadFile(indexPath);
|
||||
|
@ -109,8 +95,8 @@ else {
|
|||
mainWindow = await createMainWindow();
|
||||
createAppMenu();
|
||||
|
||||
// if (isDevelopment)
|
||||
// mainWindow.webContents.openDevTools();
|
||||
if (isDevelopment)
|
||||
mainWindow.webContents.openDevTools();
|
||||
|
||||
process.on('uncaughtException', error => {
|
||||
mainWindow.webContents.send('unhandled-exception', error);
|
||||
|
@ -120,6 +106,14 @@ else {
|
|||
mainWindow.webContents.send('unhandled-exception', error);
|
||||
});
|
||||
});
|
||||
|
||||
app.on('browser-window-created', (event, window) => {
|
||||
if (isDevelopment) {
|
||||
const { antares } = require('../../package.json');
|
||||
const extensionPath = path.resolve(__dirname, `../../misc/${antares.devtoolsId}`);
|
||||
window.webContents.session.loadExtension(extensionPath, { allowFileAccess: true }).catch(console.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createAppMenu () {
|
||||
|
|
|
@ -25,37 +25,56 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ipcRenderer } from 'electron';
|
||||
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';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
TheTitleBar: () => import(/* webpackChunkName: "TheTitleBar" */'@/components/TheTitleBar'),
|
||||
TheSettingBar: () => import(/* webpackChunkName: "TheSettingBar" */'@/components/TheSettingBar'),
|
||||
TheFooter: () => import(/* webpackChunkName: "TheFooter" */'@/components/TheFooter'),
|
||||
TheNotificationsBoard: () => import(/* webpackChunkName: "TheNotificationsBoard" */'@/components/TheNotificationsBoard'),
|
||||
Workspace: () => import(/* webpackChunkName: "Workspace" */'@/components/Workspace'),
|
||||
WorkspaceAddConnectionPanel: () => import(/* webpackChunkName: "WorkspaceAddConnectionPanel" */'@/components/WorkspaceAddConnectionPanel'),
|
||||
ModalSettings: () => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings'),
|
||||
TheScratchpad: () => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad'),
|
||||
BaseTextEditor: () => import(/* webpackChunkName: "BaseTextEditor" */'@/components/BaseTextEditor')
|
||||
TheTitleBar: defineAsyncComponent(() => import(/* webpackChunkName: "TheTitleBar" */'@/components/TheTitleBar')),
|
||||
TheSettingBar,
|
||||
TheFooter: defineAsyncComponent(() => import(/* webpackChunkName: "TheFooter" */'@/components/TheFooter')),
|
||||
TheNotificationsBoard: defineAsyncComponent(() => import(/* webpackChunkName: "TheNotificationsBoard" */'@/components/TheNotificationsBoard')),
|
||||
Workspace: defineAsyncComponent(() => import(/* webpackChunkName: "Workspace" */'@/components/Workspace')),
|
||||
WorkspaceAddConnectionPanel: defineAsyncComponent(() => import(/* webpackChunkName: "WorkspaceAddConnectionPanel" */'@/components/WorkspaceAddConnectionPanel')),
|
||||
ModalSettings: defineAsyncComponent(() => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings')),
|
||||
TheScratchpad: defineAsyncComponent(() => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad')),
|
||||
BaseTextEditor: defineAsyncComponent(() => import(/* webpackChunkName: "BaseTextEditor" */'@/components/BaseTextEditor'))
|
||||
},
|
||||
data () {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
isLoading: 'application/isLoading',
|
||||
isSettingModal: 'application/isSettingModal',
|
||||
isScratchpad: 'application/isScratchpad',
|
||||
connections: 'connections/getConnections',
|
||||
applicationTheme: 'settings/getApplicationTheme',
|
||||
disableBlur: 'settings/getDisableBlur',
|
||||
isUnsavedDiscardModal: 'workspaces/isUnsavedDiscardModal'
|
||||
})
|
||||
setup () {
|
||||
const applicationStore = useApplicationStore();
|
||||
const connectionsStore = useConnectionsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const {
|
||||
isLoading,
|
||||
isSettingModal,
|
||||
isScratchpad
|
||||
} = storeToRefs(applicationStore);
|
||||
const { connections } = storeToRefs(connectionsStore);
|
||||
const { applicationTheme, disableBlur } = storeToRefs(settingsStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { checkVersionUpdate } = applicationStore;
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
isSettingModal,
|
||||
isScratchpad,
|
||||
checkVersionUpdate,
|
||||
connections,
|
||||
applicationTheme,
|
||||
disableBlur,
|
||||
selectedWorkspace
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
ipcRenderer.send('check-for-updates');
|
||||
|
@ -97,12 +116,6 @@ export default {
|
|||
node = node.parentNode;
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
showNewConnModal: 'application/showNewConnModal',
|
||||
checkVersionUpdate: 'application/checkVersionUpdate'
|
||||
})
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,44 +1,48 @@
|
|||
<template>
|
||||
<div class="modal active" :class="modalSizeClass">
|
||||
<a class="modal-overlay" @click="hideModal" />
|
||||
<div class="modal-container">
|
||||
<div v-if="hasHeader" class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<slot name="header" />
|
||||
</div>
|
||||
<a class="btn btn-clear float-right" @click="hideModal" />
|
||||
</div>
|
||||
<div v-if="hasDefault" class="modal-header">
|
||||
<div class="modal-title h6">
|
||||
<slot />
|
||||
</div>
|
||||
<a class="btn btn-clear float-right" @click="hideModal" />
|
||||
</div>
|
||||
<div v-if="hasBody" class="modal-body">
|
||||
<a
|
||||
v-if="!hasHeader && !hasDefault"
|
||||
class="btn btn-clear float-right"
|
||||
@click="hideModal"
|
||||
/>
|
||||
<div class="content">
|
||||
<slot name="body" />
|
||||
<div class="dummy-wrapper">
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active" :class="modalSizeClass">
|
||||
<a class="modal-overlay" @click="hideModal" />
|
||||
<div class="modal-container">
|
||||
<div v-if="hasHeader" class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<slot name="header" />
|
||||
</div>
|
||||
<a class="btn btn-clear float-right" @click="hideModal" />
|
||||
</div>
|
||||
<div v-if="hasDefault" class="modal-header">
|
||||
<div class="modal-title h6">
|
||||
<slot />
|
||||
</div>
|
||||
<a class="btn btn-clear float-right" @click="hideModal" />
|
||||
</div>
|
||||
<div v-if="hasBody" class="modal-body pb-0">
|
||||
<a
|
||||
v-if="!hasHeader && !hasDefault"
|
||||
class="btn btn-clear float-right"
|
||||
@click="hideModal"
|
||||
/>
|
||||
<div class="content">
|
||||
<slot name="body" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!hideFooter" class="modal-footer">
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
@click.stop="confirmModal"
|
||||
>
|
||||
{{ confirmText || $t('word.confirm') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-link"
|
||||
@click="hideModal"
|
||||
>
|
||||
{{ cancelText || $t('word.cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!hideFooter" class="modal-footer">
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
@click.stop="confirmModal"
|
||||
>
|
||||
{{ confirmText || $t('word.confirm') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-link"
|
||||
@click="hideModal"
|
||||
>
|
||||
{{ cancelText || $t('word.cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -58,6 +62,7 @@ export default {
|
|||
confirmText: String,
|
||||
cancelText: String
|
||||
},
|
||||
emits: ['confirm', 'hide'],
|
||||
computed: {
|
||||
hasHeader () {
|
||||
return !!this.$slots.header;
|
||||
|
@ -81,7 +86,7 @@ export default {
|
|||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -21,6 +21,7 @@ export default {
|
|||
props: {
|
||||
contextEvent: MouseEvent
|
||||
},
|
||||
emits: ['close-context'],
|
||||
data () {
|
||||
return {
|
||||
contextSize: null,
|
||||
|
@ -61,7 +62,7 @@ export default {
|
|||
if (this.$refs.contextContent)
|
||||
this.contextSize = this.$refs.contextContent.getBoundingClientRect();
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -27,6 +27,7 @@ export default {
|
|||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['close'],
|
||||
data () {
|
||||
return {
|
||||
isExpanded: false
|
||||
|
|
|
@ -11,13 +11,15 @@
|
|||
|
||||
<script>
|
||||
import * as ace from 'ace-builds';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import 'ace-builds/webpack-resolver';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
|
||||
export default {
|
||||
name: 'BaseTextEditor',
|
||||
props: {
|
||||
value: String,
|
||||
modelValue: String,
|
||||
mode: { type: String, default: 'text' },
|
||||
editorClass: { type: String, default: '' },
|
||||
autoFocus: { type: Boolean, default: false },
|
||||
|
@ -25,20 +27,30 @@ export default {
|
|||
showLineNumbers: { type: Boolean, default: true },
|
||||
height: { type: Number, default: 200 }
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup () {
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const {
|
||||
editorTheme,
|
||||
editorFontSize,
|
||||
autoComplete,
|
||||
lineWrap
|
||||
} = storeToRefs(settingsStore);
|
||||
|
||||
return {
|
||||
editorTheme,
|
||||
editorFontSize,
|
||||
autoComplete,
|
||||
lineWrap
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
editor: null,
|
||||
id: null
|
||||
id: uidGen()
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
editorTheme: 'settings/getEditorTheme',
|
||||
editorFontSize: 'settings/getEditorFontSize',
|
||||
autoComplete: 'settings/getAutoComplete',
|
||||
lineWrap: 'settings/getLineWrap'
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
mode () {
|
||||
if (this.editor)
|
||||
|
@ -76,14 +88,11 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.id = this._uid;
|
||||
},
|
||||
mounted () {
|
||||
this.editor = ace.edit(`editor-${this.id}`, {
|
||||
mode: `ace/mode/${this.mode}`,
|
||||
theme: `ace/theme/${this.editorTheme}`,
|
||||
value: this.value || '',
|
||||
value: this.modelValue || '',
|
||||
fontSize: '14px',
|
||||
printMargin: false,
|
||||
readOnly: this.readOnly,
|
||||
|
@ -100,7 +109,7 @@ export default {
|
|||
|
||||
this.editor.session.on('change', () => {
|
||||
const content = this.editor.getValue();
|
||||
this.$emit('update:value', content);
|
||||
this.$emit('update:modelValue', content);
|
||||
});
|
||||
|
||||
if (this.autoFocus) {
|
||||
|
|
|
@ -22,6 +22,7 @@ export default {
|
|||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['close'],
|
||||
data () {
|
||||
return {
|
||||
isVisible: false
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
<i class="mdi mdi-folder-open mr-1" />{{ message }}
|
||||
</span>
|
||||
<span class="text-ellipsis file-uploader-value">
|
||||
{{ value | lastPart }}
|
||||
{{ lastPart(modelValue) }}
|
||||
</span>
|
||||
<i
|
||||
v-if="value.length"
|
||||
v-if="modelValue.length"
|
||||
class="file-uploader-reset mdi mdi-close"
|
||||
@click.prevent="clear"
|
||||
/>
|
||||
|
@ -25,26 +25,17 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'BaseUploadInput',
|
||||
filters: {
|
||||
lastPart (string) {
|
||||
if (!string) return '';
|
||||
|
||||
string = string.split(/[/\\]+/).pop();
|
||||
if (string.length >= 19)
|
||||
string = `...${string.slice(-19)}`;
|
||||
return string;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
message: {
|
||||
default: 'Browse',
|
||||
type: String
|
||||
},
|
||||
value: {
|
||||
modelValue: {
|
||||
default: '',
|
||||
type: String
|
||||
}
|
||||
},
|
||||
emits: ['change', 'clear'],
|
||||
data () {
|
||||
return {
|
||||
id: null
|
||||
|
@ -56,6 +47,14 @@ export default {
|
|||
methods: {
|
||||
clear () {
|
||||
this.$emit('clear');
|
||||
},
|
||||
lastPart (string) {
|
||||
if (!string) return '';
|
||||
|
||||
string = string.split(/[/\\]+/).pop();
|
||||
if (string.length >= 19)
|
||||
string = `...${string.slice(-19)}`;
|
||||
return string;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ export default {
|
|||
mounted () {
|
||||
this.setScrollElement();
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
this.localScrollElement.removeEventListener('scroll', this.checkScrollPosition);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
<ForeignKeySelect
|
||||
v-else-if="foreignKeys.includes(field.name)"
|
||||
ref="formInput"
|
||||
v-model="selectedValue"
|
||||
class="form-select"
|
||||
:value.sync="selectedValue"
|
||||
:key-usage="getKeyUsage(field.name)"
|
||||
:disabled="!isChecked"
|
||||
/>
|
||||
|
@ -105,7 +105,6 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { VueMaskDirective } from 'v-mask';
|
||||
import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
import ForeignKeySelect from '@/components/ForeignKeySelect';
|
||||
|
@ -117,9 +116,6 @@ export default {
|
|||
ForeignKeySelect,
|
||||
BaseUploadInput
|
||||
},
|
||||
directives: {
|
||||
mask: VueMaskDirective
|
||||
},
|
||||
props: {
|
||||
type: String,
|
||||
field: Object,
|
||||
|
@ -129,6 +125,7 @@ export default {
|
|||
fieldLength: Number,
|
||||
fieldObj: Object
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
data () {
|
||||
return {
|
||||
localType: null,
|
||||
|
@ -244,7 +241,7 @@ export default {
|
|||
this.selectedValue = '';
|
||||
},
|
||||
onChange () {
|
||||
this.$emit('update:value', {
|
||||
this.$emit('update:modelValue', {
|
||||
group: this.selectedGroup,
|
||||
method: this.selectedMethod,
|
||||
params: this.methodParams,
|
||||
|
|
|
@ -6,53 +6,55 @@
|
|||
@change="onChange"
|
||||
@blur="$emit('blur')"
|
||||
>
|
||||
<option v-if="!isValidDefault" :value="value">
|
||||
{{ value === null ? 'NULL' : value }}
|
||||
<option v-if="!isValidDefault" :value="modelValue">
|
||||
{{ modelValue === null ? 'NULL' : modelValue }}
|
||||
</option>
|
||||
<option
|
||||
v-for="row in foreignList"
|
||||
:key="row.foreign_column"
|
||||
:value="row.foreign_column"
|
||||
:selected="row.foreign_column === value"
|
||||
:selected="row.foreign_column === modelValue"
|
||||
>
|
||||
{{ row.foreign_column }} {{ 'foreign_description' in row ? ` - ${row.foreign_description}` : '' | cutText }}
|
||||
{{ row.foreign_column }} {{ cutText('foreign_description' in row ? ` - ${row.foreign_description}` : '') }}
|
||||
</option>
|
||||
</select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { TEXT, LONG_TEXT } from 'common/fieldTypes';
|
||||
export default {
|
||||
name: 'ForeignKeySelect',
|
||||
filters: {
|
||||
cutText (val) {
|
||||
if (typeof val !== 'string') return val;
|
||||
return val.length > 15 ? `${val.substring(0, 15)}...` : val;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: [String, Number],
|
||||
modelValue: [String, Number],
|
||||
keyUsage: Object,
|
||||
size: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['update:modelValue', 'blur'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
return { addNotification, selectedWorkspace };
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
foreignList: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected'
|
||||
}),
|
||||
isValidDefault () {
|
||||
if (!this.foreignList.length) return true;
|
||||
if (this.value === null) return false;
|
||||
return this.foreignList.some(foreign => foreign.foreign_column.toString() === this.value.toString());
|
||||
if (this.modelValue === null) return false;
|
||||
return this.foreignList.some(foreign => foreign.foreign_column.toString() === this.modelValue.toString());
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
|
@ -93,11 +95,12 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
onChange () {
|
||||
this.$emit('update:value', this.$refs.editField.value);
|
||||
this.$emit('update:modelValue', this.$refs.editField.value);
|
||||
},
|
||||
cutText (val) {
|
||||
if (typeof val !== 'string') return val;
|
||||
return val.length > 15 ? `${val.substring(0, 15)}...` : val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,61 +1,64 @@
|
|||
<template>
|
||||
<div class="modal active modal-sm">
|
||||
<a class="modal-overlay" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-key-variant mr-1" /> {{ $t('word.credentials') }}
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active modal-sm">
|
||||
<a class="modal-overlay" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-key-variant mr-1" /> {{ $t('word.credentials') }}
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="credentials.user"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
v-model="credentials.password"
|
||||
class="form-input"
|
||||
type="password"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="credentials.user"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
v-model="credentials.password"
|
||||
class="form-input"
|
||||
type="password"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary mr-2" @click.stop="sendCredentials">
|
||||
{{ $t('word.send') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary mr-2" @click.stop="sendCredentials">
|
||||
{{ $t('word.send') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ModalAskCredentials',
|
||||
emits: ['close-asking', 'credentials'],
|
||||
data () {
|
||||
return {
|
||||
credentials: {
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
class="input-group-addon field-type cut-text"
|
||||
:class="typeClass(parameter.type)"
|
||||
>
|
||||
{{ parameter.type }} {{ parameter.length | wrapNumber }}
|
||||
{{ parameter.type }} {{ wrapNumber(parameter.length) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -56,16 +56,11 @@ export default {
|
|||
components: {
|
||||
ConfirmModal
|
||||
},
|
||||
filters: {
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
localRoutine: Object,
|
||||
client: String
|
||||
},
|
||||
emits: ['confirm', 'close'],
|
||||
data () {
|
||||
return {
|
||||
values: {}
|
||||
|
@ -83,7 +78,7 @@ export default {
|
|||
this.$refs.firstInput[0].focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
|
@ -122,6 +117,10 @@ export default {
|
|||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -26,10 +26,11 @@ export default {
|
|||
components: {
|
||||
ConfirmModal
|
||||
},
|
||||
emits: ['confirm', 'close'],
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,72 +1,76 @@
|
|||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-database-edit mr-1" />
|
||||
<span class="cut-text">{{ $t('message.editSchema') }}</span>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-database-edit mr-1" />
|
||||
<span class="cut-text">{{ $t('message.editSchema') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.name') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
v-model="database.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
required
|
||||
:placeholder="$t('message.schemaName')"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.collation') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<select
|
||||
ref="firstInput"
|
||||
v-model="database.collation"
|
||||
class="form-select"
|
||||
>
|
||||
<option
|
||||
v-for="collation in collations"
|
||||
:key="collation.id"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.name') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
v-model="database.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
required
|
||||
:placeholder="$t('message.schemaName')"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.collation') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<select
|
||||
ref="firstInput"
|
||||
v-model="database.collation"
|
||||
class="form-select"
|
||||
>
|
||||
<option
|
||||
v-for="collation in collations"
|
||||
:key="collation.id"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary mr-2" @click.stop="updateSchema">
|
||||
{{ $t('word.update') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary mr-2" @click.stop="updateSchema">
|
||||
{{ $t('word.update') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
|
||||
export default {
|
||||
|
@ -74,6 +78,22 @@ export default {
|
|||
props: {
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: ['close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, getDatabaseVariable } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getDatabaseVariable
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
database: {
|
||||
|
@ -84,11 +104,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
getDatabaseVariable: 'workspaces/getDatabaseVariable'
|
||||
}),
|
||||
collations () {
|
||||
return this.getWorkspace(this.selectedWorkspace).collations;
|
||||
},
|
||||
|
@ -124,13 +139,10 @@ export default {
|
|||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
async updateSchema () {
|
||||
if (this.database.collation !== this.database.prevCollation) {
|
||||
try {
|
||||
|
|
|
@ -1,287 +1,310 @@
|
|||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-database-arrow-down mr-1" />
|
||||
<span class="cut-text">{{ $t('message.exportSchema') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('message.directoryPath') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<fieldset class="input-group">
|
||||
<input
|
||||
v-model="basePath"
|
||||
class="form-input"
|
||||
type="text"
|
||||
required
|
||||
readonly
|
||||
:placeholder="$t('message.schemaName')"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary input-group-btn"
|
||||
@click.prevent="openPathDialog"
|
||||
>
|
||||
{{ $t('word.change') }}
|
||||
</button>
|
||||
</fieldset>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-database-arrow-down mr-1" />
|
||||
<span class="cut-text">{{ $t('message.exportSchema') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
|
||||
<div class="columns export-options">
|
||||
<div class="column col-8 left">
|
||||
<div class="columns mb-2">
|
||||
<div class="column col-auto d-flex text-italic ">
|
||||
<i class="mdi mdi-file-document-outline mr-2" />
|
||||
{{ filename }}
|
||||
<div class="modal-body pb-0">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('message.directoryPath') }}</label>
|
||||
</div>
|
||||
|
||||
<div class="column col-auto col-ml-auto ">
|
||||
<button
|
||||
class="btn btn-dark btn-sm"
|
||||
:title="$t('word.refresh')"
|
||||
@click="refresh"
|
||||
>
|
||||
<i class="mdi mdi-database-refresh" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm"
|
||||
:title="$t('message.uncheckAllTables')"
|
||||
:disabled="isRefreshing"
|
||||
@click="uncheckAllTables"
|
||||
>
|
||||
<i class="mdi mdi-file-tree-outline" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm"
|
||||
:title="$t('message.checkAllTables')"
|
||||
:disabled="isRefreshing"
|
||||
@click="checkAllTables"
|
||||
>
|
||||
<i class="mdi mdi-file-tree" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workspace-query-results">
|
||||
<div ref="table" class="table table-hover">
|
||||
<div class="thead">
|
||||
<div class="tr text-center">
|
||||
<div class="th no-border" style="width: 50%;" />
|
||||
<div class="th no-border">
|
||||
<label
|
||||
class="form-checkbox m-0 px-2 form-inline"
|
||||
@click.prevent="toggleAllTablesOption('includeStructure')"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:indeterminate.prop="includeStructureStatus === 2"
|
||||
:checked.prop="!!includeStructureStatus"
|
||||
>
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="th no-border">
|
||||
<label
|
||||
class="form-checkbox m-0 px-2 form-inline"
|
||||
@click.prevent="toggleAllTablesOption('includeContent')"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:indeterminate.prop="includeContentStatus === 2"
|
||||
:checked.prop="!!includeContentStatus"
|
||||
>
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="th no-border">
|
||||
<label
|
||||
class="form-checkbox m-0 px-2 form-inline"
|
||||
@click.prevent="toggleAllTablesOption('includeDropStatement')"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:indeterminate.prop="includeDropStatementStatus === 2"
|
||||
:checked.prop="!!includeDropStatementStatus"
|
||||
>
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tr">
|
||||
<div class="th" style="width: 50%;">
|
||||
<div class="table-column-title">
|
||||
<span>{{ $t('word.table') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th text-center">
|
||||
<div class="table-column-title">
|
||||
<span>{{ $t('word.structure') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th text-center">
|
||||
<div class="table-column-title">
|
||||
<span>{{ $t('word.content') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th text-center">
|
||||
<div class="table-column-title">
|
||||
<span>{{ $t('word.drop') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tbody">
|
||||
<div
|
||||
v-for="item in tables"
|
||||
:key="item.name"
|
||||
class="tr"
|
||||
<div class="col-9">
|
||||
<fieldset class="input-group">
|
||||
<input
|
||||
v-model="basePath"
|
||||
class="form-input"
|
||||
type="text"
|
||||
required
|
||||
readonly
|
||||
:placeholder="$t('message.schemaName')"
|
||||
>
|
||||
<div class="td">
|
||||
{{ item.table }}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary input-group-btn"
|
||||
@click.prevent="openPathDialog"
|
||||
>
|
||||
{{ $t('word.change') }}
|
||||
</button>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns export-options">
|
||||
<div class="column col-8 left">
|
||||
<div class="columns mb-2">
|
||||
<div class="column col-auto d-flex text-italic ">
|
||||
<i class="mdi mdi-file-document-outline mr-2" />
|
||||
{{ filename }}
|
||||
</div>
|
||||
|
||||
<div class="column col-auto col-ml-auto ">
|
||||
<button
|
||||
class="btn btn-dark btn-sm"
|
||||
:title="$t('word.refresh')"
|
||||
@click="refresh"
|
||||
>
|
||||
<i class="mdi mdi-database-refresh" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm mx-1"
|
||||
:title="$t('message.uncheckAllTables')"
|
||||
:disabled="isRefreshing"
|
||||
@click="uncheckAllTables"
|
||||
>
|
||||
<i class="mdi mdi-file-tree-outline" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm"
|
||||
:title="$t('message.checkAllTables')"
|
||||
:disabled="isRefreshing"
|
||||
@click="checkAllTables"
|
||||
>
|
||||
<i class="mdi mdi-file-tree" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workspace-query-results">
|
||||
<div ref="table" class="table table-hover">
|
||||
<div class="thead">
|
||||
<div class="tr text-center">
|
||||
<div class="th no-border" style="width: 50%;" />
|
||||
<div class="th no-border">
|
||||
<label
|
||||
class="form-checkbox m-0 px-2 form-inline"
|
||||
@click.prevent="toggleAllTablesOption('includeStructure')"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:indeterminate="includeStructureStatus === 2"
|
||||
:checked="!!includeStructureStatus"
|
||||
>
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="th no-border">
|
||||
<label
|
||||
class="form-checkbox m-0 px-2 form-inline"
|
||||
@click.prevent="toggleAllTablesOption('includeContent')"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:indeterminate="includeContentStatus === 2"
|
||||
:checked="!!includeContentStatus"
|
||||
>
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="th no-border">
|
||||
<label
|
||||
class="form-checkbox m-0 px-2 form-inline"
|
||||
@click.prevent="toggleAllTablesOption('includeDropStatement')"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:indeterminate="includeDropStatementStatus === 2"
|
||||
:checked="!!includeDropStatementStatus"
|
||||
>
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td text-center">
|
||||
<label class="form-checkbox m-0 px-2 form-inline">
|
||||
<input
|
||||
v-model="item.includeStructure"
|
||||
type="checkbox"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
<div class="tr">
|
||||
<div class="th" style="width: 50%;">
|
||||
<div class="table-column-title">
|
||||
<span>{{ $t('word.table') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th text-center">
|
||||
<div class="table-column-title">
|
||||
<span>{{ $t('word.structure') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th text-center">
|
||||
<div class="table-column-title">
|
||||
<span>{{ $t('word.content') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="th text-center">
|
||||
<div class="table-column-title">
|
||||
<span>{{ $t('word.drop') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="td text-center">
|
||||
<label class="form-checkbox m-0 px-2 form-inline">
|
||||
<input
|
||||
v-model="item.includeContent"
|
||||
type="checkbox"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="td text-center">
|
||||
<label class="form-checkbox m-0 px-2 form-inline">
|
||||
<input
|
||||
v-model="item.includeDropStatement"
|
||||
type="checkbox"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="tbody">
|
||||
<div
|
||||
v-for="item in tables"
|
||||
:key="item.name"
|
||||
class="tr"
|
||||
>
|
||||
<div class="td">
|
||||
{{ item.table }}
|
||||
</div>
|
||||
<div class="td text-center">
|
||||
<label class="form-checkbox m-0 px-2 form-inline">
|
||||
<input
|
||||
v-model="item.includeStructure"
|
||||
type="checkbox"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="td text-center">
|
||||
<label class="form-checkbox m-0 px-2 form-inline">
|
||||
<input
|
||||
v-model="item.includeContent"
|
||||
type="checkbox"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="td text-center">
|
||||
<label class="form-checkbox m-0 px-2 form-inline">
|
||||
<input
|
||||
v-model="item.includeDropStatement"
|
||||
type="checkbox"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-4">
|
||||
<h5 class="h5">
|
||||
{{ $t('word.options') }}
|
||||
</h5>
|
||||
<span class="h6">{{ $t('word.includes') }}:</span>
|
||||
<label
|
||||
v-for="(_, key) in options.includes"
|
||||
:key="key"
|
||||
class="form-checkbox"
|
||||
>
|
||||
<input v-model="options.includes[key]" type="checkbox"><i class="form-icon" /> {{ $tc(`word.${key}`, 2) }}
|
||||
</label>
|
||||
<div v-if="customizations.exportByChunks">
|
||||
<div class="h6 mt-4 mb-2">
|
||||
{{ $t('message.newInserStmtEvery') }}:
|
||||
<div class="column col-4">
|
||||
<h5 class="h5">
|
||||
{{ $t('word.options') }}
|
||||
</h5>
|
||||
<span class="h6">{{ $t('word.includes') }}:</span>
|
||||
<label
|
||||
v-for="(_, key) in options.includes"
|
||||
:key="key"
|
||||
class="form-checkbox"
|
||||
>
|
||||
<input v-model="options.includes[key]" type="checkbox"><i class="form-icon" /> {{ $tc(`word.${key}`, 2) }}
|
||||
</label>
|
||||
<div v-if="customizations.exportByChunks">
|
||||
<div class="h6 mt-4 mb-2">
|
||||
{{ $t('message.newInserStmtEvery') }}:
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column col-6">
|
||||
<input
|
||||
v-model.number="options.sqlInsertAfter"
|
||||
type="number"
|
||||
class="form-input"
|
||||
>
|
||||
</div>
|
||||
<div class="column col-6">
|
||||
<select v-model="options.sqlInsertDivider" class="form-select">
|
||||
<option value="bytes">
|
||||
KiB
|
||||
</option>
|
||||
<option value="rows">
|
||||
{{ $tc('word.row', 2) }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h6 mb-2 mt-4">
|
||||
{{ $t('message.ourputFormat') }}:
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column col-6">
|
||||
<input
|
||||
v-model.number="options.sqlInsertAfter"
|
||||
type="number"
|
||||
class="form-input"
|
||||
value="250"
|
||||
>
|
||||
</div>
|
||||
<div class="column col-6">
|
||||
<select v-model="options.sqlInsertDivider" class="form-select">
|
||||
<option value="bytes">
|
||||
KiB
|
||||
<div class="column h5 mb-4">
|
||||
<select v-model="options.outputFormat" class="form-select">
|
||||
<option value="sql">
|
||||
{{ $t('message.singleFile', {ext: '.sql'}) }}
|
||||
</option>
|
||||
<option value="rows">
|
||||
{{ $tc('word.row', 2) }}
|
||||
<option value="sql.zip">
|
||||
{{ $t('message.zipCompressedFile', {ext: '.sql'}) }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h6 mb-2 mt-4">
|
||||
{{ $t('message.ourputFormat') }}:
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column h5 mb-4">
|
||||
<select v-model="options.outputFormat" class="form-select">
|
||||
<option value="sql">
|
||||
{{ $t('message.singleFile', {ext: '.sql'}) }}
|
||||
</option>
|
||||
<option value="sql.zip">
|
||||
{{ $t('message.zipCompressedFile', {ext: '.sql'}) }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer columns">
|
||||
<div class="column col modal-progress-wrapper text-left">
|
||||
<div v-if="progressPercentage > 0" class="export-progress">
|
||||
<span class="progress-status">
|
||||
{{ progressPercentage }}% - {{ progressStatus }}
|
||||
</span>
|
||||
<progress
|
||||
class="progress d-block"
|
||||
:value="progressPercentage"
|
||||
max="100"
|
||||
/>
|
||||
<div class="modal-footer columns">
|
||||
<div class="column col modal-progress-wrapper text-left">
|
||||
<div v-if="progressPercentage > 0" class="export-progress">
|
||||
<span class="progress-status">
|
||||
{{ progressPercentage }}% - {{ progressStatus }}
|
||||
</span>
|
||||
<progress
|
||||
class="progress d-block"
|
||||
:value="progressPercentage"
|
||||
max="100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto px-0">
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isExporting}"
|
||||
:disabled="isExporting || isRefreshing"
|
||||
autofocus
|
||||
@click.prevent="startExport"
|
||||
>
|
||||
{{ $t('word.export') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto px-0">
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isExporting}"
|
||||
:disabled="isExporting || isRefreshing"
|
||||
autofocus
|
||||
@click.prevent="startExport"
|
||||
>
|
||||
{{ $t('word.export') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import moment from 'moment';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import customizations from 'common/customizations';
|
||||
import Application from '@/ipc-api/Application';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
|
||||
export default {
|
||||
name: 'ModalExportSchema',
|
||||
|
||||
props: {
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: ['close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
getDatabaseVariable,
|
||||
refreshSchema
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getDatabaseVariable,
|
||||
refreshSchema
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isExporting: false,
|
||||
|
@ -299,11 +322,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
getDatabaseVariable: 'workspaces/getDatabaseVariable'
|
||||
}),
|
||||
currentWorkspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
|
@ -358,20 +376,16 @@ export default {
|
|||
structure.forEach(feat => {
|
||||
const val = customizations[this.currentWorkspace.client][feat];
|
||||
if (val)
|
||||
this.$set(this.options.includes, feat, true);
|
||||
this.options.includes[feat] = true;
|
||||
});
|
||||
|
||||
ipcRenderer.on('export-progress', this.updateProgress);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
ipcRenderer.off('export-progress', this.updateProgress);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshSchema: 'workspaces/refreshSchema'
|
||||
}),
|
||||
async startExport () {
|
||||
this.isExporting = true;
|
||||
const { uid, client } = this.currentWorkspace;
|
||||
|
|
|
@ -1,192 +1,196 @@
|
|||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
|
||||
<span class="cut-text">{{ $tc('message.insertRow', 2) }}</span>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
|
||||
<span class="cut-text">{{ $tc('message.insertRow', 2) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<fieldset :disabled="isInserting">
|
||||
<div
|
||||
v-for="field in fields"
|
||||
:key="field.name"
|
||||
class="form-group"
|
||||
>
|
||||
<div class="col-3 col-sm-12">
|
||||
<label class="form-label" :title="field.name">{{ field.name }}</label>
|
||||
</div>
|
||||
<div class="column columns col-sm-12">
|
||||
<FakerSelect
|
||||
v-model="localRow[field.name]"
|
||||
:type="field.type"
|
||||
class="column columns pr-0"
|
||||
:is-checked="!fieldsToExclude.includes(field.name)"
|
||||
:foreign-keys="foreignKeys"
|
||||
:key-usage="keyUsage"
|
||||
:field="field"
|
||||
:field-length="fieldLength(field)"
|
||||
:field-obj="localRow[field.name]"
|
||||
>
|
||||
<span class="input-group-addon field-type" :class="typeClass(field.type)">
|
||||
{{ field.type }} {{ wrapNumber(fieldLength(field)) }}
|
||||
</span>
|
||||
<label class="form-checkbox ml-3" :title="$t('word.insert')">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="!fieldsToExclude.includes(field.name)"
|
||||
@change.prevent="toggleFields($event, field)"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</FakerSelect>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<fieldset :disabled="isInserting">
|
||||
<div
|
||||
v-for="field in fields"
|
||||
:key="field.name"
|
||||
class="form-group"
|
||||
<div class="modal-footer columns">
|
||||
<div class="column d-flex" :class="hasFakes ? 'col-4' : 'col-2'">
|
||||
<div class="input-group tooltip tooltip-right" :data-tooltip="$t('message.numberOfInserts')">
|
||||
<input
|
||||
v-model="nInserts"
|
||||
type="number"
|
||||
class="form-input"
|
||||
min="1"
|
||||
:disabled="isInserting"
|
||||
>
|
||||
<div class="col-3 col-sm-12">
|
||||
<label class="form-label" :title="field.name">{{ field.name }}</label>
|
||||
</div>
|
||||
<div class="column columns col-sm-12">
|
||||
<FakerSelect
|
||||
:type="field.type"
|
||||
class="column columns pr-0"
|
||||
:is-checked="!fieldsToExclude.includes(field.name)"
|
||||
:foreign-keys="foreignKeys"
|
||||
:key-usage="keyUsage"
|
||||
:field="field"
|
||||
:field-length="fieldLength(field)"
|
||||
:field-obj="localRow[field.name]"
|
||||
:value.sync="localRow[field.name]"
|
||||
>
|
||||
<span class="input-group-addon field-type" :class="typeClass(field.type)">
|
||||
{{ field.type }} {{ fieldLength(field) | wrapNumber }}
|
||||
</span>
|
||||
<label class="form-checkbox ml-3" :title="$t('word.insert')">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="!fieldsToExclude.includes(field.name)"
|
||||
@change.prevent="toggleFields($event, field)"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</FakerSelect>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer columns">
|
||||
<div class="column d-flex" :class="hasFakes ? 'col-4' : 'col-2'">
|
||||
<div class="input-group tooltip tooltip-right" :data-tooltip="$t('message.numberOfInserts')">
|
||||
<input
|
||||
v-model="nInserts"
|
||||
type="number"
|
||||
class="form-input"
|
||||
min="1"
|
||||
:disabled="isInserting"
|
||||
<span class="input-group-addon">
|
||||
<i class="mdi mdi-24px mdi-repeat" />
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasFakes"
|
||||
class="tooltip tooltip-right ml-2"
|
||||
:data-tooltip="$t('message.fakeDataLanguage')"
|
||||
>
|
||||
<span class="input-group-addon">
|
||||
<i class="mdi mdi-24px mdi-repeat" />
|
||||
</span>
|
||||
<select v-model="fakerLocale" class="form-select">
|
||||
<option value="ar">
|
||||
Arabic
|
||||
</option><option value="az">
|
||||
Azerbaijani
|
||||
</option><option value="zh_CN">
|
||||
Chinese
|
||||
</option><option value="zh_TW">
|
||||
Chinese (Taiwan)
|
||||
</option><option value="cz">
|
||||
Czech
|
||||
</option><option value="nl">
|
||||
Dutch
|
||||
</option><option value="nl_BE">
|
||||
Dutch (Belgium)
|
||||
</option><option value="en">
|
||||
English
|
||||
</option><option value="en_AU_ocker">
|
||||
English (Australia Ocker)
|
||||
</option><option value="en_AU">
|
||||
English (Australia)
|
||||
</option><option value="en_BORK">
|
||||
English (Bork)
|
||||
</option><option value="en_CA">
|
||||
English (Canada)
|
||||
</option><option value="en_GB">
|
||||
English (Great Britain)
|
||||
</option><option value="en_IND">
|
||||
English (India)
|
||||
</option><option value="en_IE">
|
||||
English (Ireland)
|
||||
</option><option value="en_ZA">
|
||||
English (South Africa)
|
||||
</option><option value="en_US">
|
||||
English (United States)
|
||||
</option><option value="fa">
|
||||
Farsi
|
||||
</option><option value="fi">
|
||||
Finnish
|
||||
</option><option value="fr">
|
||||
French
|
||||
</option><option value="fr_CA">
|
||||
French (Canada)
|
||||
</option><option value="fr_CH">
|
||||
French (Switzerland)
|
||||
</option><option value="ge">
|
||||
Georgian
|
||||
</option><option value="de">
|
||||
German
|
||||
</option><option value="de_AT">
|
||||
German (Austria)
|
||||
</option><option value="de_CH">
|
||||
German (Switzerland)
|
||||
</option><option value="hr">
|
||||
Hrvatski
|
||||
</option><option value="id_ID">
|
||||
Indonesia
|
||||
</option><option value="it">
|
||||
Italian
|
||||
</option><option value="ja">
|
||||
Japanese
|
||||
</option><option value="ko">
|
||||
Korean
|
||||
</option><option value="nep">
|
||||
Nepalese
|
||||
</option><option value="nb_NO">
|
||||
Norwegian
|
||||
</option><option value="pl">
|
||||
Polish
|
||||
</option><option value="pt_BR">
|
||||
Portuguese (Brazil)
|
||||
</option><option value="pt_PT">
|
||||
Portuguese (Portugal)
|
||||
</option><option value="ro">
|
||||
Romanian
|
||||
</option><option value="ru">
|
||||
Russian
|
||||
</option><option value="sk">
|
||||
Slovakian
|
||||
</option><option value="es">
|
||||
Spanish
|
||||
</option><option value="es_MX">
|
||||
Spanish (Mexico)
|
||||
</option><option value="sv">
|
||||
Swedish
|
||||
</option><option value="tr">
|
||||
Turkish
|
||||
</option><option value="uk">
|
||||
Ukrainian
|
||||
</option><option value="vi">
|
||||
Vietnamese
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="hasFakes"
|
||||
class="tooltip tooltip-right ml-2"
|
||||
:data-tooltip="$t('message.fakeDataLanguage')"
|
||||
>
|
||||
<select v-model="fakerLocale" class="form-select">
|
||||
<option value="ar">
|
||||
Arabic
|
||||
</option><option value="az">
|
||||
Azerbaijani
|
||||
</option><option value="zh_CN">
|
||||
Chinese
|
||||
</option><option value="zh_TW">
|
||||
Chinese (Taiwan)
|
||||
</option><option value="cz">
|
||||
Czech
|
||||
</option><option value="nl">
|
||||
Dutch
|
||||
</option><option value="nl_BE">
|
||||
Dutch (Belgium)
|
||||
</option><option value="en">
|
||||
English
|
||||
</option><option value="en_AU_ocker">
|
||||
English (Australia Ocker)
|
||||
</option><option value="en_AU">
|
||||
English (Australia)
|
||||
</option><option value="en_BORK">
|
||||
English (Bork)
|
||||
</option><option value="en_CA">
|
||||
English (Canada)
|
||||
</option><option value="en_GB">
|
||||
English (Great Britain)
|
||||
</option><option value="en_IND">
|
||||
English (India)
|
||||
</option><option value="en_IE">
|
||||
English (Ireland)
|
||||
</option><option value="en_ZA">
|
||||
English (South Africa)
|
||||
</option><option value="en_US">
|
||||
English (United States)
|
||||
</option><option value="fa">
|
||||
Farsi
|
||||
</option><option value="fi">
|
||||
Finnish
|
||||
</option><option value="fr">
|
||||
French
|
||||
</option><option value="fr_CA">
|
||||
French (Canada)
|
||||
</option><option value="fr_CH">
|
||||
French (Switzerland)
|
||||
</option><option value="ge">
|
||||
Georgian
|
||||
</option><option value="de">
|
||||
German
|
||||
</option><option value="de_AT">
|
||||
German (Austria)
|
||||
</option><option value="de_CH">
|
||||
German (Switzerland)
|
||||
</option><option value="hr">
|
||||
Hrvatski
|
||||
</option><option value="id_ID">
|
||||
Indonesia
|
||||
</option><option value="it">
|
||||
Italian
|
||||
</option><option value="ja">
|
||||
Japanese
|
||||
</option><option value="ko">
|
||||
Korean
|
||||
</option><option value="nep">
|
||||
Nepalese
|
||||
</option><option value="nb_NO">
|
||||
Norwegian
|
||||
</option><option value="pl">
|
||||
Polish
|
||||
</option><option value="pt_BR">
|
||||
Portuguese (Brazil)
|
||||
</option><option value="pt_PT">
|
||||
Portuguese (Portugal)
|
||||
</option><option value="ro">
|
||||
Romanian
|
||||
</option><option value="ru">
|
||||
Russian
|
||||
</option><option value="sk">
|
||||
Slovakian
|
||||
</option><option value="es">
|
||||
Spanish
|
||||
</option><option value="es_MX">
|
||||
Spanish (Mexico)
|
||||
</option><option value="sv">
|
||||
Swedish
|
||||
</option><option value="tr">
|
||||
Turkish
|
||||
</option><option value="uk">
|
||||
Ukrainian
|
||||
</option><option value="vi">
|
||||
Vietnamese
|
||||
</option>
|
||||
</select>
|
||||
<div class="column col-auto">
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isInserting}"
|
||||
@click.stop="insertRows"
|
||||
>
|
||||
{{ $t('word.insert') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto">
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isInserting}"
|
||||
@click.stop="insertRows"
|
||||
>
|
||||
{{ $t('word.insert') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import FakerSelect from '@/components/FakerSelect';
|
||||
|
||||
|
@ -195,17 +199,27 @@ export default {
|
|||
components: {
|
||||
FakerSelect
|
||||
},
|
||||
filters: {
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
tabUid: [String, Number],
|
||||
fields: Array,
|
||||
keyUsage: Array
|
||||
},
|
||||
emits: ['reload', 'hide'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, getWorkspaceTab } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getWorkspaceTab
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localRow: {},
|
||||
|
@ -216,11 +230,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
getWorkspaceTab: 'workspaces/getWorkspaceTab'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
|
@ -287,13 +296,10 @@ export default {
|
|||
|
||||
this.localRow = { ...rowObj };
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
typeClass (type) {
|
||||
if (type)
|
||||
return `type-${type.toLowerCase().replaceAll(' ', '_').replaceAll('"', '')}`;
|
||||
|
@ -345,8 +351,8 @@ export default {
|
|||
},
|
||||
fieldLength (field) {
|
||||
if ([...BLOB, ...LONG_TEXT].includes(field.type)) return null;
|
||||
else if (TEXT.includes(field.type)) return field.charLength;
|
||||
return field.length;
|
||||
else if (TEXT.includes(field.type)) return Number(field.charLength);
|
||||
return Number(field.length);
|
||||
},
|
||||
toggleFields (event, field) {
|
||||
if (event.target.checked)
|
||||
|
@ -367,6 +373,10 @@ export default {
|
|||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,103 +1,107 @@
|
|||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div 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-history mr-1" />
|
||||
<span class="cut-text">{{ $t('word.history') }}: {{ connectionName }}</span>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div 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-history mr-1" />
|
||||
<span class="cut-text">{{ $t('word.history') }}: {{ connectionName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body p-0 workspace-query-results">
|
||||
<div
|
||||
v-if="history.length"
|
||||
ref="searchForm"
|
||||
class="form-group has-icon-right p-2 m-0"
|
||||
>
|
||||
<input
|
||||
v-model="searchTerm"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:placeholder="$t('message.searchForQueries')"
|
||||
<div class="modal-body p-0 workspace-query-results">
|
||||
<div
|
||||
v-if="history.length"
|
||||
ref="searchForm"
|
||||
class="form-group has-icon-right p-2 m-0"
|
||||
>
|
||||
<i v-if="!searchTerm" class="form-icon mdi mdi-magnify mdi-18px pr-4" />
|
||||
<i
|
||||
v-else
|
||||
class="form-icon c-hand mdi mdi-backspace mdi-18px pr-4"
|
||||
@click="searchTerm = ''"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="history.length"
|
||||
ref="tableWrapper"
|
||||
class="vscroll px-1 "
|
||||
:style="{'height': resultsSize+'px'}"
|
||||
>
|
||||
<div ref="table">
|
||||
<BaseVirtualScroll
|
||||
ref="resultTable"
|
||||
:items="filteredHistory"
|
||||
:item-height="66"
|
||||
:visible-height="resultsSize"
|
||||
:scroll-element="scrollElement"
|
||||
<input
|
||||
v-model="searchTerm"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:placeholder="$t('message.searchForQueries')"
|
||||
>
|
||||
<template slot-scope="{ items }">
|
||||
<div
|
||||
v-for="query in items"
|
||||
:key="query.uid"
|
||||
class="tile my-2"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="tile-icon">
|
||||
<i class="mdi mdi-code-tags pr-1" />
|
||||
</div>
|
||||
<div class="tile-content">
|
||||
<div class="tile-title">
|
||||
<code
|
||||
class="cut-text"
|
||||
:title="query.sql"
|
||||
v-html="highlightWord(query.sql)"
|
||||
/>
|
||||
<i v-if="!searchTerm" class="form-icon mdi mdi-magnify mdi-18px pr-4" />
|
||||
<i
|
||||
v-else
|
||||
class="form-icon c-hand mdi mdi-backspace mdi-18px pr-4"
|
||||
@click="searchTerm = ''"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="history.length"
|
||||
ref="tableWrapper"
|
||||
class="vscroll px-1 "
|
||||
:style="{'height': resultsSize+'px'}"
|
||||
>
|
||||
<div ref="table">
|
||||
<BaseVirtualScroll
|
||||
ref="resultTable"
|
||||
:items="filteredHistory"
|
||||
:item-height="66"
|
||||
:visible-height="resultsSize"
|
||||
:scroll-element="scrollElement"
|
||||
>
|
||||
<template #default="{ items }">
|
||||
<div
|
||||
v-for="query in items"
|
||||
:key="query.uid"
|
||||
class="tile my-2"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="tile-icon">
|
||||
<i class="mdi mdi-code-tags pr-1" />
|
||||
</div>
|
||||
<div class="tile-bottom-content">
|
||||
<small class="tile-subtitle">{{ query.schema }} · {{ formatDate(query.date) }}</small>
|
||||
<div class="tile-history-buttons">
|
||||
<button class="btn btn-link pl-1" @click.stop="$emit('select-query', query.sql)">
|
||||
<i class="mdi mdi-open-in-app pr-1" /> {{ $t('word.select') }}
|
||||
</button>
|
||||
<button class="btn btn-link pl-1" @click="copyQuery(query.sql)">
|
||||
<i class="mdi mdi-content-copy pr-1" /> {{ $t('word.copy') }}
|
||||
</button>
|
||||
<button class="btn btn-link pl-1" @click="deleteQuery(query)">
|
||||
<i class="mdi mdi-delete-forever pr-1" /> {{ $t('word.delete') }}
|
||||
</button>
|
||||
<div class="tile-content">
|
||||
<div class="tile-title">
|
||||
<code
|
||||
class="cut-text"
|
||||
:title="query.sql"
|
||||
v-html="highlightWord(query.sql)"
|
||||
/>
|
||||
</div>
|
||||
<div class="tile-bottom-content">
|
||||
<small class="tile-subtitle">{{ query.schema }} · {{ formatDate(query.date) }}</small>
|
||||
<div class="tile-history-buttons">
|
||||
<button class="btn btn-link pl-1" @click.stop="$emit('select-query', query.sql)">
|
||||
<i class="mdi mdi-open-in-app pr-1" /> {{ $t('word.select') }}
|
||||
</button>
|
||||
<button class="btn btn-link pl-1" @click="copyQuery(query.sql)">
|
||||
<i class="mdi mdi-content-copy pr-1" /> {{ $t('word.copy') }}
|
||||
</button>
|
||||
<button class="btn btn-link pl-1" @click="deleteQuery(query)">
|
||||
<i class="mdi mdi-delete-forever pr-1" /> {{ $t('word.delete') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</BaseVirtualScroll>
|
||||
</template>
|
||||
</BaseVirtualScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="empty">
|
||||
<div class="empty-icon">
|
||||
<i class="mdi mdi-history mdi-48px" />
|
||||
<div v-else class="empty">
|
||||
<div class="empty-icon">
|
||||
<i class="mdi mdi-history mdi-48px" />
|
||||
</div>
|
||||
<p class="empty-title h5">
|
||||
{{ $t('message.thereIsNoQueriesYet') }}
|
||||
</p>
|
||||
</div>
|
||||
<p class="empty-title h5">
|
||||
{{ $t('message.thereIsNoQueriesYet') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useHistoryStore } from '@/stores/history';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
|
||||
|
||||
export default {
|
||||
|
@ -108,6 +112,19 @@ export default {
|
|||
props: {
|
||||
connection: Object
|
||||
},
|
||||
emits: ['select-query', 'close'],
|
||||
setup () {
|
||||
const { getHistoryByWorkspace, deleteQueryFromHistory } = useHistoryStore();
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
|
||||
return {
|
||||
getHistoryByWorkspace,
|
||||
deleteQueryFromHistory,
|
||||
getConnectionName,
|
||||
addNotification
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
resultsSize: 1000,
|
||||
|
@ -119,10 +136,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getConnectionName: 'connections/getConnectionName',
|
||||
getHistoryByWorkspace: 'history/getHistoryByWorkspace'
|
||||
}),
|
||||
connectionName () {
|
||||
return this.getConnectionName(this.connection.uid);
|
||||
},
|
||||
|
@ -156,16 +169,12 @@ export default {
|
|||
this.resizeResults();
|
||||
window.addEventListener('resize', this.resizeResults);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey, { capture: true });
|
||||
window.removeEventListener('resize', this.resizeResults);
|
||||
clearInterval(this.refreshInterval);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
deleteQueryFromHistory: 'history/deleteQueryFromHistory'
|
||||
}),
|
||||
copyQuery (sql) {
|
||||
navigator.clipboard.writeText(sql);
|
||||
},
|
||||
|
|
|
@ -1,56 +1,61 @@
|
|||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-database-arrow-up mr-1" />
|
||||
<span class="cut-text">{{ $t('message.importSchema') }}</span>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-database-arrow-up mr-1" />
|
||||
<span class="cut-text">{{ $t('message.importSchema') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
{{ sqlFile }}
|
||||
<div v-if="queryErrors.length > 0" class="mt-2">
|
||||
<label>{{ $tc('message.importQueryErrors', queryErrors.length) }}</label>
|
||||
<textarea
|
||||
v-model="formattedQueryErrors"
|
||||
class="form-input"
|
||||
rows="5"
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer columns">
|
||||
<div class="column col modal-progress-wrapper text-left">
|
||||
<div class="import-progress">
|
||||
<span class="progress-status">
|
||||
{{ progressPercentage }}% - {{ progressStatus }} - {{ $tc('message.executedQueries', queryCount) }}
|
||||
</span>
|
||||
<progress
|
||||
class="progress d-block"
|
||||
:value="progressPercentage"
|
||||
max="100"
|
||||
<div class="modal-body pb-0">
|
||||
{{ sqlFile }}
|
||||
<div v-if="queryErrors.length > 0" class="mt-2">
|
||||
<label>{{ $tc('message.importQueryErrors', queryErrors.length) }}</label>
|
||||
<textarea
|
||||
v-model="formattedQueryErrors"
|
||||
class="form-input"
|
||||
rows="5"
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto px-0">
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ completed ? $t('word.close') : $t('word.cancel') }}
|
||||
</button>
|
||||
<div class="modal-footer columns">
|
||||
<div class="column col modal-progress-wrapper text-left">
|
||||
<div class="import-progress">
|
||||
<span class="progress-status">
|
||||
{{ progressPercentage }}% - {{ progressStatus }} - {{ $tc('message.executedQueries', queryCount) }}
|
||||
</span>
|
||||
<progress
|
||||
class="progress d-block"
|
||||
:value="progressPercentage"
|
||||
max="100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-auto px-0">
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ completed ? $t('word.close') : $t('word.cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Teleport to="#window-content" />
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import moment from 'moment';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'ModalImportSchema',
|
||||
|
@ -58,6 +63,22 @@ export default {
|
|||
props: {
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: ['close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, refreshSchema } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshSchema
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
sqlFile: '',
|
||||
|
@ -70,10 +91,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
currentWorkspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
|
@ -89,16 +106,12 @@ export default {
|
|||
ipcRenderer.on('import-progress', this.updateProgress);
|
||||
ipcRenderer.on('query-error', this.handleQueryError);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
ipcRenderer.off('import-progress', this.updateProgress);
|
||||
ipcRenderer.off('query-error', this.handleQueryError);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshSchema: 'workspaces/refreshSchema'
|
||||
}),
|
||||
async startImport (sqlFile) {
|
||||
this.isImporting = true;
|
||||
this.sqlFile = sqlFile;
|
||||
|
|
|
@ -1,76 +1,96 @@
|
|||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-database-plus mr-1" />
|
||||
<span class="cut-text">{{ $t('message.createNewSchema') }}</span>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-database-plus mr-1" />
|
||||
<span class="cut-text">{{ $t('message.createNewSchema') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal" @submit.prevent="createSchema">
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.name') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="database.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
required
|
||||
:placeholder="$t('message.schemaName')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.collations" class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.collation') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<select v-model="database.collation" class="form-select">
|
||||
<option
|
||||
v-for="collation in collations"
|
||||
:key="collation.id"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal" @submit.prevent="createSchema">
|
||||
<div class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.name') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="database.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
required
|
||||
:placeholder="$t('message.schemaName')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.collations" class="form-group">
|
||||
<div class="col-3">
|
||||
<label class="form-label">{{ $t('word.collation') }}</label>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<select v-model="database.collation" class="form-select">
|
||||
<option
|
||||
v-for="collation in collations"
|
||||
:key="collation.id"
|
||||
:value="collation.collation"
|
||||
>
|
||||
{{ collation.collation }}
|
||||
</option>
|
||||
</select>
|
||||
<small>{{ $t('message.serverDefault') }}: {{ defaultCollation }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isLoading}"
|
||||
@click.stop="createSchema"
|
||||
>
|
||||
{{ $t('word.add') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isLoading}"
|
||||
@click.stop="createSchema"
|
||||
>
|
||||
{{ $t('word.add') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'ModalNewSchema',
|
||||
emits: ['reload', 'close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, getDatabaseVariable } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getDatabaseVariable
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -81,11 +101,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
getDatabaseVariable: 'workspaces/getDatabaseVariable'
|
||||
}),
|
||||
collations () {
|
||||
return this.getWorkspace(this.selectedWorkspace).collations;
|
||||
},
|
||||
|
@ -103,13 +118,10 @@ export default {
|
|||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
async createSchema () {
|
||||
this.isLoading = true;
|
||||
try {
|
||||
|
|
|
@ -1,148 +1,158 @@
|
|||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
|
||||
<span class="cut-text">{{ $t('message.addNewRow') }}</span>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div class="modal-container p-0">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
|
||||
<span class="cut-text">{{ $t('message.addNewRow') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<fieldset :disabled="isInserting">
|
||||
<div
|
||||
v-for="(field, key) in fields"
|
||||
:key="field.name"
|
||||
class="form-group"
|
||||
>
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label" :title="field.name">{{ field.name }}</label>
|
||||
</div>
|
||||
<div class="input-group col-8 col-sm-12">
|
||||
<ForeignKeySelect
|
||||
v-if="foreignKeys.includes(field.name)"
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
class="form-select"
|
||||
:key-usage="getKeyUsage(field.name)"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
/>
|
||||
<input
|
||||
v-else-if="inputProps(field).mask"
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
v-mask="inputProps(field).mask"
|
||||
class="form-input"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<input
|
||||
v-else-if="inputProps(field).type === 'file'"
|
||||
ref="formInput"
|
||||
class="form-input"
|
||||
type="file"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
@change="filesChange($event,field.name)"
|
||||
>
|
||||
<input
|
||||
v-else-if="inputProps(field).type === 'number'"
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
class="form-input"
|
||||
step="any"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<input
|
||||
v-else
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
class="form-input"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<span class="input-group-addon" :class="typeCLass(field.type)">
|
||||
{{ field.type }} {{ wrapNumber(fieldLength(field)) }}
|
||||
</span>
|
||||
<label class="form-checkbox ml-3" :title="$t('word.insert')">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="!field.autoIncrement"
|
||||
@change.prevent="toggleFields($event, field)"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body pb-0">
|
||||
<div class="content">
|
||||
<form class="form-horizontal">
|
||||
<fieldset :disabled="isInserting">
|
||||
<div
|
||||
v-for="(field, key) in fields"
|
||||
:key="field.name"
|
||||
class="form-group"
|
||||
>
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label" :title="field.name">{{ field.name }}</label>
|
||||
</div>
|
||||
<div class="input-group col-8 col-sm-12">
|
||||
<ForeignKeySelect
|
||||
v-if="foreignKeys.includes(field.name)"
|
||||
ref="formInput"
|
||||
class="form-select"
|
||||
:value.sync="localRow[field.name]"
|
||||
:key-usage="getKeyUsage(field.name)"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
/>
|
||||
<input
|
||||
v-else-if="inputProps(field).mask"
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
v-mask="inputProps(field).mask"
|
||||
class="form-input"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<input
|
||||
v-else-if="inputProps(field).type === 'file'"
|
||||
ref="formInput"
|
||||
class="form-input"
|
||||
type="file"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
@change="filesChange($event,field.name)"
|
||||
>
|
||||
<input
|
||||
v-else-if="inputProps(field).type === 'number'"
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
class="form-input"
|
||||
step="any"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<input
|
||||
v-else
|
||||
ref="formInput"
|
||||
v-model="localRow[field.name]"
|
||||
class="form-input"
|
||||
:type="inputProps(field).type"
|
||||
:disabled="fieldsToExclude.includes(field.name)"
|
||||
:tabindex="key+1"
|
||||
>
|
||||
<span class="input-group-addon" :class="typeCLass(field.type)">
|
||||
{{ field.type }} {{ fieldLength(field) | wrapNumber }}
|
||||
</span>
|
||||
<label class="form-checkbox ml-3" :title="$t('word.insert')">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="!field.autoIncrement"
|
||||
@change.prevent="toggleFields($event, field)"
|
||||
><i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="input-group col-3 tooltip tooltip-right" :data-tooltip="$t('message.numberOfInserts')">
|
||||
<input
|
||||
v-model="nInserts"
|
||||
type="number"
|
||||
class="form-input"
|
||||
min="1"
|
||||
:disabled="isInserting"
|
||||
>
|
||||
<span class="input-group-addon">
|
||||
<i class="mdi mdi-24px mdi-repeat" />
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isInserting}"
|
||||
@click.stop="insertRows"
|
||||
>
|
||||
{{ $t('word.insert') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
<div class="modal-footer">
|
||||
<div class="input-group col-3 tooltip tooltip-right" :data-tooltip="$t('message.numberOfInserts')">
|
||||
<input
|
||||
v-model="nInserts"
|
||||
type="number"
|
||||
class="form-input"
|
||||
min="1"
|
||||
:disabled="isInserting"
|
||||
>
|
||||
<span class="input-group-addon">
|
||||
<i class="mdi mdi-24px mdi-repeat" />
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isInserting}"
|
||||
@click.stop="insertRows"
|
||||
>
|
||||
{{ $t('word.insert') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click.stop="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
|
||||
import { VueMaskDirective } from 'v-mask';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import ForeignKeySelect from '@/components/ForeignKeySelect';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'ModalNewTableRow',
|
||||
components: {
|
||||
ForeignKeySelect
|
||||
},
|
||||
directives: {
|
||||
mask: VueMaskDirective
|
||||
},
|
||||
filters: {
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
tabUid: [String, Number],
|
||||
fields: Array,
|
||||
keyUsage: Array
|
||||
},
|
||||
emits: ['reload', 'hide'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, getWorkspaceTab } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
getWorkspaceTab
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localRow: {},
|
||||
|
@ -152,11 +162,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
getWorkspaceTab: 'workspaces/getWorkspaceTab'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
|
@ -216,13 +221,10 @@ export default {
|
|||
firstSelectableInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
typeClass (type) {
|
||||
if (type)
|
||||
return `type-${type.toLowerCase().replaceAll(' ', '_').replaceAll('"', '')}`;
|
||||
|
@ -331,6 +333,10 @@ export default {
|
|||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
wrapNumber (num) {
|
||||
if (!num) return '';
|
||||
return `(${num})`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,140 +1,143 @@
|
|||
<template>
|
||||
<div class="modal active">
|
||||
<ModalProcessesListContext
|
||||
v-if="isContext"
|
||||
:context-event="contextEvent"
|
||||
:selected-row="selectedRow"
|
||||
:selected-cell="selectedCell"
|
||||
@copy-cell="copyCell"
|
||||
@copy-row="copyRow"
|
||||
@kill-process="killProcess"
|
||||
@close-context="closeContext"
|
||||
/>
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div 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-memory mr-1" />
|
||||
<span class="cut-text">{{ $t('message.processesList') }}: {{ connectionName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="processes-toolbar py-2 px-4">
|
||||
<div class="workspace-query-buttons">
|
||||
<div class="dropdown pr-1">
|
||||
<div class="btn-group">
|
||||
<button
|
||||
class="btn btn-dark btn-sm mr-0 pr-1 d-flex"
|
||||
:class="{'loading':isQuering}"
|
||||
:title="`${$t('word.refresh')} (F5)`"
|
||||
@click="getProcessesList"
|
||||
>
|
||||
<i v-if="!+autorefreshTimer" class="mdi mdi-24px mdi-refresh mr-1" />
|
||||
<i v-else class="mdi mdi-24px mdi-history mdi-flip-h mr-1" />
|
||||
</button>
|
||||
<div class="btn btn-dark btn-sm dropdown-toggle pl-0 pr-0" tabindex="0">
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
</div>
|
||||
<div class="menu px-3">
|
||||
<span>{{ $t('word.autoRefresh') }}: <b>{{ +autorefreshTimer ? `${autorefreshTimer}s` : 'OFF' }}</b></span>
|
||||
<input
|
||||
v-model="autorefreshTimer"
|
||||
class="slider no-border"
|
||||
type="range"
|
||||
min="0"
|
||||
max="15"
|
||||
step="0.5"
|
||||
@change="setRefreshInterval"
|
||||
>
|
||||
</div>
|
||||
<Teleport to="#window-content">
|
||||
<div class="modal active">
|
||||
<ModalProcessesListContext
|
||||
v-if="isContext"
|
||||
:context-event="contextEvent"
|
||||
:selected-row="selectedRow"
|
||||
:selected-cell="selectedCell"
|
||||
@copy-cell="copyCell"
|
||||
@copy-row="copyRow"
|
||||
@kill-process="killProcess"
|
||||
@close-context="closeContext"
|
||||
/>
|
||||
<a class="modal-overlay" @click.stop="closeModal" />
|
||||
<div 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-memory mr-1" />
|
||||
<span class="cut-text">{{ $t('message.processesList') }}: {{ connectionName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown table-dropdown">
|
||||
<button
|
||||
:disabled="isQuering"
|
||||
class="btn btn-dark btn-sm dropdown-toggle d-flex mr-0 pr-0"
|
||||
tabindex="0"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-file-export mr-1" />
|
||||
<span>{{ $t('word.export') }}</span>
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
</button>
|
||||
<ul class="menu text-left">
|
||||
<li class="menu-item">
|
||||
<a class="c-hand" @click="downloadTable('json')">JSON</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a class="c-hand" @click="downloadTable('csv')">CSV</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
<div v-if="sortedResults.length">
|
||||
{{ $t('word.processes') }}: <b>{{ sortedResults.length.toLocaleString() }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body py-0 workspace-query-results">
|
||||
<div
|
||||
ref="tableWrapper"
|
||||
class="vscroll"
|
||||
:style="{'height': resultsSize+'px'}"
|
||||
>
|
||||
<div ref="table" class="table table-hover">
|
||||
<div class="thead">
|
||||
<div class="tr">
|
||||
<div
|
||||
v-for="(field, index) in fields"
|
||||
:key="index"
|
||||
class="th c-hand"
|
||||
<div class="processes-toolbar py-2 px-4">
|
||||
<div class="workspace-query-buttons">
|
||||
<div class="dropdown pr-1">
|
||||
<div class="btn-group">
|
||||
<button
|
||||
class="btn btn-dark btn-sm mr-0 pr-1 d-flex"
|
||||
:class="{'loading':isQuering}"
|
||||
:title="`${$t('word.refresh')} (F5)`"
|
||||
@click="getProcessesList"
|
||||
>
|
||||
<div ref="columnResize" class="column-resizable">
|
||||
<div class="table-column-title" @click="sort(field)">
|
||||
<span>{{ field.toUpperCase() }}</span>
|
||||
<i
|
||||
v-if="currentSort === field"
|
||||
class="mdi sort-icon"
|
||||
:class="currentSortDir === 'asc' ? 'mdi-sort-ascending':'mdi-sort-descending'"
|
||||
/>
|
||||
<i v-if="!+autorefreshTimer" class="mdi mdi-24px mdi-refresh mr-1" />
|
||||
<i v-else class="mdi mdi-24px mdi-history mdi-flip-h mr-1" />
|
||||
</button>
|
||||
<div class="btn btn-dark btn-sm dropdown-toggle pl-0 pr-0" tabindex="0">
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
</div>
|
||||
<div class="menu px-3">
|
||||
<span>{{ $t('word.autoRefresh') }}: <b>{{ +autorefreshTimer ? `${autorefreshTimer}s` : 'OFF' }}</b></span>
|
||||
<input
|
||||
v-model="autorefreshTimer"
|
||||
class="slider no-border"
|
||||
type="range"
|
||||
min="0"
|
||||
max="15"
|
||||
step="0.5"
|
||||
@change="setRefreshInterval"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown table-dropdown">
|
||||
<button
|
||||
:disabled="isQuering"
|
||||
class="btn btn-dark btn-sm dropdown-toggle d-flex mr-0 pr-0"
|
||||
tabindex="0"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-file-export mr-1" />
|
||||
<span>{{ $t('word.export') }}</span>
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
</button>
|
||||
<ul class="menu text-left">
|
||||
<li class="menu-item">
|
||||
<a class="c-hand" @click="downloadTable('json')">JSON</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a class="c-hand" @click="downloadTable('csv')">CSV</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
<div v-if="sortedResults.length">
|
||||
{{ $t('word.processes') }}: <b>{{ sortedResults.length.toLocaleString() }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body py-0 workspace-query-results">
|
||||
<div
|
||||
ref="tableWrapper"
|
||||
class="vscroll"
|
||||
:style="{'height': resultsSize+'px'}"
|
||||
>
|
||||
<div ref="table" class="table table-hover">
|
||||
<div class="thead">
|
||||
<div class="tr">
|
||||
<div
|
||||
v-for="(field, index) in fields"
|
||||
:key="index"
|
||||
class="th c-hand"
|
||||
>
|
||||
<div ref="columnResize" class="column-resizable">
|
||||
<div class="table-column-title" @click="sort(field)">
|
||||
<span>{{ field.toUpperCase() }}</span>
|
||||
<i
|
||||
v-if="currentSort === field"
|
||||
class="mdi sort-icon"
|
||||
:class="currentSortDir === 'asc' ? 'mdi-sort-ascending':'mdi-sort-descending'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<BaseVirtualScroll
|
||||
ref="resultTable"
|
||||
:items="sortedResults"
|
||||
:item-height="22"
|
||||
class="tbody"
|
||||
:visible-height="resultsSize"
|
||||
:scroll-element="scrollElement"
|
||||
>
|
||||
<template #default="{ items }">
|
||||
<ModalProcessesListRow
|
||||
v-for="row in items"
|
||||
:key="row.id"
|
||||
class="process-row"
|
||||
:row="row"
|
||||
@select-row="selectRow(row.id)"
|
||||
@contextmenu="contextMenu"
|
||||
@stop-refresh="stopRefresh"
|
||||
/>
|
||||
</template>
|
||||
</BaseVirtualScroll>
|
||||
</div>
|
||||
<BaseVirtualScroll
|
||||
ref="resultTable"
|
||||
:items="sortedResults"
|
||||
:item-height="22"
|
||||
class="tbody"
|
||||
:visible-height="resultsSize"
|
||||
:scroll-element="scrollElement"
|
||||
>
|
||||
<template slot-scope="{ items }">
|
||||
<ModalProcessesListRow
|
||||
v-for="row in items"
|
||||
:key="row.id"
|
||||
class="process-row"
|
||||
:row="row"
|
||||
@select-row="selectRow(row.id)"
|
||||
@contextmenu="contextMenu"
|
||||
@stop-refresh="stopRefresh"
|
||||
/>
|
||||
</template>
|
||||
</BaseVirtualScroll>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import arrayToFile from '../libs/arrayToFile';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
|
||||
import ModalProcessesListRow from '@/components/ModalProcessesListRow';
|
||||
import ModalProcessesListContext from '@/components/ModalProcessesListContext';
|
||||
|
@ -149,6 +152,13 @@ export default {
|
|||
props: {
|
||||
connection: Object
|
||||
},
|
||||
emits: ['close'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
|
||||
return { addNotification, getConnectionName };
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
resultsSize: 1000,
|
||||
|
@ -167,9 +177,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getConnectionName: 'connections/getConnectionName'
|
||||
}),
|
||||
connectionName () {
|
||||
return this.getConnectionName(this.connection.uid);
|
||||
},
|
||||
|
@ -203,15 +210,12 @@ export default {
|
|||
this.getProcessesList();
|
||||
window.addEventListener('resize', this.resizeResults);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey, { capture: true });
|
||||
window.removeEventListener('resize', this.resizeResults);
|
||||
clearInterval(this.refreshInterval);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
async getProcessesList () {
|
||||
this.isQuering = true;
|
||||
|
||||
|
@ -284,14 +288,14 @@ export default {
|
|||
this.clearRefresh();
|
||||
},
|
||||
selectRow (row) {
|
||||
this.selectedRow = row;
|
||||
this.selectedRow = Number(row);
|
||||
},
|
||||
contextMenu (event, cell) {
|
||||
if (event.target.localName === 'input') return;
|
||||
this.stopRefresh();
|
||||
|
||||
this.selectedCell = cell;
|
||||
this.selectedRow = cell.id;
|
||||
this.selectedRow = Number(cell.id);
|
||||
this.contextEvent = event;
|
||||
this.isContext = true;
|
||||
},
|
||||
|
|
|
@ -52,6 +52,7 @@ export default {
|
|||
selectedRow: Number,
|
||||
selectedCell: Object
|
||||
},
|
||||
emits: ['close-context', 'copy-cell', 'copy-row', 'kill-process'],
|
||||
computed: {
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
class="cell-content"
|
||||
:class="`${isNull(col)} type-${typeof col === 'number' ? 'int' : 'varchar'}`"
|
||||
@dblclick="dblClick(cKey)"
|
||||
>{{ col | cutText }}</span>
|
||||
>{{ cutText(col) }}</span>
|
||||
</div>
|
||||
<ConfirmModal
|
||||
v-if="isInfoModal"
|
||||
|
@ -53,15 +53,10 @@ export default {
|
|||
ConfirmModal,
|
||||
TextEditor
|
||||
},
|
||||
filters: {
|
||||
cutText (val) {
|
||||
if (typeof val !== 'string') return val;
|
||||
return val.length > 250 ? `${val.substring(0, 250)}[...]` : val;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
row: Object
|
||||
},
|
||||
emits: ['select-row', 'contextmenu', 'stop-refresh'],
|
||||
data () {
|
||||
return {
|
||||
isInlineEditor: {},
|
||||
|
@ -95,6 +90,10 @@ export default {
|
|||
this.editingField = null;
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
}
|
||||
},
|
||||
cutText (val) {
|
||||
if (typeof val !== 'string') return val;
|
||||
return val.length > 250 ? `${val.substring(0, 250)}[...]` : val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,327 +1,332 @@
|
|||
<template>
|
||||
<div id="settings" class="modal active">
|
||||
<a class="modal-overlay c-hand" @click="closeModal" />
|
||||
<div class="modal-container">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-cog mr-1" />
|
||||
<span class="cut-text">{{ $t('word.settings') }}</span>
|
||||
<Teleport to="#window-content">
|
||||
<div id="settings" class="modal active">
|
||||
<a class="modal-overlay c-hand" @click="closeModal" />
|
||||
<div class="modal-container">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-cog mr-1" />
|
||||
<span class="cut-text">{{ $t('word.settings') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click="closeModal" />
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<div class="panel">
|
||||
<div class="panel-nav">
|
||||
<ul class="tab tab-block">
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'general'}"
|
||||
@click="selectTab('general')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.general') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'themes'}"
|
||||
@click="selectTab('themes')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.themes') }}</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="updateStatus !== 'disabled'"
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'update'}"
|
||||
@click="selectTab('update')"
|
||||
>
|
||||
<a class="tab-link" :class="{'badge badge-update': hasUpdates}">{{ $t('word.update') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'changelog'}"
|
||||
@click="selectTab('changelog')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.changelog') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'about'}"
|
||||
@click="selectTab('about')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.about') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-show="selectedTab === 'general'" class="panel-body py-4">
|
||||
<div class="container">
|
||||
<form class="form-horizontal columns">
|
||||
<div class="column col-12 h6 text-uppercase mb-1">
|
||||
{{ $t('word.application') }}
|
||||
</div>
|
||||
<div class="column col-9 col-sm-12 mb-2">
|
||||
<div class="form-group">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
<i class="mdi mdi-18px mdi-translate mr-1" />
|
||||
{{ $t('word.language') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<select
|
||||
v-model="localLocale"
|
||||
class="form-select"
|
||||
@change="changeLocale(localLocale)"
|
||||
>
|
||||
<option
|
||||
v-for="(locale, key) in locales"
|
||||
:key="key"
|
||||
:value="locale.code"
|
||||
<div class="modal-body p-0">
|
||||
<div class="panel">
|
||||
<div class="panel-nav">
|
||||
<ul class="tab tab-block">
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'general'}"
|
||||
@click="selectTab('general')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.general') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'themes'}"
|
||||
@click="selectTab('themes')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.themes') }}</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="updateStatus !== 'disabled'"
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'update'}"
|
||||
@click="selectTab('update')"
|
||||
>
|
||||
<a class="tab-link" :class="{'badge badge-update': hasUpdates}">{{ $t('word.update') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'changelog'}"
|
||||
@click="selectTab('changelog')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.changelog') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'about'}"
|
||||
@click="selectTab('about')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.about') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-show="selectedTab === 'general'" class="panel-body py-4">
|
||||
<div class="container">
|
||||
<form class="form-horizontal columns">
|
||||
<div class="column col-12 h6 text-uppercase mb-1">
|
||||
{{ $t('word.application') }}
|
||||
</div>
|
||||
<div class="column col-9 col-sm-12 mb-2">
|
||||
<div class="form-group">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
<i class="mdi mdi-18px mdi-translate mr-1" />
|
||||
{{ $t('word.language') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<select
|
||||
v-model="localLocale"
|
||||
class="form-select"
|
||||
@change="changeLocale(localLocale)"
|
||||
>
|
||||
{{ locale.name }}
|
||||
</option>
|
||||
</select>
|
||||
<option
|
||||
v-for="(locale, key) in locales"
|
||||
:key="key"
|
||||
:value="locale.code"
|
||||
>
|
||||
{{ locale.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.dataTabPageSize') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<select
|
||||
v-model="localPageSize"
|
||||
class="form-select"
|
||||
@change="changePageSize(+localPageSize)"
|
||||
>
|
||||
<option
|
||||
v-for="size in pageSizes"
|
||||
:key="size"
|
||||
<div class="form-group">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.dataTabPageSize') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<select
|
||||
v-model="localPageSize"
|
||||
class="form-select"
|
||||
@change="changePageSize(+localPageSize)"
|
||||
>
|
||||
{{ size }}
|
||||
</option>
|
||||
</select>
|
||||
<option
|
||||
v-for="size in pageSizes"
|
||||
:key="size"
|
||||
>
|
||||
{{ size }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-0">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.restorePreviourSession') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleRestoreSession">
|
||||
<input type="checkbox" :checked="restoreTabs">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-0">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.disableBlur') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleDisableBlur">
|
||||
<input type="checkbox" :checked="disableBlur">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.notificationsTimeout') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<div class="input-group">
|
||||
<input
|
||||
v-model="localTimeout"
|
||||
class="form-input"
|
||||
type="number"
|
||||
min="1"
|
||||
@focusout="checkNotificationsTimeout"
|
||||
>
|
||||
<span class="input-group-addon">{{ $t('word.seconds') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-0">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.restorePreviourSession') }}
|
||||
</label>
|
||||
|
||||
<div class="column col-12 h6 mt-4 text-uppercase mb-1">
|
||||
{{ $t('word.editor') }}
|
||||
</div>
|
||||
<div class="column col-9 col-sm-12">
|
||||
<div class="form-group mb-0">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('word.autoCompletion') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleAutoComplete">
|
||||
<input type="checkbox" :checked="selectedAutoComplete">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleRestoreSession">
|
||||
<input type="checkbox" :checked="restoreTabs">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
<div class="form-group mb-0">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.wrapLongLines') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleLineWrap">
|
||||
<input type="checkbox" :checked="selectedLineWrap">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-0">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.disableBlur') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleDisableBlur">
|
||||
<input type="checkbox" :checked="disableBlur">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="selectedTab === 'themes'" class="panel-body py-4">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column col-12 h6 text-uppercase mb-2">
|
||||
{{ $t('message.applicationTheme') }}
|
||||
</div>
|
||||
<div
|
||||
class="column col-6 c-hand theme-block"
|
||||
:class="{'selected': applicationTheme === 'dark'}"
|
||||
@click="changeApplicationTheme('dark')"
|
||||
>
|
||||
<img src="../images/dark.png" class="img-responsive img-fit-cover s-rounded">
|
||||
<div class="theme-name text-light">
|
||||
<i class="mdi mdi-moon-waning-crescent mdi-48px" />
|
||||
<div class="h6 mt-4">
|
||||
{{ $t('word.dark') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.notificationsTimeout') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<div class="input-group">
|
||||
<input
|
||||
v-model="localTimeout"
|
||||
class="form-input"
|
||||
type="number"
|
||||
min="1"
|
||||
@focusout="checkNotificationsTimeout"
|
||||
>
|
||||
<span class="input-group-addon">{{ $t('word.seconds') }}</span>
|
||||
<div
|
||||
class="column col-6 c-hand theme-block"
|
||||
:class="{'selected': applicationTheme === 'light'}"
|
||||
@click="changeApplicationTheme('light')"
|
||||
>
|
||||
<img src="../images/light.png" class="img-responsive img-fit-cover s-rounded">
|
||||
<div class="theme-name text-dark">
|
||||
<i class="mdi mdi-white-balance-sunny mdi-48px" />
|
||||
<div class="h6 mt-4">
|
||||
{{ $t('word.light') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column col-12 h6 mt-4 text-uppercase mb-1">
|
||||
{{ $t('word.editor') }}
|
||||
</div>
|
||||
<div class="column col-9 col-sm-12">
|
||||
<div class="form-group mb-0">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('word.autoCompletion') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleAutoComplete">
|
||||
<input type="checkbox" :checked="selectedAutoComplete">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
<div class="columns mt-4">
|
||||
<div class="column col-12 h6 text-uppercase mb-2 mt-4">
|
||||
{{ $t('message.editorTheme') }}
|
||||
</div>
|
||||
<div class="form-group mb-0">
|
||||
<div class="col-7 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.wrapLongLines') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-5 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleLineWrap">
|
||||
<input type="checkbox" :checked="selectedLineWrap">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="selectedTab === 'themes'" class="panel-body py-4">
|
||||
<div class="container">
|
||||
<div class="columns">
|
||||
<div class="column col-12 h6 text-uppercase mb-2">
|
||||
{{ $t('message.applicationTheme') }}
|
||||
</div>
|
||||
<div
|
||||
class="column col-6 c-hand theme-block"
|
||||
:class="{'selected': applicationTheme === 'dark'}"
|
||||
@click="changeApplicationTheme('dark')"
|
||||
>
|
||||
<img src="../images/dark.png" class="img-responsive img-fit-cover s-rounded">
|
||||
<div class="theme-name text-light">
|
||||
<i class="mdi mdi-moon-waning-crescent mdi-48px" />
|
||||
<div class="h6 mt-4">
|
||||
{{ $t('word.dark') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="column col-6 c-hand theme-block"
|
||||
:class="{'selected': applicationTheme === 'light'}"
|
||||
@click="changeApplicationTheme('light')"
|
||||
>
|
||||
<img src="../images/light.png" class="img-responsive img-fit-cover s-rounded">
|
||||
<div class="theme-name text-dark">
|
||||
<i class="mdi mdi-white-balance-sunny mdi-48px" />
|
||||
<div class="h6 mt-4">
|
||||
{{ $t('word.light') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="columns mt-4">
|
||||
<div class="column col-12 h6 text-uppercase mb-2 mt-4">
|
||||
{{ $t('message.editorTheme') }}
|
||||
</div>
|
||||
<div class="column col-6 h5 mb-4">
|
||||
<select
|
||||
v-model="localEditorTheme"
|
||||
class="form-select"
|
||||
@change="changeEditorTheme(localEditorTheme)"
|
||||
>
|
||||
<optgroup
|
||||
v-for="group in editorThemes"
|
||||
:key="group.group"
|
||||
:label="group.group"
|
||||
<div class="column col-6 h5 mb-4">
|
||||
<select
|
||||
v-model="localEditorTheme"
|
||||
class="form-select"
|
||||
@change="changeEditorTheme(localEditorTheme)"
|
||||
>
|
||||
<option
|
||||
v-for="theme in group.themes"
|
||||
:key="theme.name"
|
||||
:value="theme.code"
|
||||
:selected="editorTheme === theme.code"
|
||||
<optgroup
|
||||
v-for="group in editorThemes"
|
||||
:key="group.group"
|
||||
:label="group.group"
|
||||
>
|
||||
{{ theme.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="column col-6 mb-4">
|
||||
<div class="btn-group btn-group-block">
|
||||
<button
|
||||
class="btn btn-dark cut-text"
|
||||
:class="{'active': editorFontSize === 'small'}"
|
||||
@click="changeEditorFontSize('small')"
|
||||
>
|
||||
{{ $t('word.small') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark cut-text"
|
||||
:class="{'active': editorFontSize === 'medium'}"
|
||||
@click="changeEditorFontSize('medium')"
|
||||
>
|
||||
{{ $t('word.medium') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark cut-text"
|
||||
:class="{'active': editorFontSize === 'large'}"
|
||||
@click="changeEditorFontSize('large')"
|
||||
>
|
||||
{{ $t('word.large') }}
|
||||
</button>
|
||||
<option
|
||||
v-for="theme in group.themes"
|
||||
:key="theme.name"
|
||||
:value="theme.code"
|
||||
:selected="editorTheme === theme.code"
|
||||
>
|
||||
{{ theme.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div class="column col-6 mb-4">
|
||||
<div class="btn-group btn-group-block">
|
||||
<button
|
||||
class="btn btn-dark cut-text"
|
||||
:class="{'active': editorFontSize === 'small'}"
|
||||
@click="changeEditorFontSize('small')"
|
||||
>
|
||||
{{ $t('word.small') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark cut-text"
|
||||
:class="{'active': editorFontSize === 'medium'}"
|
||||
@click="changeEditorFontSize('medium')"
|
||||
>
|
||||
{{ $t('word.medium') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark cut-text"
|
||||
:class="{'active': editorFontSize === 'large'}"
|
||||
@click="changeEditorFontSize('large')"
|
||||
>
|
||||
{{ $t('word.large') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-12">
|
||||
<BaseTextEditor
|
||||
:model-value="exampleQuery"
|
||||
mode="sql"
|
||||
:workspace="workspace"
|
||||
:read-only="true"
|
||||
:height="270"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column col-12">
|
||||
<BaseTextEditor
|
||||
:value="exampleQuery"
|
||||
mode="sql"
|
||||
:workspace="workspace"
|
||||
:read-only="true"
|
||||
:height="270"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="selectedTab === 'update'" class="panel-body py-4">
|
||||
<ModalSettingsUpdate />
|
||||
</div>
|
||||
<div v-show="selectedTab === 'changelog'" class="panel-body py-4">
|
||||
<ModalSettingsChangelog />
|
||||
</div>
|
||||
<div v-show="selectedTab === 'update'" class="panel-body py-4">
|
||||
<ModalSettingsUpdate />
|
||||
</div>
|
||||
<div v-show="selectedTab === 'changelog'" class="panel-body py-4">
|
||||
<ModalSettingsChangelog />
|
||||
</div>
|
||||
|
||||
<div v-show="selectedTab === 'about'" class="panel-body py-4">
|
||||
<div class="text-center">
|
||||
<img src="../images/logo.svg" width="128">
|
||||
<h4>{{ appName }}</h4>
|
||||
<p class="mb-2">
|
||||
{{ $t('word.version') }} {{ appVersion }}<br>
|
||||
<a class="c-hand" @click="openOutside('https://github.com/antares-sql/antares')"><i class="mdi mdi-github d-inline" /> GitHub</a> • <a class="c-hand" @click="openOutside('https://twitter.com/AntaresSQL')"><i class="mdi mdi-twitter d-inline" /> Twitter</a> • <a class="c-hand" @click="openOutside('https://antares-sql.app/')"><i class="mdi mdi-web d-inline" /> Website</a><br>
|
||||
<small>{{ $t('word.author') }} <a class="c-hand" @click="openOutside('https://github.com/Fabio286')">{{ appAuthor }}</a></small><br>
|
||||
</p>
|
||||
<div class="mb-2">
|
||||
<small class="d-block text-uppercase">{{ $t('word.contributors') }}:</small>
|
||||
<div class="d-block py-1">
|
||||
<small v-for="(contributor, i) in otherContributors" :key="i">{{ i !== 0 ? ', ' : '' }}{{ contributor }}</small>
|
||||
<div v-show="selectedTab === 'about'" class="panel-body py-4">
|
||||
<div class="text-center">
|
||||
<img src="../images/logo.svg" width="128">
|
||||
<h4>{{ appName }}</h4>
|
||||
<p class="mb-2">
|
||||
{{ $t('word.version') }} {{ appVersion }}<br>
|
||||
<a class="c-hand" @click="openOutside('https://github.com/antares-sql/antares')"><i class="mdi mdi-github d-inline" /> GitHub</a> • <a class="c-hand" @click="openOutside('https://twitter.com/AntaresSQL')"><i class="mdi mdi-twitter d-inline" /> Twitter</a> • <a class="c-hand" @click="openOutside('https://antares-sql.app/')"><i class="mdi mdi-web d-inline" /> Website</a><br>
|
||||
<small>{{ $t('word.author') }} <a class="c-hand" @click="openOutside('https://github.com/Fabio286')">{{ appAuthor }}</a></small><br>
|
||||
</p>
|
||||
<div class="mb-2">
|
||||
<small class="d-block text-uppercase">{{ $t('word.contributors') }}:</small>
|
||||
<div class="d-block py-1">
|
||||
<small v-for="(contributor, i) in otherContributors" :key="i">{{ i !== 0 ? ', ' : '' }}{{ contributor }}</small>
|
||||
</div>
|
||||
<small>{{ $t('message.madeWithJS') }}</small>
|
||||
</div>
|
||||
<small>{{ $t('message.madeWithJS') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { shell } from 'electron';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import localesNames from '@/i18n/supported-locales';
|
||||
import ModalSettingsUpdate from '@/components/ModalSettingsUpdate';
|
||||
import ModalSettingsChangelog from '@/components/ModalSettingsChangelog';
|
||||
import BaseTextEditor from '@/components/BaseTextEditor';
|
||||
const { shell } = require('electron');
|
||||
|
||||
export default {
|
||||
name: 'ModalSettings',
|
||||
|
@ -330,6 +335,79 @@ export default {
|
|||
ModalSettingsChangelog,
|
||||
BaseTextEditor
|
||||
},
|
||||
setup () {
|
||||
const applicationStore = useApplicationStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const {
|
||||
selectedSettingTab,
|
||||
updateStatus
|
||||
} = storeToRefs(applicationStore);
|
||||
const {
|
||||
locale: selectedLocale,
|
||||
dataTabLimit: pageSize,
|
||||
autoComplete: selectedAutoComplete,
|
||||
lineWrap: selectedLineWrap,
|
||||
notificationsTimeout,
|
||||
restoreTabs,
|
||||
disableBlur,
|
||||
applicationTheme,
|
||||
editorTheme,
|
||||
editorFontSize
|
||||
} = storeToRefs(settingsStore);
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
changeLocale,
|
||||
changePageSize,
|
||||
changeRestoreTabs,
|
||||
changeDisableBlur,
|
||||
changeAutoComplete,
|
||||
changeLineWrap,
|
||||
changeApplicationTheme,
|
||||
changeEditorTheme,
|
||||
changeEditorFontSize,
|
||||
updateNotificationsTimeout
|
||||
} = settingsStore;
|
||||
const {
|
||||
hideSettingModal,
|
||||
appName,
|
||||
appVersion
|
||||
} = applicationStore;
|
||||
const { getWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
appName,
|
||||
appVersion,
|
||||
selectedSettingTab,
|
||||
updateStatus,
|
||||
closeModal: hideSettingModal,
|
||||
selectedLocale,
|
||||
pageSize,
|
||||
selectedAutoComplete,
|
||||
selectedLineWrap,
|
||||
notificationsTimeout,
|
||||
restoreTabs,
|
||||
disableBlur,
|
||||
applicationTheme,
|
||||
editorTheme,
|
||||
editorFontSize,
|
||||
changeLocale,
|
||||
changePageSize,
|
||||
changeRestoreTabs,
|
||||
changeDisableBlur,
|
||||
changeAutoComplete,
|
||||
changeLineWrap,
|
||||
changeApplicationTheme,
|
||||
changeEditorTheme,
|
||||
changeEditorFontSize,
|
||||
updateNotificationsTimeout,
|
||||
selectedWorkspace,
|
||||
getWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
appAuthor: 'Fabio Di Stasio',
|
||||
|
@ -392,24 +470,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
appName: 'application/appName',
|
||||
appVersion: 'application/appVersion',
|
||||
selectedSettingTab: 'application/selectedSettingTab',
|
||||
selectedLocale: 'settings/getLocale',
|
||||
pageSize: 'settings/getDataTabLimit',
|
||||
selectedAutoComplete: 'settings/getAutoComplete',
|
||||
selectedLineWrap: 'settings/getLineWrap',
|
||||
notificationsTimeout: 'settings/getNotificationsTimeout',
|
||||
restoreTabs: 'settings/getRestoreTabs',
|
||||
disableBlur: 'settings/getDisableBlur',
|
||||
applicationTheme: 'settings/getApplicationTheme',
|
||||
editorTheme: 'settings/getEditorTheme',
|
||||
editorFontSize: 'settings/getEditorFontSize',
|
||||
updateStatus: 'application/getUpdateStatus',
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
locales () {
|
||||
const locales = [];
|
||||
for (const locale of this.$i18n.availableLocales)
|
||||
|
@ -455,23 +515,10 @@ ORDER BY
|
|||
this.selectedTab = this.selectedSettingTab;
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
closeModal: 'application/hideSettingModal',
|
||||
changeLocale: 'settings/changeLocale',
|
||||
changePageSize: 'settings/changePageSize',
|
||||
changeRestoreTabs: 'settings/changeRestoreTabs',
|
||||
changeDisableBlur: 'settings/changeDisableBlur',
|
||||
changeAutoComplete: 'settings/changeAutoComplete',
|
||||
changeLineWrap: 'settings/changeLineWrap',
|
||||
changeApplicationTheme: 'settings/changeApplicationTheme',
|
||||
changeEditorTheme: 'settings/changeEditorTheme',
|
||||
changeEditorFontSize: 'settings/changeEditorFontSize',
|
||||
updateNotificationsTimeout: 'settings/updateNotificationsTimeout'
|
||||
}),
|
||||
selectTab (tab) {
|
||||
this.selectedTab = tab;
|
||||
},
|
||||
|
|
|
@ -15,15 +15,19 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { marked } from 'marked';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
|
||||
export default {
|
||||
name: 'ModalSettingsChangelog',
|
||||
components: {
|
||||
BaseLoader
|
||||
},
|
||||
setup () {
|
||||
const { appVersion } = useApplicationStore();
|
||||
return { appVersion };
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
changelog: '',
|
||||
|
@ -32,9 +36,6 @@ export default {
|
|||
isError: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ appVersion: 'application/appVersion' })
|
||||
},
|
||||
created () {
|
||||
this.getChangelog();
|
||||
},
|
||||
|
|
|
@ -53,17 +53,33 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { ipcRenderer, shell } from 'electron';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
|
||||
export default {
|
||||
name: 'ModalSettingsUpdate',
|
||||
setup () {
|
||||
const applicationStore = useApplicationStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const {
|
||||
updateStatus,
|
||||
getDownloadProgress
|
||||
} = storeToRefs(applicationStore);
|
||||
const { allowPrerelease } = storeToRefs(settingsStore);
|
||||
|
||||
const { changeAllowPrerelease } = settingsStore;
|
||||
|
||||
return {
|
||||
updateStatus,
|
||||
downloadPercentage: getDownloadProgress,
|
||||
allowPrerelease,
|
||||
changeAllowPrerelease
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
updateStatus: 'application/getUpdateStatus',
|
||||
downloadPercentage: 'application/getDownloadProgress',
|
||||
allowPrerelease: 'settings/getAllowPrerelease'
|
||||
}),
|
||||
updateMessage () {
|
||||
switch (this.updateStatus) {
|
||||
case 'noupdate':
|
||||
|
@ -86,9 +102,6 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
changeAllowPrerelease: 'settings/changeAllowPrerelease'
|
||||
}),
|
||||
openOutside (link) {
|
||||
shell.openExternal(link);
|
||||
},
|
||||
|
|
|
@ -12,13 +12,16 @@
|
|||
import * as ace from 'ace-builds';
|
||||
import 'ace-builds/webpack-resolver';
|
||||
import '../libs/ext-language_tools';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
|
||||
export default {
|
||||
name: 'QueryEditor',
|
||||
props: {
|
||||
value: String,
|
||||
modelValue: String,
|
||||
workspace: Object,
|
||||
isSelected: Boolean,
|
||||
schema: { type: String, default: '' },
|
||||
|
@ -26,23 +29,42 @@ export default {
|
|||
readOnly: { type: Boolean, default: false },
|
||||
height: { type: Number, default: 200 }
|
||||
},
|
||||
emits: ['update:modelValue'],
|
||||
setup () {
|
||||
const editor = null;
|
||||
const applicationStore = useApplicationStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const { setBaseCompleters } = applicationStore;
|
||||
|
||||
const { baseCompleter } = storeToRefs(applicationStore);
|
||||
const {
|
||||
editorTheme,
|
||||
editorFontSize,
|
||||
autoComplete,
|
||||
lineWrap
|
||||
} = storeToRefs(settingsStore);
|
||||
|
||||
return {
|
||||
editor,
|
||||
baseCompleter,
|
||||
setBaseCompleters,
|
||||
editorTheme,
|
||||
editorFontSize,
|
||||
autoComplete,
|
||||
lineWrap
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
editor: null,
|
||||
cursorPosition: 0,
|
||||
fields: [],
|
||||
customCompleter: [],
|
||||
id: null,
|
||||
id: uidGen(),
|
||||
lastSchema: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
editorTheme: 'settings/getEditorTheme',
|
||||
editorFontSize: 'settings/getEditorFontSize',
|
||||
autoComplete: 'settings/getAutoComplete',
|
||||
lineWrap: 'settings/getLineWrap',
|
||||
baseCompleter: 'application/getBaseCompleter'
|
||||
}),
|
||||
tables () {
|
||||
return this.workspace
|
||||
? this.workspace.structure.filter(schema => schema.name === this.schema)
|
||||
|
@ -127,11 +149,8 @@ export default {
|
|||
return 'sql';
|
||||
}
|
||||
},
|
||||
cursorPosition () {
|
||||
return this.editor.session.doc.positionToIndex(this.editor.getCursorPosition());
|
||||
},
|
||||
lastWord () {
|
||||
const charsBefore = this.value.slice(0, this.cursorPosition);
|
||||
const charsBefore = this.modelValue.slice(0, this.cursorPosition);
|
||||
const words = charsBefore.replaceAll('\n', ' ').split(' ').filter(Boolean);
|
||||
return words.pop();
|
||||
},
|
||||
|
@ -155,6 +174,9 @@ export default {
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
modelValue () {
|
||||
this.cursorPosition = this.editor.session.doc.positionToIndex(this.editor.getCursorPosition());
|
||||
},
|
||||
editorTheme () {
|
||||
if (this.editor)
|
||||
this.editor.setTheme(`ace/theme/${this.editorTheme}`);
|
||||
|
@ -205,14 +227,13 @@ export default {
|
|||
}
|
||||
},
|
||||
created () {
|
||||
this.id = this._uid;
|
||||
this.lastSchema = this.schema;
|
||||
},
|
||||
mounted () {
|
||||
this.editor = ace.edit(`editor-${this.id}`, {
|
||||
mode: `ace/mode/${this.mode}`,
|
||||
theme: `ace/theme/${this.editorTheme}`,
|
||||
value: this.value,
|
||||
value: this.modelValue,
|
||||
fontSize: '14px',
|
||||
printMargin: false,
|
||||
readOnly: this.readOnly
|
||||
|
@ -263,7 +284,7 @@ export default {
|
|||
|
||||
this.editor.session.on('change', () => {
|
||||
const content = this.editor.getValue();
|
||||
this.$emit('update:value', content);
|
||||
this.$emit('update:modelValue', content);
|
||||
});
|
||||
|
||||
this.editor.on('guttermousedown', e => {
|
||||
|
@ -294,9 +315,6 @@ export default {
|
|||
}, 20);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
setBaseCompleters: 'application/setBaseCompleter'
|
||||
}),
|
||||
setCustomCompleter () {
|
||||
this.editor.completers.push({
|
||||
getCompletions: (editor, session, pos, prefix, callback) => {
|
||||
|
|
|
@ -30,10 +30,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
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';
|
||||
|
||||
export default {
|
||||
name: 'SettingBarContext',
|
||||
|
@ -45,6 +47,26 @@ export default {
|
|||
contextEvent: MouseEvent,
|
||||
contextConnection: Object
|
||||
},
|
||||
emits: ['close-context'],
|
||||
setup () {
|
||||
const {
|
||||
getConnectionName,
|
||||
addConnection,
|
||||
deleteConnection
|
||||
} = useConnectionsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { selectWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
getConnectionName,
|
||||
addConnection,
|
||||
deleteConnection,
|
||||
selectedWorkspace,
|
||||
selectWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isConfirmModal: false,
|
||||
|
@ -52,20 +74,11 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getConnectionName: 'connections/getConnectionName',
|
||||
selectedWorkspace: 'workspaces/getSelected'
|
||||
}),
|
||||
connectionName () {
|
||||
return this.getConnectionName(this.contextConnection.uid);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addConnection: 'connections/addConnection',
|
||||
deleteConnection: 'connections/deleteConnection',
|
||||
selectWorkspace: 'workspaces/selectWorkspace'
|
||||
}),
|
||||
confirmDeleteConnection () {
|
||||
if (this.selectedWorkspace === this.contextConnection.uid)
|
||||
this.selectWorkspace();
|
||||
|
@ -77,7 +90,7 @@ export default {
|
|||
connectionCopy = {
|
||||
...connectionCopy,
|
||||
uid: uidGen('C'),
|
||||
name: connectionCopy.name ? `${connectionCopy.name}_copy` : ''
|
||||
name: connectionCopy.name ? `${connectionCopy?.name}_copy` : ''
|
||||
};
|
||||
|
||||
this.addConnection(connectionCopy);
|
||||
|
|
|
@ -27,17 +27,30 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { storeToRefs } from 'pinia';
|
||||
const { shell } = require('electron');
|
||||
|
||||
export default {
|
||||
name: 'TheFooter',
|
||||
setup () {
|
||||
const applicationStore = useApplicationStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: workspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { appVersion, showSettingModal } = applicationStore;
|
||||
const { getWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
appVersion,
|
||||
showSettingModal,
|
||||
workspace,
|
||||
getWorkspace
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
workspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
appVersion: 'application/appVersion'
|
||||
}),
|
||||
version () {
|
||||
return this.getWorkspace(this.workspace) ? this.getWorkspace(this.workspace).version : null;
|
||||
},
|
||||
|
@ -48,9 +61,6 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
showSettingModal: 'application/showSettingModal'
|
||||
}),
|
||||
openOutside (link) {
|
||||
shell.openExternal(link);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
@mouseenter="clearTimeouts"
|
||||
@mouseleave="rearmTimeouts"
|
||||
>
|
||||
<transition-group name="slide-fade">
|
||||
<TransitionGroup tag="div" name="slide-fade">
|
||||
<BaseNotification
|
||||
v-for="notification in latestNotifications"
|
||||
:key="notification.uid"
|
||||
|
@ -12,29 +12,42 @@
|
|||
:status="notification.status"
|
||||
@close="removeNotification(notification.uid)"
|
||||
/>
|
||||
</transition-group>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import BaseNotification from '@/components/BaseNotification';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'TheNotificationsBoard',
|
||||
components: {
|
||||
BaseNotification
|
||||
},
|
||||
setup () {
|
||||
const notificationsStore = useNotificationsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const { removeNotification } = notificationsStore;
|
||||
|
||||
const { notifications } = storeToRefs(notificationsStore);
|
||||
const { notificationsTimeout } = storeToRefs(settingsStore);
|
||||
|
||||
return {
|
||||
removeNotification,
|
||||
notifications,
|
||||
notificationsTimeout
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
timeouts: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
notifications: 'notifications/getNotifications',
|
||||
notificationsTimeout: 'settings/getNotificationsTimeout'
|
||||
}),
|
||||
latestNotifications () {
|
||||
return this.notifications.slice(0, 10);
|
||||
}
|
||||
|
@ -51,9 +64,6 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
removeNotification: 'notifications/removeNotification'
|
||||
}),
|
||||
clearTimeouts () {
|
||||
for (const uid in this.timeouts) {
|
||||
clearTimeout(this.timeouts[uid]);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<div>
|
||||
<div>
|
||||
<TextEditor
|
||||
:value.sync="localNotes"
|
||||
v-model="localNotes"
|
||||
editor-class="textarea-editor"
|
||||
mode="markdown"
|
||||
:auto-focus="true"
|
||||
|
@ -29,9 +29,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import TextEditor from '@/components/BaseTextEditor';
|
||||
import { useScratchpadStore } from '@/stores/scratchpad';
|
||||
|
||||
export default {
|
||||
name: 'TheScratchpad',
|
||||
|
@ -39,17 +41,26 @@ export default {
|
|||
ConfirmModal,
|
||||
TextEditor
|
||||
},
|
||||
emits: ['hide'],
|
||||
setup () {
|
||||
const applicationStore = useApplicationStore();
|
||||
const scratchpadStore = useScratchpadStore();
|
||||
|
||||
const { notes } = storeToRefs(scratchpadStore);
|
||||
const { changeNotes } = scratchpadStore;
|
||||
|
||||
return {
|
||||
notes,
|
||||
hideScratchpad: applicationStore.hideScratchpad,
|
||||
changeNotes
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localNotes: '',
|
||||
debounceTimeout: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
notes: 'scratchpad/getNotes'
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
localNotes () {
|
||||
clearTimeout(this.debounceTimeout);
|
||||
|
@ -63,10 +74,6 @@ export default {
|
|||
this.localNotes = this.notes;
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
hideScratchpad: 'application/hideScratchpad',
|
||||
changeNotes: 'scratchpad/changeNotes'
|
||||
}),
|
||||
hideModal () {
|
||||
this.$emit('hide');
|
||||
}
|
||||
|
|
|
@ -10,22 +10,23 @@
|
|||
<ul class="settingbar-elements">
|
||||
<Draggable
|
||||
v-model="connections"
|
||||
:item-key="'uid'"
|
||||
@start="isDragging = true"
|
||||
@end="dragStop"
|
||||
>
|
||||
<li
|
||||
v-for="connection in connections"
|
||||
:key="connection.uid"
|
||||
draggable="true"
|
||||
class="settingbar-element btn btn-link ex-tooltip"
|
||||
:class="{'selected': connection.uid === selectedWorkspace}"
|
||||
@click.stop="selectWorkspace(connection.uid)"
|
||||
@contextmenu.prevent="contextMenu($event, connection)"
|
||||
@mouseover.self="tooltipPosition"
|
||||
>
|
||||
<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>
|
||||
</li>
|
||||
<template #item="{element}">
|
||||
<li
|
||||
:draggable="true"
|
||||
class="settingbar-element btn btn-link ex-tooltip"
|
||||
:class="{'selected': element.uid === selectedWorkspace}"
|
||||
@click.stop="selectWorkspace(element.uid)"
|
||||
@contextmenu.prevent="contextMenu($event, element)"
|
||||
@mouseover.self="tooltipPosition"
|
||||
>
|
||||
<i class="settingbar-element-icon dbi" :class="`dbi-${element.client} ${getStatusBadge(element.uid)}`" />
|
||||
<span v-if="!isDragging" class="ex-tooltip-content">{{ getConnectionName(element.uid) }}</span>
|
||||
</li>
|
||||
</template>
|
||||
</Draggable>
|
||||
<li
|
||||
class="settingbar-element btn btn-link ex-tooltip"
|
||||
|
@ -55,7 +56,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useApplicationStore } from '@/stores/application';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Draggable from 'vuedraggable';
|
||||
import SettingBarContext from '@/components/SettingBarContext';
|
||||
|
||||
|
@ -65,6 +69,32 @@ export default {
|
|||
Draggable,
|
||||
SettingBarContext
|
||||
},
|
||||
setup () {
|
||||
const applicationStore = useApplicationStore();
|
||||
const connectionsStore = useConnectionsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { updateStatus } = storeToRefs(applicationStore);
|
||||
const { connections: getConnections } = storeToRefs(connectionsStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { showSettingModal, showScratchpad } = applicationStore;
|
||||
const { getConnectionName, updateConnections } = connectionsStore;
|
||||
const { getWorkspace, selectWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
applicationStore,
|
||||
updateStatus,
|
||||
showSettingModal,
|
||||
showScratchpad,
|
||||
getConnections,
|
||||
getConnectionName,
|
||||
updateConnections,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
selectWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dragElement: null,
|
||||
|
@ -76,13 +106,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getConnections: 'connections/getConnections',
|
||||
getConnectionName: 'connections/getConnectionName',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
updateStatus: 'application/getUpdateStatus'
|
||||
}),
|
||||
connections: {
|
||||
get () {
|
||||
return this.getConnections;
|
||||
|
@ -96,12 +119,6 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
updateConnections: 'connections/updateConnections',
|
||||
showSettingModal: 'application/showSettingModal',
|
||||
showScratchpad: 'application/showScratchpad',
|
||||
selectWorkspace: 'workspaces/selectWorkspace'
|
||||
}),
|
||||
contextMenu (event, connection) {
|
||||
this.contextEvent = event;
|
||||
this.contextConnection = connection;
|
||||
|
|
|
@ -55,10 +55,26 @@
|
|||
<script>
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { getCurrentWindow } from '@electron/remote';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'TheTitleBar',
|
||||
setup () {
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
getConnectionName,
|
||||
selectedWorkspace,
|
||||
getWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
w: getCurrentWindow(),
|
||||
|
@ -68,11 +84,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getConnectionName: 'connections/getConnectionName',
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
windowTitle () {
|
||||
if (!this.selectedWorkspace) return '';
|
||||
if (this.selectedWorkspace === 'NEW') return this.$t('message.createNewConnection');
|
||||
|
@ -87,7 +98,7 @@ export default {
|
|||
created () {
|
||||
window.addEventListener('resize', this.onResize);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.onResize);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,264 +1,265 @@
|
|||
<template>
|
||||
<div v-show="isSelected" class="workspace column columns col-gapless">
|
||||
<WorkspaceExploreBar
|
||||
v-if="workspace.connectionStatus === 'connected'"
|
||||
v-if="workspace?.connectionStatus === 'connected'"
|
||||
:connection="connection"
|
||||
:is-selected="isSelected"
|
||||
/>
|
||||
<div v-if="workspace.connectionStatus === 'connected'" class="workspace-tabs column columns col-gapless">
|
||||
<div v-if="workspace?.connectionStatus === 'connected'" class="workspace-tabs column columns col-gapless">
|
||||
<Draggable
|
||||
ref="tabWrap"
|
||||
v-model="draggableTabs"
|
||||
tag="ul"
|
||||
item-key="uid"
|
||||
group="tabs"
|
||||
class="tab tab-block column col-12"
|
||||
draggable=".tab-draggable"
|
||||
@mouseover.native="addWheelEvent"
|
||||
@mouseover="addWheelEvent"
|
||||
>
|
||||
<li
|
||||
v-for="(tab, i) of draggableTabs"
|
||||
:key="i"
|
||||
class="tab-item tab-draggable"
|
||||
draggable="true"
|
||||
:class="{'active': selectedTab === tab.uid}"
|
||||
@mousedown.left="selectTab({uid: workspace.uid, tab: tab.uid})"
|
||||
@mouseup.middle="closeTab(tab)"
|
||||
>
|
||||
<a
|
||||
v-if="tab.type === 'query'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
<template #item="{element}">
|
||||
<li
|
||||
class="tab-item tab-draggable"
|
||||
:draggable="true"
|
||||
:class="{'active': selectedTab === element.uid}"
|
||||
@mousedown.left="selectTab({uid: workspace.uid, tab: element.uid})"
|
||||
@mouseup.middle="closeTab(element)"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-code-tags mr-1" />
|
||||
<span>
|
||||
<span>{{ tab.content || 'Query' | cutText }} #{{ tab.index }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-if="element.type === 'query'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-code-tags mr-1" />
|
||||
<span>
|
||||
<span>{{ cutText(element.content || 'Query') }} #{{ element.index }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'temp-data'"
|
||||
class="tab-link"
|
||||
@dblclick="openAsPermanentTab(tab)"
|
||||
>
|
||||
<i class="mdi mdi-18px mr-1" :class="tab.elementType === 'view' ? 'mdi-table-eye' : 'mdi-table'" />
|
||||
<span :title="`${$t('word.data').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
<span class=" text-italic">{{ tab.elementName | cutText }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'temp-data'"
|
||||
class="tab-link"
|
||||
@dblclick="openAsPermanentTab(element)"
|
||||
>
|
||||
<i class="mdi mdi-18px mr-1" :class="element.elementType === 'view' ? 'mdi-table-eye' : 'mdi-table'" />
|
||||
<span :title="`${$t('word.data').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
<span class=" text-italic">{{ cutText(element.elementName) }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a v-else-if="tab.type === 'data'" class="tab-link">
|
||||
<i class="mdi mdi-18px mr-1" :class="tab.elementType === 'view' ? 'mdi-table-eye' : 'mdi-table'" />
|
||||
<span :title="`${$t('word.data').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ tab.elementName | cutText }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a v-else-if="element.type === 'data'" class="tab-link">
|
||||
<i class="mdi mdi-18px mr-1" :class="element.elementType === 'view' ? 'mdi-table-eye' : 'mdi-table'" />
|
||||
<span :title="`${$t('word.data').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ cutText(element.elementName) }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'new-table'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ $t('message.newTable') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'new-table'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ $t('message.newTable') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'table-props'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-tune-vertical-variant mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ tab.elementName | cutText }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'table-props'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-tune-vertical-variant mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ cutText(element.elementName) }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'view-props'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-tune-vertical-variant mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.view`)}`">
|
||||
{{ tab.elementName | cutText }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'view-props'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-tune-vertical-variant mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.view`)}`">
|
||||
{{ cutText(element.elementName) }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'new-view'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ $t('message.newView') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'new-view'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ $t('message.newView') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'new-trigger'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ $t('message.newTrigger') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'new-trigger'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ $t('message.newTrigger') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'new-routine'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ $t('message.newRoutine') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'new-routine'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ $t('message.newRoutine') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'new-function'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ $t('message.newFunction') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'new-function'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ $t('message.newFunction') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'new-trigger-function'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ $t('message.newTriggerFunction') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'new-trigger-function'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ $t('message.newTriggerFunction') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'new-scheduler'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ $t('message.newScheduler') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type === 'new-scheduler'"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-shape-square-plus mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.new').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ $t('message.newScheduler') }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type.includes('temp-')"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
@dblclick="openAsPermanentTab(tab)"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
<span class=" text-italic">{{ tab.elementName | cutText }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="element.type.includes('temp-')"
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
@dblclick="openAsPermanentTab(element)"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
<span class=" text-italic">{{ cutText(element.elementName) }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${tab.elementType}`)}`">
|
||||
{{ tab.elementName | cutText }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<a
|
||||
v-else
|
||||
class="tab-link"
|
||||
:class="{'badge': element.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${$tc(`word.${element.elementType}`)}`">
|
||||
{{ cutText(element.elementName) }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@mousedown.left.stop
|
||||
@click.stop="closeTab(element)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</template>
|
||||
<template #header>
|
||||
<li
|
||||
v-if="workspace.customizations.processesList"
|
||||
|
@ -318,6 +319,7 @@
|
|||
<WorkspaceTabQuery
|
||||
v-if="tab.type==='query'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:connection="connection"
|
||||
|
@ -325,6 +327,7 @@
|
|||
<WorkspaceTabTable
|
||||
v-else-if="['temp-data', 'data'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:table="tab.elementName"
|
||||
|
@ -334,6 +337,7 @@
|
|||
<WorkspaceTabNewTable
|
||||
v-else-if="tab.type === 'new-table'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
|
@ -342,6 +346,7 @@
|
|||
<WorkspaceTabPropsTable
|
||||
v-else-if="tab.type === 'table-props'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:table="tab.elementName"
|
||||
|
@ -350,6 +355,7 @@
|
|||
<WorkspaceTabNewView
|
||||
v-else-if="tab.type === 'new-view'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
|
@ -358,6 +364,7 @@
|
|||
<WorkspaceTabPropsView
|
||||
v-else-if="tab.type === 'view-props'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:connection="connection"
|
||||
:view="tab.elementName"
|
||||
|
@ -366,6 +373,7 @@
|
|||
<WorkspaceTabNewTrigger
|
||||
v-else-if="tab.type === 'new-trigger'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
|
@ -375,6 +383,7 @@
|
|||
<WorkspaceTabPropsTrigger
|
||||
v-else-if="['temp-trigger-props', 'trigger-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:trigger="tab.elementName"
|
||||
|
@ -383,6 +392,7 @@
|
|||
<WorkspaceTabNewTriggerFunction
|
||||
v-else-if="tab.type === 'new-trigger-function'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
|
@ -392,6 +402,7 @@
|
|||
<WorkspaceTabPropsTriggerFunction
|
||||
v-else-if="['temp-trigger-function-props', 'trigger-function-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:function="tab.elementName"
|
||||
|
@ -400,6 +411,7 @@
|
|||
<WorkspaceTabNewRoutine
|
||||
v-else-if="tab.type === 'new-routine'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
|
@ -409,6 +421,7 @@
|
|||
<WorkspaceTabPropsRoutine
|
||||
v-else-if="['temp-routine-props', 'routine-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:routine="tab.elementName"
|
||||
|
@ -417,6 +430,7 @@
|
|||
<WorkspaceTabNewFunction
|
||||
v-else-if="tab.type === 'new-function'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
|
@ -426,6 +440,7 @@
|
|||
<WorkspaceTabPropsFunction
|
||||
v-else-if="['temp-function-props', 'function-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:function="tab.elementName"
|
||||
|
@ -434,6 +449,7 @@
|
|||
<WorkspaceTabNewScheduler
|
||||
v-else-if="tab.type === 'new-scheduler'"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:tab="tab"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
|
@ -443,6 +459,7 @@
|
|||
<WorkspaceTabPropsScheduler
|
||||
v-else-if="['temp-scheduler-props', 'scheduler-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:tab-uid="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:scheduler="tab.elementName"
|
||||
|
@ -468,9 +485,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Draggable from 'vuedraggable';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
|
||||
import WorkspaceEmptyState from '@/components/WorkspaceEmptyState';
|
||||
import WorkspaceExploreBar from '@/components/WorkspaceExploreBar';
|
||||
import WorkspaceEditConnectionPanel from '@/components/WorkspaceEditConnectionPanel';
|
||||
|
@ -521,18 +540,37 @@ export default {
|
|||
ModalProcessesList,
|
||||
ModalDiscardChanges
|
||||
},
|
||||
filters: {
|
||||
cutText (string) {
|
||||
const limit = 20;
|
||||
const escapedString = string.replace(/\s{2,}/g, ' ');
|
||||
if (escapedString.length > limit)
|
||||
return `${escapedString.substr(0, limit)}...`;
|
||||
return escapedString;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
setup () {
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
addWorkspace,
|
||||
connectWorkspace,
|
||||
removeConnected,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTab,
|
||||
updateTabs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
addWorkspace,
|
||||
connectWorkspace,
|
||||
removeConnected,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTab,
|
||||
updateTabs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
hasWheelEvent: false,
|
||||
|
@ -541,10 +579,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
|
@ -583,19 +617,25 @@ export default {
|
|||
return false;
|
||||
},
|
||||
hasTools () {
|
||||
return this.workspace.customizations.processesList ||
|
||||
if (!this.workspace.customizations) return false;
|
||||
else {
|
||||
return this.workspace.customizations.processesList ||
|
||||
this.workspace.customizations.usersManagement ||
|
||||
this.workspace.customizations.variables;
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
queryTabs: function (newVal, oldVal) {
|
||||
if (newVal.length > oldVal.length) {
|
||||
setTimeout(() => {
|
||||
const scroller = this.$refs.tabWrap;
|
||||
if (scroller) scroller.$el.scrollLeft = scroller.$el.scrollWidth;
|
||||
}, 0);
|
||||
}
|
||||
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 () {
|
||||
|
@ -605,19 +645,10 @@ export default {
|
|||
if (isInitiated)
|
||||
this.connectWorkspace(this.connection);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addWorkspace: 'workspaces/addWorkspace',
|
||||
connectWorkspace: 'workspaces/connectWorkspace',
|
||||
removeConnected: 'workspaces/removeConnected',
|
||||
selectTab: 'workspaces/selectTab',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTab: 'workspaces/removeTab',
|
||||
updateTabs: 'workspaces/updateTabs'
|
||||
}),
|
||||
addQueryTab () {
|
||||
this.newTab({ uid: this.connection.uid, type: 'query' });
|
||||
},
|
||||
|
@ -683,6 +714,13 @@ export default {
|
|||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -809,48 +847,5 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -50,7 +50,11 @@
|
|||
<label class="form-label cut-text">{{ $t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<select v-model="connection.client" class="form-select">
|
||||
<select
|
||||
id="connection-client"
|
||||
v-model="connection.client"
|
||||
class="form-select"
|
||||
>
|
||||
<option
|
||||
v-for="client in clients"
|
||||
:key="client.slug"
|
||||
|
@ -363,6 +367,7 @@
|
|||
</div>
|
||||
<div class="panel-footer">
|
||||
<button
|
||||
id="connection-test"
|
||||
class="btn btn-gray mr-2 d-flex"
|
||||
:class="{'loading': isTesting}"
|
||||
:disabled="isBusy"
|
||||
|
@ -372,6 +377,7 @@
|
|||
{{ $t('message.testConnection') }}
|
||||
</button>
|
||||
<button
|
||||
id="connection-save"
|
||||
class="btn btn-primary mr-2 d-flex"
|
||||
:disabled="isBusy"
|
||||
@click="saveConnection"
|
||||
|
@ -390,10 +396,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
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';
|
||||
|
||||
|
@ -403,6 +411,20 @@ export default {
|
|||
ModalAskCredentials,
|
||||
BaseUploadInput
|
||||
},
|
||||
setup () {
|
||||
const { addConnection } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { connectWorkspace, selectWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
addConnection,
|
||||
addNotification,
|
||||
connectWorkspace,
|
||||
selectWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
clients: [
|
||||
|
@ -466,12 +488,6 @@ export default {
|
|||
}, 20);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addConnection: 'connections/addConnection',
|
||||
connectWorkspace: 'workspaces/connectWorkspace',
|
||||
addNotification: 'notifications/addNotification',
|
||||
selectWorkspace: 'workspaces/selectWorkspace'
|
||||
}),
|
||||
setDefaults () {
|
||||
this.connection.user = this.customizations.defaultUser;
|
||||
this.connection.port = this.customizations.defaultPort;
|
||||
|
|
|
@ -355,6 +355,7 @@
|
|||
</div>
|
||||
<div class="panel-footer">
|
||||
<button
|
||||
id="connection-test"
|
||||
class="btn btn-gray mr-2 d-flex"
|
||||
:class="{'loading': isTesting}"
|
||||
:disabled="isBusy"
|
||||
|
@ -364,6 +365,7 @@
|
|||
{{ $t('message.testConnection') }}
|
||||
</button>
|
||||
<button
|
||||
id="connection-save"
|
||||
class="btn btn-primary mr-2 d-flex"
|
||||
:disabled="isBusy || !hasChanges"
|
||||
@click="saveConnection"
|
||||
|
@ -372,6 +374,7 @@
|
|||
{{ $t('word.save') }}
|
||||
</button>
|
||||
<button
|
||||
id="connection-connect"
|
||||
class="btn btn-success d-flex"
|
||||
:class="{'loading': isConnecting}"
|
||||
:disabled="isBusy"
|
||||
|
@ -391,8 +394,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
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';
|
||||
|
@ -406,6 +411,17 @@ export default {
|
|||
props: {
|
||||
connection: Object
|
||||
},
|
||||
setup () {
|
||||
const { editConnection } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const { connectWorkspace } = useWorkspacesStore();
|
||||
|
||||
return {
|
||||
editConnection,
|
||||
addNotification,
|
||||
connectWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
clients: [
|
||||
|
@ -441,11 +457,6 @@ export default {
|
|||
this.localConnection = JSON.parse(JSON.stringify(this.connection));
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
editConnection: 'connections/editConnection',
|
||||
connectWorkspace: 'workspaces/connectWorkspace',
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
async startConnection () {
|
||||
await this.saveConnection();
|
||||
this.isConnecting = true;
|
||||
|
|
|
@ -25,26 +25,35 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
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();
|
||||
|
||||
const { applicationTheme } = storeToRefs(settingsStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, changeBreadcrumbs } = workspacesStore;
|
||||
|
||||
return {
|
||||
applicationTheme,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
changeBreadcrumbs
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
applicationTheme: 'settings/getApplicationTheme',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
selectedWorkspace: 'workspaces/getSelected'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.changeBreadcrumbs({ schema: this.workspace.breadcrumbs.schema });
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
})
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -115,7 +115,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
import { useConnectionsStore } from '@/stores/connections';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import Views from '@/ipc-api/Views';
|
||||
|
@ -143,6 +148,45 @@ export default {
|
|||
connection: Object,
|
||||
isSelected: Boolean
|
||||
},
|
||||
setup () {
|
||||
const { getConnectionName } = useConnectionsStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { explorebarSize } = storeToRefs(settingsStore);
|
||||
|
||||
const { changeExplorebarSize } = settingsStore;
|
||||
const {
|
||||
getWorkspace,
|
||||
removeConnected: disconnectWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTabs,
|
||||
setSearchTerm,
|
||||
addLoadingElement,
|
||||
removeLoadingElement
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
getConnectionName,
|
||||
addNotification,
|
||||
explorebarSize,
|
||||
changeExplorebarSize,
|
||||
getWorkspace,
|
||||
disconnectWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
selectTab,
|
||||
newTab,
|
||||
removeTabs,
|
||||
setSearchTerm,
|
||||
addLoadingElement,
|
||||
removeLoadingElement
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isRefreshing: false,
|
||||
|
@ -174,11 +218,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
explorebarSize: 'settings/getExplorebarSize',
|
||||
getConnectionName: 'connections/getConnectionName'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
|
@ -222,19 +261,6 @@ export default {
|
|||
});
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
disconnectWorkspace: 'workspaces/removeConnected',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
selectTab: 'workspaces/selectTab',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTabs: 'workspaces/removeTabs',
|
||||
setSearchTerm: 'workspaces/setSearchTerm',
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeExplorebarSize: 'settings/changeExplorebarSize',
|
||||
addLoadingElement: 'workspaces/addLoadingElement',
|
||||
removeLoadingElement: 'workspaces/removeLoadingElement'
|
||||
}),
|
||||
async refresh () {
|
||||
if (!this.isRefreshing) {
|
||||
this.isRefreshing = true;
|
||||
|
|
|
@ -65,7 +65,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import ModalAskParameters from '@/components/ModalAskParameters';
|
||||
|
@ -73,6 +74,7 @@ import Triggers from '@/ipc-api/Triggers';
|
|||
import Routines from '@/ipc-api/Routines';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
import Schedulers from '@/ipc-api/Schedulers';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceExploreBarMiscContext',
|
||||
|
@ -86,6 +88,33 @@ export default {
|
|||
selectedMisc: Object,
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: ['close-context', 'reload'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
changeBreadcrumbs,
|
||||
addLoadingElement,
|
||||
removeLoadingElement,
|
||||
removeTabs,
|
||||
newTab
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
changeBreadcrumbs,
|
||||
addLoadingElement,
|
||||
removeLoadingElement,
|
||||
removeTabs,
|
||||
newTab
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isDeleteModal: false,
|
||||
|
@ -95,10 +124,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
|
@ -122,14 +147,6 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
addLoadingElement: 'workspaces/addLoadingElement',
|
||||
removeLoadingElement: 'workspaces/removeLoadingElement',
|
||||
removeTabs: 'workspaces/removeTabs',
|
||||
newTab: 'workspaces/newTab'
|
||||
}),
|
||||
showDeleteModal () {
|
||||
this.isDeleteModal = true;
|
||||
},
|
||||
|
|
|
@ -42,8 +42,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceExploreBarMiscContext',
|
||||
|
@ -55,25 +57,40 @@ export default {
|
|||
selectedMisc: String,
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: [
|
||||
'open-create-trigger-tab',
|
||||
'open-create-routine-tab',
|
||||
'open-create-function-tab',
|
||||
'open-create-trigger-function-tab',
|
||||
'open-create-scheduler-tab',
|
||||
'close-context'
|
||||
],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace, changeBreadcrumbs } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
changeBreadcrumbs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localElement: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
showDeleteModal () {
|
||||
this.isDeleteModal = true;
|
||||
},
|
||||
|
|
|
@ -243,8 +243,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { formatBytes } from 'common/libs/formatBytes';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceExploreBarSchema',
|
||||
|
@ -252,18 +254,45 @@ export default {
|
|||
database: Object,
|
||||
connection: Object
|
||||
},
|
||||
emits: [
|
||||
'show-schema-context',
|
||||
'show-table-context',
|
||||
'show-misc-context',
|
||||
'show-misc-folder-context'
|
||||
],
|
||||
setup () {
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { applicationTheme } = storeToRefs(settingsStore);
|
||||
|
||||
const {
|
||||
getLoadedSchemas,
|
||||
getWorkspace,
|
||||
getSearchTerm,
|
||||
changeBreadcrumbs,
|
||||
addLoadedSchema,
|
||||
newTab,
|
||||
refreshSchema
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
applicationTheme,
|
||||
getLoadedSchemas,
|
||||
getWorkspace,
|
||||
getSearchTerm,
|
||||
changeBreadcrumbs,
|
||||
addLoadedSchema,
|
||||
newTab,
|
||||
refreshSchema
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getLoadedSchemas: 'workspaces/getLoadedSchemas',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
getSearchTerm: 'workspaces/getSearchTerm',
|
||||
applicationTheme: 'settings/getApplicationTheme'
|
||||
}),
|
||||
searchTerm () {
|
||||
return this.getSearchTerm(this.connection.uid);
|
||||
},
|
||||
|
@ -331,12 +360,6 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
addLoadedSchema: 'workspaces/addLoadedSchema',
|
||||
newTab: 'workspaces/newTab',
|
||||
refreshSchema: 'workspaces/refreshSchema'
|
||||
}),
|
||||
formatBytes,
|
||||
async selectSchema (schema) {
|
||||
if (!this.loadedSchemas.has(schema) && !this.isLoading) {
|
||||
|
|
|
@ -124,7 +124,8 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import ModalEditSchema from '@/components/ModalEditSchema';
|
||||
|
@ -132,6 +133,7 @@ import ModalExportSchema from '@/components/ModalExportSchema';
|
|||
import ModalImportSchema from '@/components/ModalImportSchema';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import Application from '@/ipc-api/Application';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceExploreBarSchemaContext',
|
||||
|
@ -146,6 +148,35 @@ export default {
|
|||
contextEvent: MouseEvent,
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: [
|
||||
'open-create-table-tab',
|
||||
'open-create-view-tab',
|
||||
'open-create-trigger-tab',
|
||||
'open-create-routine-tab',
|
||||
'open-create-function-tab',
|
||||
'open-create-trigger-function-tab',
|
||||
'open-create-scheduler-tab',
|
||||
'close-context',
|
||||
'reload'
|
||||
],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
changeBreadcrumbs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
changeBreadcrumbs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isDeleteModal: false,
|
||||
|
@ -155,19 +186,11 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
openCreateTableTab () {
|
||||
this.$emit('open-create-table-tab');
|
||||
},
|
||||
|
|
|
@ -72,10 +72,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceExploreBarTableContext',
|
||||
|
@ -88,6 +90,33 @@ export default {
|
|||
selectedTable: Object,
|
||||
selectedSchema: String
|
||||
},
|
||||
emits: ['close-context', 'duplicate-table', 'reload', 'delete-table'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
newTab,
|
||||
removeTabs,
|
||||
addLoadingElement,
|
||||
removeLoadingElement,
|
||||
changeBreadcrumbs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
getWorkspace,
|
||||
newTab,
|
||||
removeTabs,
|
||||
addLoadingElement,
|
||||
removeLoadingElement,
|
||||
changeBreadcrumbs,
|
||||
selectedWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isDeleteModal: false,
|
||||
|
@ -95,10 +124,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
},
|
||||
|
@ -107,14 +132,6 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTabs: 'workspaces/removeTabs',
|
||||
addLoadingElement: 'workspaces/addLoadingElement',
|
||||
removeLoadingElement: 'workspaces/removeLoadingElement',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
showDeleteModal () {
|
||||
this.isDeleteModal = true;
|
||||
},
|
||||
|
|
|
@ -185,7 +185,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localFunction.sql"
|
||||
v-model="localFunction.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -203,11 +203,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import WorkspaceTabPropsFunctionParamsModal from '@/components/WorkspaceTabPropsFunctionParamsModal';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewFunction',
|
||||
|
@ -217,11 +219,40 @@ export default {
|
|||
WorkspaceTabPropsFunctionParamsModal
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
tab: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -235,19 +266,12 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalFunction) !== JSON.stringify(this.localFunction);
|
||||
},
|
||||
|
@ -302,22 +326,13 @@ export default {
|
|||
this.$refs.firstInput.focus();
|
||||
}, 100);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTab: 'workspaces/removeTab',
|
||||
renameTabs: 'workspaces/renameTabs'
|
||||
}),
|
||||
async saveChanges () {
|
||||
if (this.isSaving) return;
|
||||
this.isSaving = true;
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
v-show="isSelected"
|
||||
:key="`new-${_uid}`"
|
||||
ref="queryEditor"
|
||||
:value.sync="localRoutine.sql"
|
||||
v-model="localRoutine.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -163,11 +163,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import WorkspaceTabPropsRoutineParamsModal from '@/components/WorkspaceTabPropsRoutineParamsModal';
|
||||
import Routines from '@/ipc-api/Routines';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabNewRoutine',
|
||||
|
@ -177,11 +179,40 @@ export default {
|
|||
WorkspaceTabPropsRoutineParamsModal
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
tab: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -195,19 +226,12 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalRoutine) !== JSON.stringify(this.localRoutine);
|
||||
},
|
||||
|
@ -261,22 +285,13 @@ export default {
|
|||
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTab: 'workspaces/removeTab',
|
||||
renameTabs: 'workspaces/renameTabs'
|
||||
}),
|
||||
async saveChanges () {
|
||||
if (this.isSaving) return;
|
||||
this.isSaving = true;
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localScheduler.sql"
|
||||
v-model="localScheduler.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -142,7 +142,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import WorkspaceTabPropsSchedulerTimingModal from '@/components/WorkspaceTabPropsSchedulerTimingModal';
|
||||
|
@ -156,11 +158,40 @@ export default {
|
|||
WorkspaceTabPropsSchedulerTimingModal
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
tab: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -174,16 +205,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalScheduler) !== JSON.stringify(this.localScheduler);
|
||||
},
|
||||
|
@ -237,22 +261,13 @@ export default {
|
|||
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTab: 'workspaces/removeTab',
|
||||
renameTabs: 'workspaces/renameTabs'
|
||||
}),
|
||||
async saveChanges () {
|
||||
if (this.isSaving) return;
|
||||
this.isSaving = true;
|
||||
|
|
|
@ -165,7 +165,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
|
@ -184,11 +186,42 @@ export default {
|
|||
WorkspaceTabNewTableEmptyState
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
tab: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
getDatabaseVariable,
|
||||
refreshStructure,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
renameTabs,
|
||||
removeTab,
|
||||
changeBreadcrumbs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
getWorkspace,
|
||||
getDatabaseVariable,
|
||||
refreshStructure,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
renameTabs,
|
||||
removeTab,
|
||||
changeBreadcrumbs,
|
||||
selectedWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -209,17 +242,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getDatabaseVariable: 'workspaces/getDatabaseVariable'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
defaultCollation () {
|
||||
if (this.workspace.customizations.collations)
|
||||
return this.getDatabaseVariable(this.selectedWorkspace, 'collation_server').value || '';
|
||||
|
@ -276,19 +301,10 @@ export default {
|
|||
this.$refs.firstInput.focus();
|
||||
}, 100);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
newTab: 'workspaces/newTab',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
removeTab: 'workspaces/removeTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
async saveChanges () {
|
||||
if (this.isSaving || !this.isValid) return;
|
||||
this.isSaving = true;
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: 'WorkspaceTabNewTableEmptyState'
|
||||
name: 'WorkspaceTabNewTableEmptyState',
|
||||
emits: ['new-field']
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localTrigger.sql"
|
||||
v-model="localTrigger.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -132,8 +132,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import Triggers from '@/ipc-api/Triggers';
|
||||
|
||||
|
@ -144,11 +146,40 @@ export default {
|
|||
QueryEditor
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
tab: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -162,16 +193,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
|
@ -226,22 +250,13 @@ export default {
|
|||
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTab: 'workspaces/removeTab',
|
||||
renameTabs: 'workspaces/renameTabs'
|
||||
}),
|
||||
changeEvents (event) {
|
||||
if (this.customizations.triggerMultipleEvents) {
|
||||
this.localEvents[event] = !this.localEvents[event];
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localFunction.sql"
|
||||
v-model="localFunction.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -108,7 +108,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
|
@ -120,11 +122,40 @@ export default {
|
|||
QueryEditor
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
tab: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -139,19 +170,12 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalFunction) !== JSON.stringify(this.localFunction);
|
||||
},
|
||||
|
@ -202,22 +226,13 @@ export default {
|
|||
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTab: 'workspaces/removeTab',
|
||||
renameTabs: 'workspaces/renameTabs'
|
||||
}),
|
||||
async saveChanges () {
|
||||
if (this.isSaving) return;
|
||||
this.isSaving = true;
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localView.sql"
|
||||
v-model="localView.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -121,7 +121,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import Views from '@/ipc-api/Views';
|
||||
|
@ -133,11 +135,40 @@ export default {
|
|||
QueryEditor
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
tab: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
setUnsavedChanges,
|
||||
changeBreadcrumbs,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
setUnsavedChanges,
|
||||
changeBreadcrumbs,
|
||||
newTab,
|
||||
removeTab,
|
||||
renameTabs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -150,16 +181,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalView) !== JSON.stringify(this.localView);
|
||||
},
|
||||
|
@ -209,22 +233,13 @@ export default {
|
|||
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTab: 'workspaces/removeTab',
|
||||
renameTabs: 'workspaces/renameTabs'
|
||||
}),
|
||||
async saveChanges () {
|
||||
if (this.isSaving) return;
|
||||
this.isSaving = true;
|
||||
|
|
|
@ -197,7 +197,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localFunction.sql"
|
||||
v-model="localFunction.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -222,7 +222,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
|
@ -239,11 +241,38 @@ export default {
|
|||
ModalAskParameters
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
function: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -258,19 +287,12 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalFunction) !== JSON.stringify(this.localFunction);
|
||||
},
|
||||
|
@ -339,21 +361,13 @@ export default {
|
|||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getFunctionData () {
|
||||
if (!this.function) return;
|
||||
|
||||
|
|
|
@ -181,10 +181,14 @@ export default {
|
|||
ConfirmModal
|
||||
},
|
||||
props: {
|
||||
localParameters: Array,
|
||||
localParameters: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
func: String,
|
||||
workspace: Object
|
||||
},
|
||||
emits: ['hide', 'parameters-update'],
|
||||
data () {
|
||||
return {
|
||||
parametersProxy: [],
|
||||
|
@ -215,7 +219,7 @@ export default {
|
|||
this.getModalInnerHeight();
|
||||
window.addEventListener('resize', this.getModalInnerHeight);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.getModalInnerHeight);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -152,9 +152,8 @@
|
|||
<label class="form-label ml-2">{{ $t('message.routineBody') }}</label>
|
||||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
:key="`${routine}-${_uid}`"
|
||||
ref="queryEditor"
|
||||
:value.sync="localRoutine.sql"
|
||||
v-model="localRoutine.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -179,7 +178,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
|
@ -196,11 +197,38 @@ export default {
|
|||
ModalAskParameters
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
routine: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -215,19 +243,12 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalRoutine) !== JSON.stringify(this.localRoutine);
|
||||
},
|
||||
|
@ -284,21 +305,13 @@ export default {
|
|||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getRoutineData () {
|
||||
if (!this.routine) return;
|
||||
|
||||
|
|
|
@ -181,10 +181,14 @@ export default {
|
|||
ConfirmModal
|
||||
},
|
||||
props: {
|
||||
localParameters: Array,
|
||||
localParameters: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
routine: String,
|
||||
workspace: Object
|
||||
},
|
||||
emits: ['parameters-update', 'hide'],
|
||||
data () {
|
||||
return {
|
||||
parametersProxy: [],
|
||||
|
@ -215,7 +219,7 @@ export default {
|
|||
this.getModalInnerHeight();
|
||||
window.addEventListener('resize', this.getModalInnerHeight);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.getModalInnerHeight);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -124,7 +124,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localScheduler.sql"
|
||||
v-model="localScheduler.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -141,7 +141,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import WorkspaceTabPropsSchedulerTimingModal from '@/components/WorkspaceTabPropsSchedulerTimingModal';
|
||||
|
@ -155,11 +157,38 @@ export default {
|
|||
WorkspaceTabPropsSchedulerTimingModal
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
scheduler: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -173,16 +202,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalScheduler) !== JSON.stringify(this.localScheduler);
|
||||
},
|
||||
|
@ -236,21 +258,13 @@ export default {
|
|||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getSchedulerData () {
|
||||
if (!this.scheduler) return;
|
||||
|
||||
|
|
|
@ -138,22 +138,19 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import { VueMaskDirective } from 'v-mask';
|
||||
import moment from 'moment';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceTabPropsSchedulerTimingModal',
|
||||
components: {
|
||||
ConfirmModal
|
||||
},
|
||||
directives: {
|
||||
mask: VueMaskDirective
|
||||
},
|
||||
props: {
|
||||
localOptions: Object,
|
||||
workspace: Object
|
||||
},
|
||||
emits: ['hide', 'options-update'],
|
||||
data () {
|
||||
return {
|
||||
optionsProxy: {},
|
||||
|
|
|
@ -177,7 +177,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
|
@ -194,11 +196,38 @@ export default {
|
|||
WorkspaceTabPropsTableForeignModal
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
isSelected: Boolean,
|
||||
table: String,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
getDatabaseVariable,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
getDatabaseVariable,
|
||||
getWorkspace,
|
||||
selectedWorkspace,
|
||||
refreshStructure,
|
||||
setUnsavedChanges,
|
||||
renameTabs,
|
||||
changeBreadcrumbs
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -219,17 +248,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getDatabaseVariable: 'workspaces/getDatabaseVariable'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
defaultEngine () {
|
||||
const engine = this.getDatabaseVariable(this.connection.uid, 'default_storage_engine');
|
||||
return engine ? engine.value : '';
|
||||
|
@ -277,17 +298,10 @@ export default {
|
|||
this.getFieldsData();
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
async getTableOptions (params) {
|
||||
const db = this.workspace.structure.find(db => db.name === this.schema);
|
||||
|
||||
|
@ -415,7 +429,7 @@ export default {
|
|||
const localIDs = this.localFields.reduce((acc, curr) => [...acc, curr._antares_id], []);
|
||||
|
||||
// Fields Additions
|
||||
const additions = this.localFields.filter((field, i) => !originalIDs.includes(field._antares_id)).map(field => {
|
||||
const additions = this.localFields.filter(field => !originalIDs.includes(field._antares_id)).map(field => {
|
||||
const lI = this.localFields.findIndex(localField => localField._antares_id === field._antares_id);
|
||||
const after = lI > 0 ? this.localFields[lI - 1].name : false;
|
||||
return { ...field, after };
|
||||
|
|
|
@ -56,6 +56,7 @@ export default {
|
|||
indexTypes: Array,
|
||||
selectedField: Object
|
||||
},
|
||||
emits: ['close-context', 'duplicate-selected', 'delete-selected', 'add-new-index', 'add-to-index'],
|
||||
computed: {
|
||||
hasPrimary () {
|
||||
return this.indexes.some(index => index.type === 'PRIMARY');
|
||||
|
|
|
@ -105,26 +105,29 @@
|
|||
ref="resultTable"
|
||||
:list="fields"
|
||||
class="tbody"
|
||||
item-key="_antares_id"
|
||||
handle=".row-draggable"
|
||||
>
|
||||
<TableRow
|
||||
v-for="row in fields"
|
||||
:key="row._antares_id"
|
||||
:row="row"
|
||||
:indexes="getIndexes(row.name)"
|
||||
:foreigns="getForeigns(row.name)"
|
||||
:data-types="dataTypes"
|
||||
:customizations="customizations"
|
||||
@contextmenu="contextMenu"
|
||||
@rename-field="$emit('rename-field', $event)"
|
||||
/>
|
||||
<template #item="{element}">
|
||||
<TableRow
|
||||
:row="element"
|
||||
:indexes="getIndexes(element.name)"
|
||||
:foreigns="getForeigns(element.name)"
|
||||
:data-types="dataTypes"
|
||||
:customizations="customizations"
|
||||
@contextmenu="contextMenu"
|
||||
@rename-field="$emit('rename-field', $event)"
|
||||
/>
|
||||
</template>
|
||||
</Draggable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Draggable from 'vuedraggable';
|
||||
import TableRow from '@/components/WorkspaceTabPropsTableRow';
|
||||
import TableContext from '@/components/WorkspaceTabPropsTableContext';
|
||||
|
@ -147,6 +150,21 @@ export default {
|
|||
schema: String,
|
||||
mode: String
|
||||
},
|
||||
emits: ['add-new-index', 'add-to-index', 'rename-field', 'duplicate-field', 'remove-field'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
resultsSize: 1000,
|
||||
|
@ -157,10 +175,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getWorkspaceTab: 'workspaces/getWorkspaceTab',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspaceSchema () {
|
||||
return this.getWorkspace(this.connUid).breadcrumbs.schema;
|
||||
},
|
||||
|
@ -195,13 +209,10 @@ export default {
|
|||
mounted () {
|
||||
window.addEventListener('resize', this.resizeResults);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeResults);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
resizeResults () {
|
||||
if (this.$refs.resultTable) {
|
||||
const el = this.$refs.tableWrapper;
|
||||
|
|
|
@ -202,7 +202,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
|
@ -221,6 +221,12 @@ export default {
|
|||
fields: Array,
|
||||
workspace: Object
|
||||
},
|
||||
emits: ['foreigns-update', 'hide'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
|
||||
return { addNotification };
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
foreignProxy: [],
|
||||
|
@ -259,13 +265,10 @@ export default {
|
|||
this.getModalInnerHeight();
|
||||
window.addEventListener('resize', this.getModalInnerHeight);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.getModalInnerHeight);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
confirmForeignsChange () {
|
||||
this.foreignProxy = this.foreignProxy.filter(foreign =>
|
||||
foreign.field &&
|
||||
|
|
|
@ -153,6 +153,7 @@ export default {
|
|||
workspace: Object,
|
||||
indexTypes: Array
|
||||
},
|
||||
emits: ['hide', 'indexes-update'],
|
||||
data () {
|
||||
return {
|
||||
indexesProxy: [],
|
||||
|
@ -181,7 +182,7 @@ export default {
|
|||
this.getModalInnerHeight();
|
||||
window.addEventListener('resize', this.getModalInnerHeight);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.getModalInnerHeight);
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -343,7 +343,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
|
||||
export default {
|
||||
|
@ -358,6 +360,21 @@ export default {
|
|||
foreigns: Array,
|
||||
customizations: Object
|
||||
},
|
||||
emits: ['contextmenu', 'rename-field'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { getWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localRow: {},
|
||||
|
@ -375,10 +392,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
localLength () {
|
||||
const localLength = this.localRow.numLength || this.localRow.charLength || this.localRow.datePrecision || this.localRow.numPrecision || 0;
|
||||
return localLength === true ? null : localLength;
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localTrigger.sql"
|
||||
v-model="localTrigger.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -131,8 +131,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import Triggers from '@/ipc-api/Triggers';
|
||||
|
||||
|
@ -143,11 +145,38 @@ export default {
|
|||
QueryEditor
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
trigger: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -161,16 +190,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
|
@ -227,21 +249,13 @@ export default {
|
|||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getTriggerData () {
|
||||
if (!this.trigger) return;
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localFunction.sql"
|
||||
v-model="localFunction.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -102,7 +102,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
|
@ -117,11 +119,38 @@ export default {
|
|||
ModalAskParameters
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
function: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
newTab,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -136,19 +165,12 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalFunction) !== JSON.stringify(this.localFunction);
|
||||
},
|
||||
|
@ -204,21 +226,13 @@ export default {
|
|||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getFunctionData () {
|
||||
if (!this.function) return;
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localView.sql"
|
||||
v-model="localView.sql"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:height="editorHeight"
|
||||
|
@ -120,7 +120,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import Views from '@/ipc-api/Views';
|
||||
|
@ -132,11 +134,36 @@ export default {
|
|||
QueryEditor
|
||||
},
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String,
|
||||
view: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
refreshStructure,
|
||||
renameTabs,
|
||||
changeBreadcrumbs,
|
||||
setUnsavedChanges
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -149,16 +176,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalView) !== JSON.stringify(this.localView);
|
||||
},
|
||||
|
@ -205,20 +225,13 @@ export default {
|
|||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
renameTabs: 'workspaces/renameTabs'
|
||||
}),
|
||||
async getViewData () {
|
||||
if (!this.view) return;
|
||||
this.isLoading = true;
|
||||
|
|
|
@ -3,18 +3,18 @@
|
|||
v-show="isSelected"
|
||||
class="workspace-query-tab column col-12 columns col-gapless no-outline p-0"
|
||||
tabindex="0"
|
||||
@keydown.116="runQuery(query)"
|
||||
@keydown.75="killTabQuery"
|
||||
@keydown.ctrl.alt.87="clear"
|
||||
@keydown.ctrl.66="beautify"
|
||||
@keydown.ctrl.71="openHistoryModal"
|
||||
@keydown.f5="runQuery(query)"
|
||||
@keydown.k="killTabQuery"
|
||||
@keydown.ctrl.alt.w="clear"
|
||||
@keydown.ctrl.b="beautify"
|
||||
@keydown.ctrl.g="openHistoryModal"
|
||||
>
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<QueryEditor
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
v-model="query"
|
||||
:auto-focus="true"
|
||||
:value.sync="query"
|
||||
:workspace="workspace"
|
||||
:schema="breadcrumbsSchema"
|
||||
:is-selected="isSelected"
|
||||
|
@ -187,8 +187,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { format } from 'sql-formatter';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import { useHistoryStore } from '@/stores/history';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import QueryEditor from '@/components/QueryEditor';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
|
@ -208,10 +211,36 @@ export default {
|
|||
},
|
||||
mixins: [tableTabs],
|
||||
props: {
|
||||
tabUid: String,
|
||||
connection: Object,
|
||||
tab: Object,
|
||||
isSelected: Boolean
|
||||
},
|
||||
setup () {
|
||||
const { getHistoryByWorkspace, saveHistory } = useHistoryStore();
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const {
|
||||
getWorkspace,
|
||||
changeBreadcrumbs,
|
||||
updateTabContent,
|
||||
setUnsavedChanges
|
||||
} = workspacesStore;
|
||||
|
||||
return {
|
||||
getHistoryByWorkspace,
|
||||
saveHistory,
|
||||
addNotification,
|
||||
selectedWorkspace,
|
||||
getWorkspace,
|
||||
changeBreadcrumbs,
|
||||
updateTabContent,
|
||||
setUnsavedChanges
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
query: '',
|
||||
|
@ -230,17 +259,9 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getHistoryByWorkspace: 'history/getHistoryByWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
breadcrumbsSchema () {
|
||||
return this.workspace.breadcrumbs.schema || null;
|
||||
},
|
||||
|
@ -296,7 +317,7 @@ export default {
|
|||
if (this.tab.autorun)
|
||||
this.runQuery(this.query);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
|
@ -305,13 +326,6 @@ export default {
|
|||
Schema.destroyConnectionToCommit(params);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
updateTabContent: 'workspaces/updateTabContent',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
saveHistory: 'history/saveHistory'
|
||||
}),
|
||||
async runQuery (query) {
|
||||
if (!query || this.isQuering) return;
|
||||
this.isQuering = true;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
class="vscroll no-outline"
|
||||
tabindex="0"
|
||||
:style="{'height': resultsSize+'px'}"
|
||||
@keyup.46="showDeleteConfirmModal"
|
||||
@keydown.ctrl.65="selectAllRows($event)"
|
||||
@keyup.delete="showDeleteConfirmModal"
|
||||
@keydown.ctrl.a="selectAllRows($event)"
|
||||
@keydown.esc="deselectRows"
|
||||
>
|
||||
<TableContext
|
||||
|
@ -68,7 +68,7 @@
|
|||
:visible-height="resultsSize"
|
||||
:scroll-element="scrollElement"
|
||||
>
|
||||
<template slot-scope="{ items }">
|
||||
<template #default="{ items }">
|
||||
<WorkspaceTabQueryTableRow
|
||||
v-for="row in items"
|
||||
:key="row._antares_id"
|
||||
|
@ -107,14 +107,17 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import arrayToFile from '../libs/arrayToFile';
|
||||
import { TEXT, LONG_TEXT, BLOB } from 'common/fieldTypes';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
|
||||
import WorkspaceTabQueryTableRow from '@/components/WorkspaceTabQueryTableRow';
|
||||
import TableContext from '@/components/WorkspaceTabQueryTableContext';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import moment from 'moment';
|
||||
|
||||
export default {
|
||||
|
@ -132,6 +135,20 @@ export default {
|
|||
isSelected: Boolean,
|
||||
elementType: { type: String, default: 'table' }
|
||||
},
|
||||
emits: ['update-field', 'delete-selected', 'hard-sort'],
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const { getWorkspace } = useWorkspacesStore();
|
||||
|
||||
const { dataTabLimit: pageSize } = storeToRefs(settingsStore);
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
pageSize,
|
||||
getWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
resultsSize: 0,
|
||||
|
@ -149,10 +166,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
pageSize: 'settings/getDataTabLimit'
|
||||
}),
|
||||
workspaceSchema () {
|
||||
return this.getWorkspace(this.connUid).breadcrumbs.schema;
|
||||
},
|
||||
|
@ -256,13 +269,10 @@ export default {
|
|||
mounted () {
|
||||
window.addEventListener('resize', this.resizeResults);
|
||||
},
|
||||
destroyed () {
|
||||
unmounted () {
|
||||
window.removeEventListener('resize', this.resizeResults);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
fieldType (cKey) {
|
||||
let type = 'unknown';
|
||||
const field = this.fields.filter(field => field.name === cKey)[0];
|
||||
|
|
|
@ -61,6 +61,7 @@ export default {
|
|||
selectedRows: Array,
|
||||
selectedCell: Object
|
||||
},
|
||||
emits: ['show-delete-modal', 'close-context', 'set-null', 'copy-cell', 'copy-row'],
|
||||
methods: {
|
||||
showConfirmModal () {
|
||||
this.$emit('show-delete-modal');
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
class="cell-content"
|
||||
:class="`${isNull(col)} ${typeClass(fields[cKey].type)}`"
|
||||
@dblclick="editON($event, col, cKey)"
|
||||
>{{ col | typeFormat(fields[cKey].type.toLowerCase(), fields[cKey].length) | cutText }}</span>
|
||||
>{{ cutText(typeFormat(col, fields[cKey].type.toLowerCase(), fields[cKey].length)) }}</span>
|
||||
<ForeignKeySelect
|
||||
v-else-if="isForeignKey(cKey)"
|
||||
v-model="editingContent"
|
||||
class="editable-field"
|
||||
:value.sync="editingContent"
|
||||
:key-usage="getKeyUsage(cKey)"
|
||||
size="small"
|
||||
@blur="editOFF"
|
||||
|
@ -85,7 +85,7 @@
|
|||
<div class="mb-2">
|
||||
<div>
|
||||
<TextEditor
|
||||
:value.sync="editingContent"
|
||||
v-model="editingContent"
|
||||
editor-class="textarea-editor"
|
||||
:mode="editorMode"
|
||||
/>
|
||||
|
@ -152,7 +152,7 @@
|
|||
</template>
|
||||
<template #body>
|
||||
<div class="mb-2">
|
||||
<transition name="jump-down">
|
||||
<Transition name="jump-down">
|
||||
<div v-if="contentInfo.size">
|
||||
<img
|
||||
v-if="isImage"
|
||||
|
@ -173,10 +173,10 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</Transition>
|
||||
<div class="editor-field-info">
|
||||
<div>
|
||||
<b>{{ $t('word.size') }}</b>: {{ editingContent.length | formatBytes }}<br>
|
||||
<b>{{ $t('word.size') }}</b>: {{ formatBytes(editingContent.length) }}<br>
|
||||
<b>{{ $t('word.mimeType') }}</b>: {{ contentInfo.mime }}
|
||||
</div>
|
||||
<div><b>{{ $t('word.type') }}</b>: {{ editingType.toUpperCase() }}</div>
|
||||
|
@ -219,7 +219,6 @@ import {
|
|||
SPATIAL,
|
||||
IS_MULTI_SPATIAL
|
||||
} from 'common/fieldTypes';
|
||||
import { VueMaskDirective } from 'v-mask';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import TextEditor from '@/components/BaseTextEditor';
|
||||
import BaseMap from '@/components/BaseMap';
|
||||
|
@ -233,61 +232,6 @@ export default {
|
|||
ForeignKeySelect,
|
||||
BaseMap
|
||||
},
|
||||
directives: {
|
||||
mask: VueMaskDirective
|
||||
},
|
||||
filters: {
|
||||
formatBytes,
|
||||
cutText (val) {
|
||||
if (typeof val !== 'string') return val;
|
||||
return val.length > 128 ? `${val.substring(0, 128)}[...]` : val;
|
||||
},
|
||||
typeFormat (val, type, precision) {
|
||||
if (!val) return val;
|
||||
|
||||
type = type.toUpperCase();
|
||||
|
||||
if (DATE.includes(type))
|
||||
return moment(val).isValid() ? moment(val).format('YYYY-MM-DD') : val;
|
||||
|
||||
if (DATETIME.includes(type)) {
|
||||
if (typeof val === 'string')
|
||||
return val;
|
||||
|
||||
let datePrecision = '';
|
||||
for (let i = 0; i < precision; i++)
|
||||
datePrecision += i === 0 ? '.S' : 'S';
|
||||
|
||||
return moment(val).isValid() ? moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`) : val;
|
||||
}
|
||||
|
||||
if (BLOB.includes(type)) {
|
||||
const buff = Buffer.from(val);
|
||||
if (!buff.length) return '';
|
||||
|
||||
const hex = buff.toString('hex').substring(0, 8).toUpperCase();
|
||||
return `${mimeFromHex(hex).mime} (${formatBytes(buff.length)})`;
|
||||
}
|
||||
|
||||
if (BIT.includes(type)) {
|
||||
if (typeof val === 'number') val = [val];
|
||||
const hex = Buffer.from(val).toString('hex');
|
||||
const bitString = hexToBinary(hex);
|
||||
return parseInt(bitString).toString().padStart(precision, '0');
|
||||
}
|
||||
|
||||
if (ARRAY.includes(type)) {
|
||||
if (Array.isArray(val))
|
||||
return JSON.stringify(val).replaceAll('[', '{').replaceAll(']', '}');
|
||||
return val;
|
||||
}
|
||||
|
||||
if (SPATIAL.includes(type))
|
||||
return val;
|
||||
|
||||
return typeof val === 'object' ? JSON.stringify(val) : val;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
row: Object,
|
||||
fields: Object,
|
||||
|
@ -295,6 +239,7 @@ export default {
|
|||
itemHeight: Number,
|
||||
elementType: { type: String, default: 'table' }
|
||||
},
|
||||
emits: ['update-field', 'select-row', 'contextmenu'],
|
||||
data () {
|
||||
return {
|
||||
isInlineEditor: {},
|
||||
|
@ -449,15 +394,15 @@ export default {
|
|||
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
|
||||
const type = this.fields[field].type.toUpperCase(); ;
|
||||
this.originalContent = this.$options.filters.typeFormat(content, type, this.fields[field].length);
|
||||
const type = this.fields[field].type.toUpperCase();
|
||||
this.originalContent = this.typeFormat(content, type, this.fields[field].length);
|
||||
this.editingType = type;
|
||||
this.editingField = field;
|
||||
this.editingLength = this.fields[field].length;
|
||||
|
||||
if ([...LONG_TEXT, ...ARRAY, ...TEXT_SEARCH].includes(type)) {
|
||||
this.isTextareaEditor = true;
|
||||
this.editingContent = this.$options.filters.typeFormat(content, type);
|
||||
this.editingContent = this.typeFormat(content, type);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -465,7 +410,7 @@ export default {
|
|||
if (content) {
|
||||
this.isMultiSpatial = IS_MULTI_SPATIAL.includes(type);
|
||||
this.isMapModal = true;
|
||||
this.editingContent = this.$options.filters.typeFormat(content, type);
|
||||
this.editingContent = this.typeFormat(content, type);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -513,7 +458,7 @@ export default {
|
|||
this.editingContent = this.editingContent.slice(0, -1);
|
||||
}
|
||||
|
||||
if (this.editingContent === this.$options.filters.typeFormat(this.originalContent, this.editingType, this.editingLength)) return;// If not changed
|
||||
if (this.editingContent === this.typeFormat(this.originalContent, this.editingType, this.editingLength)) return;// If not changed
|
||||
|
||||
content = this.editingContent;
|
||||
}
|
||||
|
@ -590,6 +535,56 @@ export default {
|
|||
this.editingField = null;
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
}
|
||||
},
|
||||
formatBytes,
|
||||
cutText (val) {
|
||||
if (typeof val !== 'string') return val;
|
||||
return val.length > 128 ? `${val.substring(0, 128)}[...]` : val;
|
||||
},
|
||||
typeFormat (val, type, precision) {
|
||||
if (!val) return val;
|
||||
|
||||
type = type.toUpperCase();
|
||||
|
||||
if (DATE.includes(type))
|
||||
return moment(val).isValid() ? moment(val).format('YYYY-MM-DD') : val;
|
||||
|
||||
if (DATETIME.includes(type)) {
|
||||
if (typeof val === 'string')
|
||||
return val;
|
||||
|
||||
let datePrecision = '';
|
||||
for (let i = 0; i < precision; i++)
|
||||
datePrecision += i === 0 ? '.S' : 'S';
|
||||
|
||||
return moment(val).isValid() ? moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`) : val;
|
||||
}
|
||||
|
||||
if (BLOB.includes(type)) {
|
||||
const buff = Buffer.from(val);
|
||||
if (!buff.length) return '';
|
||||
|
||||
const hex = buff.toString('hex').substring(0, 8).toUpperCase();
|
||||
return `${mimeFromHex(hex).mime} (${formatBytes(buff.length)})`;
|
||||
}
|
||||
|
||||
if (BIT.includes(type)) {
|
||||
if (typeof val === 'number') val = [val];
|
||||
const hex = Buffer.from(val).toString('hex');
|
||||
const bitString = hexToBinary(hex);
|
||||
return parseInt(bitString).toString().padStart(precision, '0');
|
||||
}
|
||||
|
||||
if (ARRAY.includes(type)) {
|
||||
if (Array.isArray(val))
|
||||
return JSON.stringify(val).replaceAll('[', '{').replaceAll(']', '}');
|
||||
return val;
|
||||
}
|
||||
|
||||
if (SPATIAL.includes(type))
|
||||
return val;
|
||||
|
||||
return typeof val === 'object' ? JSON.stringify(val) : val;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -117,14 +117,14 @@
|
|||
<i class="mdi mdi-timer-sand mdi-rotate-180 pr-1" /> <b>{{ results[0].duration / 1000 }}s</b>
|
||||
</div>
|
||||
<div v-if="results.length && results[0].rows">
|
||||
{{ $t('word.results') }}: <b>{{ results[0].rows.length | localeString }}</b>
|
||||
{{ $t('word.results') }}: <b>{{ localeString(results[0].rows.length) }}</b>
|
||||
</div>
|
||||
<div v-if="hasApproximately || (page > 1 && approximateCount)">
|
||||
{{ $t('word.total') }}: <b
|
||||
:title="!customizations.tableRealCount ? $t('word.approximately') : ''"
|
||||
>
|
||||
<span v-if="!customizations.tableRealCount">≈</span>
|
||||
{{ approximateCount | localeString }}
|
||||
{{ localeString(approximateCount) }}
|
||||
</b>
|
||||
</div>
|
||||
<div class="d-flex" :title="$t('word.schema')">
|
||||
|
@ -176,13 +176,16 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||
import BaseLoader from '@/components/BaseLoader';
|
||||
import WorkspaceTabQueryTable from '@/components/WorkspaceTabQueryTable';
|
||||
import WorkspaceTabTableFilters from '@/components/WorkspaceTabTableFilters';
|
||||
import ModalNewTableRow from '@/components/ModalNewTableRow';
|
||||
import ModalFakerRows from '@/components/ModalFakerRows';
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import tableTabs from '@/mixins/tableTabs';
|
||||
|
||||
export default {
|
||||
|
@ -194,12 +197,6 @@ export default {
|
|||
ModalNewTableRow,
|
||||
ModalFakerRows
|
||||
},
|
||||
filters: {
|
||||
localeString (val) {
|
||||
if (val !== null)
|
||||
return val.toLocaleString();
|
||||
}
|
||||
},
|
||||
mixins: [tableTabs],
|
||||
props: {
|
||||
connection: Object,
|
||||
|
@ -208,6 +205,24 @@ export default {
|
|||
schema: String,
|
||||
elementType: String
|
||||
},
|
||||
setup () {
|
||||
const { addNotification } = useNotificationsStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const workspacesStore = useWorkspacesStore();
|
||||
|
||||
const { dataTabLimit: limit } = storeToRefs(settingsStore);
|
||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||
|
||||
const { changeBreadcrumbs, getWorkspace } = workspacesStore;
|
||||
|
||||
return {
|
||||
addNotification,
|
||||
limit,
|
||||
selectedWorkspace,
|
||||
changeBreadcrumbs,
|
||||
getWorkspace
|
||||
};
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'data', // ???
|
||||
|
@ -228,11 +243,6 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
limit: 'settings/getDataTabLimit'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
|
@ -310,15 +320,11 @@ export default {
|
|||
this.getTableData();
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
beforeUnmount () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
clearInterval(this.refreshInterval);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
async getTableData () {
|
||||
if (!this.table || !this.isSelected) return;
|
||||
this.isQuering = true;
|
||||
|
@ -335,8 +341,8 @@ export default {
|
|||
table: this.table,
|
||||
limit: this.limit,
|
||||
page: this.page,
|
||||
sortParams: this.sortParams,
|
||||
where: this.filters || []
|
||||
sortParams: { ...this.sortParams },
|
||||
where: [...this.filters] || []
|
||||
};
|
||||
|
||||
try { // Table data
|
||||
|
@ -458,6 +464,10 @@ export default {
|
|||
updateFilters (clausoles) {
|
||||
this.filters = clausoles;
|
||||
this.getTableData();
|
||||
},
|
||||
localeString (val) {
|
||||
if (val !== null)
|
||||
return val.toLocaleString();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -79,6 +79,7 @@ export default {
|
|||
fields: Array,
|
||||
connClient: String
|
||||
},
|
||||
emits: ['filter-change', 'filter'],
|
||||
data () {
|
||||
return {
|
||||
rows: [],
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
// TODO: unfinished
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default function useResultTables (uid, reloadTable, addNotification) {
|
||||
const tableRef = ref(null);
|
||||
const isQuering = ref(false);
|
||||
|
||||
async function updateField (payload) {
|
||||
isQuering.value = true;
|
||||
|
||||
const params = {
|
||||
uid: uid,
|
||||
...payload
|
||||
};
|
||||
|
||||
try {
|
||||
const { status, response } = await Tables.updateTableCell(params);
|
||||
if (status === 'success') {
|
||||
if (response.reload)// Needed for blob fields
|
||||
reloadTable();
|
||||
else
|
||||
tableRef.applyUpdate(payload);
|
||||
}
|
||||
else
|
||||
addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
isQuering.value = false;
|
||||
}
|
||||
|
||||
async function deleteSelected (payload) {
|
||||
isQuering.value = true;
|
||||
|
||||
const params = {
|
||||
uid: uid,
|
||||
...payload
|
||||
};
|
||||
|
||||
try {
|
||||
const { status, response } = await Tables.deleteTableRows(params);
|
||||
isQuering.value = false;
|
||||
|
||||
if (status === 'success')
|
||||
reloadTable();
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
isQuering.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tableRef,
|
||||
isQuering,
|
||||
updateField,
|
||||
deleteSelected
|
||||
};
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
import VueI18n from 'vue-i18n';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
Vue.use(VueI18n);
|
||||
|
||||
const i18n = new VueI18n({
|
||||
const i18n = createI18n({
|
||||
fallbackLocale: 'en-US',
|
||||
messages: {
|
||||
'en-US': require('./en-US'),
|
||||
'it-IT': require('./it-IT'),
|
||||
|
|
|
@ -1,20 +1,28 @@
|
|||
'use strict';
|
||||
|
||||
import Vue from 'vue';
|
||||
|
||||
import { createApp } from 'vue';
|
||||
import '@mdi/font/css/materialdesignicons.css';
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import '@/scss/main.scss';
|
||||
import { VueMaskDirective } from 'v-mask';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
|
||||
import App from '@/App.vue';
|
||||
import store from '@/store';
|
||||
import { pinia } from '@/stores';
|
||||
import i18n from '@/i18n';
|
||||
|
||||
i18n.locale = store.state.settings.locale;
|
||||
Vue.config.productionTip = false;
|
||||
// https://github.com/probil/v-mask/issues/498#issuecomment-827027834
|
||||
const vMaskV2 = VueMaskDirective;
|
||||
const vMaskV3 = {
|
||||
beforeMount: vMaskV2.bind,
|
||||
updated: vMaskV2.componentUpdated,
|
||||
unmounted: vMaskV2.unbind
|
||||
};
|
||||
|
||||
new Vue({
|
||||
render: h => h(App),
|
||||
store,
|
||||
i18n
|
||||
}).$mount('#app');
|
||||
createApp(App)
|
||||
.directive('mask', vMaskV3)
|
||||
.use(pinia)
|
||||
.use(i18n)
|
||||
.mount('#app');
|
||||
|
||||
const { locale } = useSettingsStore();
|
||||
i18n.global.locale = locale;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static getKey (params) {
|
||||
return ipcRenderer.sendSync('get-key', params);
|
||||
return ipcRenderer.sendSync('get-key', unproxify(params));
|
||||
}
|
||||
|
||||
static showOpenDialog (options) {
|
||||
return ipcRenderer.invoke('showOpenDialog', options);
|
||||
return ipcRenderer.invoke('show-open-dialog', unproxify(options));
|
||||
}
|
||||
|
||||
static getDownloadPathDirectory () {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
import connStringConstruct from '../libs/connStringDecode';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static makeTest (params) {
|
||||
params = connStringConstruct(params);
|
||||
return ipcRenderer.invoke('test-connection', params);
|
||||
return ipcRenderer.invoke('test-connection', unproxify(params));
|
||||
}
|
||||
|
||||
static connect (params) {
|
||||
params = connStringConstruct(params);
|
||||
return ipcRenderer.invoke('connect', params);
|
||||
return ipcRenderer.invoke('connect', unproxify(params));
|
||||
}
|
||||
|
||||
static checkConnection (uid) {
|
||||
|
|
|
@ -1,28 +1,29 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static getFunctionInformations (params) {
|
||||
return ipcRenderer.invoke('get-function-informations', params);
|
||||
return ipcRenderer.invoke('get-function-informations', unproxify(params));
|
||||
}
|
||||
|
||||
static dropFunction (params) {
|
||||
return ipcRenderer.invoke('drop-function', params);
|
||||
return ipcRenderer.invoke('drop-function', unproxify(params));
|
||||
}
|
||||
|
||||
static alterFunction (params) {
|
||||
return ipcRenderer.invoke('alter-function', params);
|
||||
return ipcRenderer.invoke('alter-function', unproxify(params));
|
||||
}
|
||||
|
||||
static alterTriggerFunction (params) {
|
||||
return ipcRenderer.invoke('alter-trigger-function', params);
|
||||
return ipcRenderer.invoke('alter-trigger-function', unproxify(params));
|
||||
}
|
||||
|
||||
static createFunction (params) {
|
||||
return ipcRenderer.invoke('create-function', params);
|
||||
return ipcRenderer.invoke('create-function', unproxify(params));
|
||||
}
|
||||
|
||||
static createTriggerFunction (params) {
|
||||
return ipcRenderer.invoke('create-trigger-function', params);
|
||||
return ipcRenderer.invoke('create-trigger-function', unproxify(params));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static getRoutineInformations (params) {
|
||||
return ipcRenderer.invoke('get-routine-informations', params);
|
||||
return ipcRenderer.invoke('get-routine-informations', unproxify(params));
|
||||
}
|
||||
|
||||
static dropRoutine (params) {
|
||||
return ipcRenderer.invoke('drop-routine', params);
|
||||
return ipcRenderer.invoke('drop-routine', unproxify(params));
|
||||
}
|
||||
|
||||
static alterRoutine (params) {
|
||||
return ipcRenderer.invoke('alter-routine', params);
|
||||
return ipcRenderer.invoke('alter-routine', unproxify(params));
|
||||
}
|
||||
|
||||
static createRoutine (params) {
|
||||
return ipcRenderer.invoke('create-routine', params);
|
||||
return ipcRenderer.invoke('create-routine', unproxify(params));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
export default class {
|
||||
static getSchedulerInformations (params) {
|
||||
return ipcRenderer.invoke('get-scheduler-informations', params);
|
||||
return ipcRenderer.invoke('get-scheduler-informations', unproxify(params));
|
||||
}
|
||||
|
||||
static dropScheduler (params) {
|
||||
return ipcRenderer.invoke('drop-scheduler', params);
|
||||
return ipcRenderer.invoke('drop-scheduler', unproxify(params));
|
||||
}
|
||||
|
||||
static alterScheduler (params) {
|
||||
return ipcRenderer.invoke('alter-scheduler', params);
|
||||
return ipcRenderer.invoke('alter-scheduler', unproxify(params));
|
||||
}
|
||||
|
||||
static createScheduler (params) {
|
||||
return ipcRenderer.invoke('create-scheduler', params);
|
||||
return ipcRenderer.invoke('create-scheduler', unproxify(params));
|
||||
}
|
||||
|
||||
static toggleScheduler (params) {
|
||||
return ipcRenderer.invoke('toggle-scheduler', params);
|
||||
return ipcRenderer.invoke('toggle-scheduler', unproxify(params));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static createSchema (params) {
|
||||
return ipcRenderer.invoke('create-schema', params);
|
||||
return ipcRenderer.invoke('create-schema', unproxify(params));
|
||||
}
|
||||
|
||||
static updateSchema (params) {
|
||||
return ipcRenderer.invoke('update-schema', params);
|
||||
return ipcRenderer.invoke('update-schema', unproxify(params));
|
||||
}
|
||||
|
||||
static getDatabaseCollation (params) {
|
||||
return ipcRenderer.invoke('get-schema-collation', params);
|
||||
return ipcRenderer.invoke('get-schema-collation', unproxify(params));
|
||||
}
|
||||
|
||||
static deleteSchema (params) {
|
||||
return ipcRenderer.invoke('delete-schema', params);
|
||||
return ipcRenderer.invoke('delete-schema', unproxify(params));
|
||||
}
|
||||
|
||||
static getStructure (params) {
|
||||
return ipcRenderer.invoke('get-structure', params);
|
||||
return ipcRenderer.invoke('get-structure', unproxify(params, false));
|
||||
}
|
||||
|
||||
static getCollations (uid) {
|
||||
|
@ -43,35 +44,35 @@ export default class {
|
|||
}
|
||||
|
||||
static killProcess (params) {
|
||||
return ipcRenderer.invoke('kill-process', params);
|
||||
return ipcRenderer.invoke('kill-process', unproxify(params));
|
||||
}
|
||||
|
||||
static killTabQuery (params) {
|
||||
return ipcRenderer.invoke('kill-tab-query', params);
|
||||
return ipcRenderer.invoke('kill-tab-query', unproxify(params));
|
||||
}
|
||||
|
||||
static commitTab (params) {
|
||||
return ipcRenderer.invoke('commit-tab', params);
|
||||
return ipcRenderer.invoke('commit-tab', unproxify(params));
|
||||
}
|
||||
|
||||
static rollbackTab (params) {
|
||||
return ipcRenderer.invoke('rollback-tab', params);
|
||||
return ipcRenderer.invoke('rollback-tab', unproxify(params));
|
||||
}
|
||||
|
||||
static destroyConnectionToCommit (params) {
|
||||
return ipcRenderer.invoke('destroy-connection-to-commit', params);
|
||||
return ipcRenderer.invoke('destroy-connection-to-commit', unproxify(params));
|
||||
}
|
||||
|
||||
static useSchema (params) {
|
||||
return ipcRenderer.invoke('use-schema', params);
|
||||
return ipcRenderer.invoke('use-schema', unproxify(params));
|
||||
}
|
||||
|
||||
static rawQuery (params) {
|
||||
return ipcRenderer.invoke('raw-query', params);
|
||||
return ipcRenderer.invoke('raw-query', unproxify(params));
|
||||
}
|
||||
|
||||
static export (params) {
|
||||
return ipcRenderer.invoke('export', params);
|
||||
return ipcRenderer.invoke('export', unproxify(params));
|
||||
}
|
||||
|
||||
static abortExport () {
|
||||
|
@ -79,7 +80,7 @@ export default class {
|
|||
}
|
||||
|
||||
static import (params) {
|
||||
return ipcRenderer.invoke('import-sql', params);
|
||||
return ipcRenderer.invoke('import-sql', unproxify(params));
|
||||
}
|
||||
|
||||
static abortImport () {
|
||||
|
|
|
@ -1,68 +1,69 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static getTableColumns (params) {
|
||||
return ipcRenderer.invoke('get-table-columns', params);
|
||||
return ipcRenderer.invoke('get-table-columns', unproxify(params));
|
||||
}
|
||||
|
||||
static getTableData (params) {
|
||||
return ipcRenderer.invoke('get-table-data', params);
|
||||
return ipcRenderer.invoke('get-table-data', unproxify(params));
|
||||
}
|
||||
|
||||
static getTableApproximateCount (params) {
|
||||
return ipcRenderer.invoke('get-table-count', params);
|
||||
return ipcRenderer.invoke('get-table-count', unproxify(params));
|
||||
}
|
||||
|
||||
static getTableOptions (params) {
|
||||
return ipcRenderer.invoke('get-table-options', params);
|
||||
return ipcRenderer.invoke('get-table-options', unproxify(params));
|
||||
}
|
||||
|
||||
static getTableIndexes (params) {
|
||||
return ipcRenderer.invoke('get-table-indexes', params);
|
||||
return ipcRenderer.invoke('get-table-indexes', unproxify(params));
|
||||
}
|
||||
|
||||
static getKeyUsage (params) {
|
||||
return ipcRenderer.invoke('get-key-usage', params);
|
||||
return ipcRenderer.invoke('get-key-usage', unproxify(params));
|
||||
}
|
||||
|
||||
static updateTableCell (params) {
|
||||
return ipcRenderer.invoke('update-table-cell', params);
|
||||
return ipcRenderer.invoke('update-table-cell', unproxify(params));
|
||||
}
|
||||
|
||||
static deleteTableRows (params) {
|
||||
return ipcRenderer.invoke('delete-table-rows', params);
|
||||
return ipcRenderer.invoke('delete-table-rows', unproxify(params));
|
||||
}
|
||||
|
||||
static insertTableRows (params) {
|
||||
return ipcRenderer.invoke('insert-table-rows', params);
|
||||
return ipcRenderer.invoke('insert-table-rows', unproxify(params));
|
||||
}
|
||||
|
||||
static insertTableFakeRows (params) {
|
||||
return ipcRenderer.invoke('insert-table-fake-rows', params);
|
||||
return ipcRenderer.invoke('insert-table-fake-rows', unproxify(params));
|
||||
}
|
||||
|
||||
static getForeignList (params) {
|
||||
return ipcRenderer.invoke('get-foreign-list', params);
|
||||
return ipcRenderer.invoke('get-foreign-list', unproxify(params));
|
||||
}
|
||||
|
||||
static createTable (params) {
|
||||
return ipcRenderer.invoke('create-table', params);
|
||||
return ipcRenderer.invoke('create-table', unproxify(params));
|
||||
}
|
||||
|
||||
static alterTable (params) {
|
||||
return ipcRenderer.invoke('alter-table', params);
|
||||
return ipcRenderer.invoke('alter-table', unproxify(params));
|
||||
}
|
||||
|
||||
static duplicateTable (params) {
|
||||
return ipcRenderer.invoke('duplicate-table', params);
|
||||
return ipcRenderer.invoke('duplicate-table', unproxify(params));
|
||||
}
|
||||
|
||||
static truncateTable (params) {
|
||||
return ipcRenderer.invoke('truncate-table', params);
|
||||
return ipcRenderer.invoke('truncate-table', unproxify(params));
|
||||
}
|
||||
|
||||
static dropTable (params) {
|
||||
return ipcRenderer.invoke('drop-table', params);
|
||||
return ipcRenderer.invoke('drop-table', unproxify(params));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static getTriggerInformations (params) {
|
||||
return ipcRenderer.invoke('get-trigger-informations', params);
|
||||
return ipcRenderer.invoke('get-trigger-informations', unproxify(params));
|
||||
}
|
||||
|
||||
static dropTrigger (params) {
|
||||
return ipcRenderer.invoke('drop-trigger', params);
|
||||
return ipcRenderer.invoke('drop-trigger', unproxify(params));
|
||||
}
|
||||
|
||||
static alterTrigger (params) {
|
||||
return ipcRenderer.invoke('alter-trigger', params);
|
||||
return ipcRenderer.invoke('alter-trigger', unproxify(params));
|
||||
}
|
||||
|
||||
static createTrigger (params) {
|
||||
return ipcRenderer.invoke('create-trigger', params);
|
||||
return ipcRenderer.invoke('create-trigger', unproxify(params));
|
||||
}
|
||||
|
||||
static toggleTrigger (params) {
|
||||
return ipcRenderer.invoke('toggle-trigger', params);
|
||||
return ipcRenderer.invoke('toggle-trigger', unproxify(params));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static getUsers (params) {
|
||||
return ipcRenderer.invoke('get-users', params);
|
||||
return ipcRenderer.invoke('get-users', unproxify(params));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
'use strict';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { unproxify } from '../libs/unproxify';
|
||||
|
||||
export default class {
|
||||
static getViewInformations (params) {
|
||||
return ipcRenderer.invoke('get-view-informations', params);
|
||||
return ipcRenderer.invoke('get-view-informations', unproxify(params));
|
||||
}
|
||||
|
||||
static dropView (params) {
|
||||
return ipcRenderer.invoke('drop-view', params);
|
||||
return ipcRenderer.invoke('drop-view', unproxify(params));
|
||||
}
|
||||
|
||||
static alterView (params) {
|
||||
return ipcRenderer.invoke('alter-view', params);
|
||||
return ipcRenderer.invoke('alter-view', unproxify(params));
|
||||
}
|
||||
|
||||
static createView (params) {
|
||||
return ipcRenderer.invoke('create-view', params);
|
||||
return ipcRenderer.invoke('create-view', unproxify(params));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||
/* eslint-disable @typescript-eslint/no-this-alias */
|
||||
/* eslint-disable no-labels */
|
||||
/* eslint-disable no-return-assign */
|
||||
/* eslint-disable no-cond-assign */
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import { toRaw } from 'vue';
|
||||
|
||||
/**
|
||||
* @param {*} val
|
||||
* @param {Boolean} json converts the value in JSON object (default true)
|
||||
*/
|
||||
export function unproxify (val, json = true) {
|
||||
if (json)// JSON conversion
|
||||
return JSON.parse(JSON.stringify(val));
|
||||
else if (Array.isArray(val))// If array
|
||||
return toRaw(val);
|
||||
else if (typeof val === 'object') { // If object
|
||||
const result = {};
|
||||
for (const key in val)
|
||||
result[key] = toRaw(val[key]);
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return toRaw(val);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue