mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
ec75f9546a | |||
9bc9adb7cf | |||
b4d14d98db | |||
c21bd6075c | |||
44647f5b55 | |||
3f9e6d85ca | |||
6a6f43a718 | |||
f12a04b052 | |||
abf829867e | |||
b71f04e5aa | |||
7725fafe85 | |||
ed3d35f131 | |||
e0946f04f7 | |||
0891e7be8c | |||
f312cf5f85 | |||
05e0d310ec | |||
|
1e0b2b4cae | ||
5ee728cfe4 | |||
a91fa8ff54 | |||
|
2c13433900 | ||
dcc2a4c51c | |||
7537dff401 | |||
853ee1f572 | |||
cf9c7c600a | |||
73b88cad9e | |||
d2eb31a63d | |||
d6b36b1f80 | |||
|
d66b932683 | ||
20f5497034 | |||
d4ed886489 | |||
|
aaa14f112a | ||
|
e0f3ff6939 | ||
72a328785c | |||
4c2a1998a9 | |||
8e705706ae | |||
56b0a4815c | |||
a9a4344a71 | |||
ec5ab73b19 | |||
71a5b5c828 | |||
a703dcc53e | |||
36e98e0742 | |||
f632a0f189 |
50
CHANGELOG.md
50
CHANGELOG.md
@@ -2,6 +2,56 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
### [0.5.10](https://github.com/antares-sql/antares/compare/v0.5.9...v0.5.10) (2022-07-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* context menu to copy queries from console ([c21bd60](https://github.com/antares-sql/antares/commit/c21bd6075c1203607c05e45b76233d57e3008190))
|
||||||
|
* Ctrl+PgUp & Ctrl+PgDn to navigate between tabs ([abf8298](https://github.com/antares-sql/antares/commit/abf829867e567354e534cff3e02a6d43f4c7a262))
|
||||||
|
* field names suggestion for tables in the query ([b71f04e](https://github.com/antares-sql/antares/commit/b71f04e5aa3c37eaa160dfbc76d1b84789e3543e))
|
||||||
|
* initial console implementation ([6a6f43a](https://github.com/antares-sql/antares/commit/6a6f43a718561e0abd2cb89048b7fe45d08736ae))
|
||||||
|
* ipc event channel to send logs to renderer ([f12a04b](https://github.com/antares-sql/antares/commit/f12a04b0524f1172334c89afeb27675c19ff68d2))
|
||||||
|
* open/close console on single connection ([44647f5](https://github.com/antares-sql/antares/commit/44647f5b5508965bf5a7264add89e175c725e877))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* exception on QueryEditor with null modelValue ([9bc9adb](https://github.com/antares-sql/antares/commit/9bc9adb7cff19b86a99491d968485a4cd7b47b99))
|
||||||
|
* fields content language detection not working properly ([a91fa8f](https://github.com/antares-sql/antares/commit/a91fa8ff54bbf1f8475666efd3a268a3a4f07f0c))
|
||||||
|
* **Linux:** ctrl+space shortcut not working ([ed3d35f](https://github.com/antares-sql/antares/commit/ed3d35f1319a1e2edcb8104f2045a71b9e9754a2))
|
||||||
|
* unable to delete by select all in left bar search, closes [#368](https://github.com/antares-sql/antares/issues/368) ([7725faf](https://github.com/antares-sql/antares/commit/7725fafe852479720fa619ced0970f2fa0099191))
|
||||||
|
* unable to update data on tables missing primary or unique key ([e0946f0](https://github.com/antares-sql/antares/commit/e0946f04f792d25c187ea56d4714bdacc016ada3))
|
||||||
|
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
* improved resize of text editor resizing console height ([3f9e6d8](https://github.com/antares-sql/antares/commit/3f9e6d85ca445eea1028effa32418eee4980f87d))
|
||||||
|
* **UI:** improved visibility of explore bar tooltips ([f312cf5](https://github.com/antares-sql/antares/commit/f312cf5f855deddd562c26d1835f78d16499b93b))
|
||||||
|
|
||||||
|
### [0.5.9](https://github.com/antares-sql/antares/compare/v0.5.8...v0.5.9) (2022-07-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* ability to pin/unpin and delete connections from the "all connections" modal ([8e70570](https://github.com/antares-sql/antares/commit/8e705706aecc5c9790329e63e61a1c02fa5d0342))
|
||||||
|
* connections sorted by last usage by default and option to pin them ([36e98e0](https://github.com/antares-sql/antares/commit/36e98e0742657e25df7768aa5b3b7cb350df5509))
|
||||||
|
* ctrl/cmd+space to open all connections modal ([a9a4344](https://github.com/antares-sql/antares/commit/a9a4344a71cc0f8f156b839733f6ddc200a26268))
|
||||||
|
* modal with all connections ([a703dcc](https://github.com/antares-sql/antares/commit/a703dcc53eb920117bc346a3c21f0c729c0ad96d))
|
||||||
|
* option to disable scratchpad ([56b0a48](https://github.com/antares-sql/antares/commit/56b0a4815c6f54eef164d849f6ca25af1e142b16))
|
||||||
|
* search form in all connections modal ([ec5ab73](https://github.com/antares-sql/antares/commit/ec5ab73b19d99e9971ae87e5f0a8d1bd1c34ef00))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* error on export schema ([cf9c7c6](https://github.com/antares-sql/antares/commit/cf9c7c600aa915cef1ec3777866badb7ab1312ee))
|
||||||
|
* missing option for untrusted ssl connection on connections edit panel ([71a5b5c](https://github.com/antares-sql/antares/commit/71a5b5c8285fb777c43e7f6516006bfe9f52591c))
|
||||||
|
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
|
||||||
|
* **UI:** improved focus visibility for buttons ([d2eb31a](https://github.com/antares-sql/antares/commit/d2eb31a63d612323f8738eded1e1ce7b23554001))
|
||||||
|
|
||||||
### [0.5.8](https://github.com/antares-sql/antares/compare/v0.5.7...v0.5.8) (2022-07-02)
|
### [0.5.8](https://github.com/antares-sql/antares/compare/v0.5.7...v0.5.8) (2022-07-02)
|
||||||
|
|
||||||
|
|
||||||
|
18420
package-lock.json
generated
18420
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "antares",
|
"name": "antares",
|
||||||
"productName": "Antares",
|
"productName": "Antares",
|
||||||
"version": "0.5.8",
|
"version": "0.5.10",
|
||||||
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
|
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/antares-sql/antares.git",
|
"repository": "https://github.com/antares-sql/antares.git",
|
||||||
@@ -117,11 +117,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "~2.0.1",
|
"@electron/remote": "~2.0.1",
|
||||||
"@faker-js/faker": "~6.1.2",
|
"@faker-js/faker": "~6.1.2",
|
||||||
"@mdi/font": "~6.1.95",
|
"@mdi/font": "~6.9.96",
|
||||||
"@turf/helpers": "~6.5.0",
|
"@turf/helpers": "~6.5.0",
|
||||||
"@vscode/vscode-languagedetection": "~1.0.21",
|
"@vueuse/core": "~8.7.5",
|
||||||
"ace-builds": "~1.4.13",
|
"ace-builds": "~1.4.13",
|
||||||
"better-sqlite3": "~7.5.0",
|
"better-sqlite3": "~7.5.1",
|
||||||
"electron-log": "~4.4.1",
|
"electron-log": "~4.4.1",
|
||||||
"electron-store": "~8.0.1",
|
"electron-store": "~8.0.1",
|
||||||
"electron-updater": "~4.6.5",
|
"electron-updater": "~4.6.5",
|
||||||
@@ -129,7 +129,7 @@
|
|||||||
"encoding": "~0.1.13",
|
"encoding": "~0.1.13",
|
||||||
"leaflet": "~1.7.1",
|
"leaflet": "~1.7.1",
|
||||||
"marked": "~4.0.0",
|
"marked": "~4.0.0",
|
||||||
"moment": "~2.29.1",
|
"moment": "~2.29.4",
|
||||||
"mysql2": "~2.3.2",
|
"mysql2": "~2.3.2",
|
||||||
"pg": "~8.7.1",
|
"pg": "~8.7.1",
|
||||||
"pg-query-stream": "~4.2.3",
|
"pg-query-stream": "~4.2.3",
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
"sql-formatter": "~4.0.2",
|
"sql-formatter": "~4.0.2",
|
||||||
"ssh2-promise": "~1.0.2",
|
"ssh2-promise": "~1.0.2",
|
||||||
"v-mask": "~2.3.0",
|
"v-mask": "~2.3.0",
|
||||||
"vue": "~3.2.33",
|
"vue": "~3.2.37",
|
||||||
"vue-i18n": "~9.1.9",
|
"vue-i18n": "~9.1.9",
|
||||||
"vuedraggable": "~4.1.0"
|
"vuedraggable": "~4.1.0"
|
||||||
},
|
},
|
||||||
|
@@ -25,6 +25,7 @@ export interface IpcResponse<T = any> {
|
|||||||
*/
|
*/
|
||||||
export interface ClientParams {
|
export interface ClientParams {
|
||||||
client: ClientCode;
|
client: ClientCode;
|
||||||
|
uid?: string;
|
||||||
params:
|
params:
|
||||||
mysql.ConnectionOptions & {schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean}
|
mysql.ConnectionOptions & {schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean}
|
||||||
| pg.ClientConfig & {schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean}
|
| pg.ClientConfig & {schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean}
|
||||||
|
@@ -7,6 +7,12 @@ export interface TableParams {
|
|||||||
|
|
||||||
export interface ExportOptions {
|
export interface ExportOptions {
|
||||||
schema: string;
|
schema: string;
|
||||||
|
tables: {
|
||||||
|
table: string;
|
||||||
|
includeStructure: boolean;
|
||||||
|
includeContent: boolean;
|
||||||
|
includeDropStatement: boolean;
|
||||||
|
}[];
|
||||||
includes: {[key: string]: boolean};
|
includes: {[key: string]: boolean};
|
||||||
outputFormat: 'sql' | 'sql.zip';
|
outputFormat: 'sql' | 'sql.zip';
|
||||||
outputFile: string;
|
outputFile: string;
|
||||||
|
192
src/common/libs/langDetector.ts
Normal file
192
src/common/libs/langDetector.ts
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
function isJSON (str: string) {
|
||||||
|
try {
|
||||||
|
if (!['{', '['].includes(str.trim()[0]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
JSON.parse(str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isHTML (str: string) {
|
||||||
|
const tags = [
|
||||||
|
'a',
|
||||||
|
'abbr',
|
||||||
|
'address',
|
||||||
|
'area',
|
||||||
|
'article',
|
||||||
|
'aside',
|
||||||
|
'audio',
|
||||||
|
'b',
|
||||||
|
'base',
|
||||||
|
'bdi',
|
||||||
|
'bdo',
|
||||||
|
'blockquote',
|
||||||
|
'body',
|
||||||
|
'br',
|
||||||
|
'button',
|
||||||
|
'canvas',
|
||||||
|
'caption',
|
||||||
|
'cite',
|
||||||
|
'code',
|
||||||
|
'col',
|
||||||
|
'colgroup',
|
||||||
|
'data',
|
||||||
|
'datalist',
|
||||||
|
'dd',
|
||||||
|
'del',
|
||||||
|
'details',
|
||||||
|
'dfn',
|
||||||
|
'dialog',
|
||||||
|
'div',
|
||||||
|
'dl',
|
||||||
|
'dt',
|
||||||
|
'em',
|
||||||
|
'embed',
|
||||||
|
'fieldset',
|
||||||
|
'figcaption',
|
||||||
|
'figure',
|
||||||
|
'footer',
|
||||||
|
'form',
|
||||||
|
'h1',
|
||||||
|
'h2',
|
||||||
|
'h3',
|
||||||
|
'h4',
|
||||||
|
'h5',
|
||||||
|
'h6',
|
||||||
|
'head',
|
||||||
|
'header',
|
||||||
|
'hgroup',
|
||||||
|
'hr',
|
||||||
|
'html',
|
||||||
|
'i',
|
||||||
|
'iframe',
|
||||||
|
'img',
|
||||||
|
'input',
|
||||||
|
'ins',
|
||||||
|
'kbd',
|
||||||
|
'label',
|
||||||
|
'legend',
|
||||||
|
'li',
|
||||||
|
'link',
|
||||||
|
'main',
|
||||||
|
'map',
|
||||||
|
'mark',
|
||||||
|
'math',
|
||||||
|
'menu',
|
||||||
|
'menuitem',
|
||||||
|
'meta',
|
||||||
|
'meter',
|
||||||
|
'nav',
|
||||||
|
'noscript',
|
||||||
|
'object',
|
||||||
|
'ol',
|
||||||
|
'optgroup',
|
||||||
|
'option',
|
||||||
|
'output',
|
||||||
|
'p',
|
||||||
|
'param',
|
||||||
|
'picture',
|
||||||
|
'pre',
|
||||||
|
'progress',
|
||||||
|
'q',
|
||||||
|
'rb',
|
||||||
|
'rp',
|
||||||
|
'rt',
|
||||||
|
'rtc',
|
||||||
|
'ruby',
|
||||||
|
's',
|
||||||
|
'samp',
|
||||||
|
'script',
|
||||||
|
'section',
|
||||||
|
'select',
|
||||||
|
'slot',
|
||||||
|
'small',
|
||||||
|
'source',
|
||||||
|
'span',
|
||||||
|
'strong',
|
||||||
|
'style',
|
||||||
|
'sub',
|
||||||
|
'summary',
|
||||||
|
'sup',
|
||||||
|
'svg',
|
||||||
|
'table',
|
||||||
|
'tbody',
|
||||||
|
'td',
|
||||||
|
'template',
|
||||||
|
'textarea',
|
||||||
|
'tfoot',
|
||||||
|
'th',
|
||||||
|
'thead',
|
||||||
|
'time',
|
||||||
|
'title',
|
||||||
|
'tr',
|
||||||
|
'track',
|
||||||
|
'u',
|
||||||
|
'ul',
|
||||||
|
'var',
|
||||||
|
'video',
|
||||||
|
'wbr'
|
||||||
|
];
|
||||||
|
const doc = new DOMParser().parseFromString(str, 'text/html');
|
||||||
|
const lowerStr = str.toLowerCase();
|
||||||
|
if (Array.from(doc.body.childNodes).some(node => node.nodeType === 1))
|
||||||
|
return tags.some((tag) => lowerStr.includes(`<${tag}>`));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSVG (str: string) {
|
||||||
|
const doc = new DOMParser().parseFromString(str, 'text/xml');
|
||||||
|
const lowerStr = str.toLowerCase();
|
||||||
|
const errorNode = doc.querySelector('parsererror');
|
||||||
|
if (!errorNode)
|
||||||
|
return lowerStr.includes('<svg');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isXML (str: string) {
|
||||||
|
const doc = new DOMParser().parseFromString(str, 'text/xml');
|
||||||
|
const errorNode = doc.querySelector('parsererror');
|
||||||
|
return !errorNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMD (str: string) {
|
||||||
|
const mdChecks = [
|
||||||
|
'# ',
|
||||||
|
'`',
|
||||||
|
'- ',
|
||||||
|
'+ ',
|
||||||
|
'* ',
|
||||||
|
'1. ',
|
||||||
|
'**',
|
||||||
|
'__',
|
||||||
|
'~~',
|
||||||
|
'>> ',
|
||||||
|
'](http',
|
||||||
|
'![',
|
||||||
|
'[ ]',
|
||||||
|
'[x]'
|
||||||
|
];
|
||||||
|
|
||||||
|
return mdChecks.some((tag) => str.includes(tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function langDetector (str: string) {
|
||||||
|
if (!str.trim().length)
|
||||||
|
return 'text';
|
||||||
|
if (isJSON(str))
|
||||||
|
return 'json';
|
||||||
|
if (isHTML(str))
|
||||||
|
return 'html';
|
||||||
|
if (isSVG(str))
|
||||||
|
return 'svg';
|
||||||
|
if (isXML(str))
|
||||||
|
return 'xml';
|
||||||
|
if (isMD(str))
|
||||||
|
return 'markdown';
|
||||||
|
return 'text';
|
||||||
|
}
|
49
src/common/shortcuts.ts
Normal file
49
src/common/shortcuts.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
interface ShortcutRecord {
|
||||||
|
event: string;
|
||||||
|
keys: Electron.Accelerator[];
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shortcuts: ShortcutRecord[] = [
|
||||||
|
{
|
||||||
|
event: 'open-new-tab',
|
||||||
|
keys: ['CommandOrControl+T'],
|
||||||
|
description: 'Open a new query tab'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: 'close-tab',
|
||||||
|
keys: ['CommandOrControl+W'],
|
||||||
|
description: 'Close tab'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: 'next-tab',
|
||||||
|
keys: ['Alt+CommandOrControl+Right', 'CommandOrControl+PageDown'],
|
||||||
|
description: 'Next tab'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: 'prev-tab',
|
||||||
|
keys: ['Alt+CommandOrControl+Left', 'CommandOrControl+PageUp'],
|
||||||
|
description: 'Previous tab'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: 'open-connections-modal',
|
||||||
|
keys: ['Shift+CommandOrControl+Space'],
|
||||||
|
description: 'Show all connections'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
event: 'toggle-console',
|
||||||
|
keys: ['CommandOrControl+F12', 'CommandOrControl+`'],
|
||||||
|
description: 'Toggle console'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let i = 1; i <= 9; i++) {
|
||||||
|
shortcuts.push(
|
||||||
|
{
|
||||||
|
event: `select-tab-${i}`,
|
||||||
|
keys: [`CommandOrControl+${i}`],
|
||||||
|
description: `Select tab number ${i}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { shortcuts };
|
@@ -55,6 +55,7 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const connection = await ClientsFactory.getClient({
|
const connection = await ClientsFactory.getClient({
|
||||||
|
uid: conn.uid,
|
||||||
client: conn.client,
|
client: conn.client,
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
@@ -128,6 +129,7 @@ export default (connections: {[key: string]: antares.Client}) => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const connection = ClientsFactory.getClient({
|
const connection = ClientsFactory.getClient({
|
||||||
|
uid: conn.uid,
|
||||||
client: conn.client,
|
client: conn.client,
|
||||||
params,
|
params,
|
||||||
poolSize: 5
|
poolSize: 5
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
import * as antares from 'common/interfaces/antares';
|
import * as antares from 'common/interfaces/antares';
|
||||||
|
import { webContents } from 'electron';
|
||||||
import mysql from 'mysql2/promise';
|
import mysql from 'mysql2/promise';
|
||||||
import * as pg from 'pg';
|
import * as pg from 'pg';
|
||||||
import SSH2Promise from 'ssh2-promise';
|
import SSH2Promise from 'ssh2-promise';
|
||||||
|
|
||||||
const queryLogger = (sql: string) => {
|
const queryLogger = ({ sql, cUid }: {sql: string; cUid: string}) => {
|
||||||
// Remove comments, newlines and multiple spaces
|
// Remove comments, newlines and multiple spaces
|
||||||
const escapedSql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '').replace(/\s\s+/g, ' ');
|
const escapedSql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '').replace(/\s\s+/g, ' ');
|
||||||
|
const mainWindow = webContents.fromId(1);
|
||||||
|
mainWindow.send('query-log', { cUid, sql: escapedSql, date: new Date() });
|
||||||
console.log(escapedSql);
|
console.log(escapedSql);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -14,15 +17,17 @@ const queryLogger = (sql: string) => {
|
|||||||
*/
|
*/
|
||||||
export class AntaresCore {
|
export class AntaresCore {
|
||||||
_client: antares.ClientCode;
|
_client: antares.ClientCode;
|
||||||
|
protected _cUid: string
|
||||||
protected _params: mysql.ConnectionOptions | pg.ClientConfig | { databasePath: string; readonly: boolean};
|
protected _params: mysql.ConnectionOptions | pg.ClientConfig | { databasePath: string; readonly: boolean};
|
||||||
protected _poolSize: number;
|
protected _poolSize: number;
|
||||||
protected _ssh?: SSH2Promise;
|
protected _ssh?: SSH2Promise;
|
||||||
protected _logger: (sql: string) => void;
|
protected _logger: (args: {sql: string; cUid: string}) => void;
|
||||||
protected _queryDefaults: antares.QueryBuilderObject;
|
protected _queryDefaults: antares.QueryBuilderObject;
|
||||||
protected _query: antares.QueryBuilderObject;
|
protected _query: antares.QueryBuilderObject;
|
||||||
|
|
||||||
constructor (args: antares.ClientParams) {
|
constructor (args: antares.ClientParams) {
|
||||||
this._client = args.client;
|
this._client = args.client;
|
||||||
|
this._cUid = args.uid;
|
||||||
this._params = args.params;
|
this._params = args.params;
|
||||||
this._poolSize = args.poolSize || undefined;
|
this._poolSize = args.poolSize || undefined;
|
||||||
this._logger = args.logger || queryLogger;
|
this._logger = args.logger || queryLogger;
|
||||||
|
@@ -1536,7 +1536,7 @@ export class MySQLClient extends AntaresCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
|
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
|
||||||
if (process.env.NODE_ENV === 'development') this._logger(sql);
|
if (process.env.NODE_ENV === 'development') this._logger({ cUid: this._cUid, sql });
|
||||||
|
|
||||||
args = {
|
args = {
|
||||||
nest: false,
|
nest: false,
|
||||||
|
@@ -1314,7 +1314,7 @@ export class PostgreSQLClient extends AntaresCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
|
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
|
||||||
if (process.env.NODE_ENV === 'development') this._logger(sql);
|
if (process.env.NODE_ENV === 'development') this._logger({ cUid: this._cUid, sql });
|
||||||
|
|
||||||
args = {
|
args = {
|
||||||
nest: false,
|
nest: false,
|
||||||
|
@@ -586,7 +586,7 @@ export class SQLiteClient extends AntaresCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
|
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
|
||||||
if (process.env.NODE_ENV === 'development') this._logger(sql);// TODO: replace BLOB content with a placeholder
|
if (process.env.NODE_ENV === 'development') this._logger({ cUid: this._cUid, sql });// TODO: replace BLOB content with a placeholder
|
||||||
|
|
||||||
args = {
|
args = {
|
||||||
nest: false,
|
nest: false,
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
import { app, BrowserWindow, /* session, */ nativeImage, Menu, ipcMain } from 'electron';
|
import { app, BrowserWindow, globalShortcut, nativeImage, Menu, ipcMain } from 'electron';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as Store from 'electron-store';
|
import * as Store from 'electron-store';
|
||||||
import * as windowStateKeeper from 'electron-window-state';
|
import * as windowStateKeeper from 'electron-window-state';
|
||||||
import * as remoteMain from '@electron/remote/main';
|
import * as remoteMain from '@electron/remote/main';
|
||||||
|
|
||||||
import ipcHandlers from './ipc-handlers';
|
import ipcHandlers from './ipc-handlers';
|
||||||
|
import { shortcuts } from 'common/shortcuts';
|
||||||
|
|
||||||
Store.initRenderer();
|
Store.initRenderer();
|
||||||
const persistentStore = new Store({ name: 'settings' });
|
const persistentStore = new Store({ name: 'settings' });
|
||||||
@@ -142,6 +143,31 @@ else {
|
|||||||
window.webContents.session.loadExtension(extensionPath, { allowFileAccess: true }).catch(console.error);
|
window.webContents.session.loadExtension(extensionPath, { allowFileAccess: true }).catch(console.error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.on('browser-window-focus', () => {
|
||||||
|
// Send registered shortcut events to window
|
||||||
|
for (const shortcut of shortcuts) {
|
||||||
|
for (const key of shortcut.keys) {
|
||||||
|
globalShortcut.register(key, () => {
|
||||||
|
mainWindow.webContents.send(shortcut.event);
|
||||||
|
if (isDevelopment) console.log('EVENT:', shortcut);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDevelopment) { // Dev shortcuts
|
||||||
|
globalShortcut.register('Shift+CommandOrControl+F5', () => {
|
||||||
|
mainWindow.reload();
|
||||||
|
});
|
||||||
|
globalShortcut.register('Shift+CommandOrControl+F12', () => {
|
||||||
|
mainWindow.webContents.openDevTools();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('browser-window-blur', () => {
|
||||||
|
globalShortcut.unregisterAll();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createAppMenu () {
|
function createAppMenu () {
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<div id="wrapper" :class="[`theme-${applicationTheme}`, !disableBlur || 'no-blur']">
|
<div id="wrapper" :class="[`theme-${applicationTheme}`, !disableBlur || 'no-blur']">
|
||||||
<TheTitleBar />
|
<TheTitleBar />
|
||||||
<div id="window-content">
|
<div id="window-content">
|
||||||
<TheSettingBar />
|
<TheSettingBar @show-connections-modal="isAllConnectionsModal = true" />
|
||||||
<div id="main-content" class="container">
|
<div id="main-content" class="container">
|
||||||
<div class="columns col-gapless">
|
<div class="columns col-gapless">
|
||||||
<Workspace
|
<Workspace
|
||||||
@@ -21,13 +21,15 @@
|
|||||||
<BaseTextEditor class="d-none" value="" />
|
<BaseTextEditor class="d-none" value="" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ModalAllConnections v-if="isAllConnectionsModal" @close="isAllConnectionsModal = false" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import { defineAsyncComponent } from 'vue';
|
import { defineAsyncComponent, onMounted, Ref, ref } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import { Menu, getCurrentWindow } from '@electron/remote';
|
import { Menu, getCurrentWindow } from '@electron/remote';
|
||||||
import { useApplicationStore } from '@/stores/application';
|
import { useApplicationStore } from '@/stores/application';
|
||||||
import { useConnectionsStore } from '@/stores/connections';
|
import { useConnectionsStore } from '@/stores/connections';
|
||||||
@@ -35,27 +37,24 @@ import { useSettingsStore } from '@/stores/settings';
|
|||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import TheSettingBar from '@/components/TheSettingBar.vue';
|
import TheSettingBar from '@/components/TheSettingBar.vue';
|
||||||
|
|
||||||
export default {
|
const { t } = useI18n();
|
||||||
name: 'App',
|
|
||||||
components: {
|
const TheTitleBar = defineAsyncComponent(() => import(/* webpackChunkName: "TheTitleBar" */'@/components/TheTitleBar.vue'));
|
||||||
TheTitleBar: defineAsyncComponent(() => import(/* webpackChunkName: "TheTitleBar" */'@/components/TheTitleBar.vue')),
|
const TheFooter = defineAsyncComponent(() => import(/* webpackChunkName: "TheFooter" */'@/components/TheFooter.vue'));
|
||||||
TheSettingBar,
|
const TheNotificationsBoard = defineAsyncComponent(() => import(/* webpackChunkName: "TheNotificationsBoard" */'@/components/TheNotificationsBoard.vue'));
|
||||||
TheFooter: defineAsyncComponent(() => import(/* webpackChunkName: "TheFooter" */'@/components/TheFooter.vue')),
|
const Workspace = defineAsyncComponent(() => import(/* webpackChunkName: "Workspace" */'@/components/Workspace.vue'));
|
||||||
TheNotificationsBoard: defineAsyncComponent(() => import(/* webpackChunkName: "TheNotificationsBoard" */'@/components/TheNotificationsBoard.vue')),
|
const WorkspaceAddConnectionPanel = defineAsyncComponent(() => import(/* webpackChunkName: "WorkspaceAddConnectionPanel" */'@/components/WorkspaceAddConnectionPanel.vue'));
|
||||||
Workspace: defineAsyncComponent(() => import(/* webpackChunkName: "Workspace" */'@/components/Workspace.vue')),
|
const ModalSettings = defineAsyncComponent(() => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings.vue'));
|
||||||
WorkspaceAddConnectionPanel: defineAsyncComponent(() => import(/* webpackChunkName: "WorkspaceAddConnectionPanel" */'@/components/WorkspaceAddConnectionPanel.vue')),
|
const ModalAllConnections = defineAsyncComponent(() => import(/* webpackChunkName: "ModalAllConnections" */'@/components/ModalAllConnections.vue'));
|
||||||
ModalSettings: defineAsyncComponent(() => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings.vue')),
|
const TheScratchpad = defineAsyncComponent(() => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad.vue'));
|
||||||
TheScratchpad: defineAsyncComponent(() => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad.vue')),
|
const BaseTextEditor = defineAsyncComponent(() => import(/* webpackChunkName: "BaseTextEditor" */'@/components/BaseTextEditor.vue'));
|
||||||
BaseTextEditor: defineAsyncComponent(() => import(/* webpackChunkName: "BaseTextEditor" */'@/components/BaseTextEditor.vue'))
|
|
||||||
},
|
|
||||||
setup () {
|
|
||||||
const applicationStore = useApplicationStore();
|
const applicationStore = useApplicationStore();
|
||||||
const connectionsStore = useConnectionsStore();
|
const connectionsStore = useConnectionsStore();
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isLoading,
|
|
||||||
isSettingModal,
|
isSettingModal,
|
||||||
isScratchpad
|
isScratchpad
|
||||||
} = storeToRefs(applicationStore);
|
} = storeToRefs(applicationStore);
|
||||||
@@ -66,46 +65,40 @@ export default {
|
|||||||
const { checkVersionUpdate } = applicationStore;
|
const { checkVersionUpdate } = applicationStore;
|
||||||
const { changeApplicationTheme } = settingsStore;
|
const { changeApplicationTheme } = settingsStore;
|
||||||
|
|
||||||
|
const isAllConnectionsModal: Ref<boolean> = ref(false);
|
||||||
|
|
||||||
|
ipcRenderer.on('open-connections-modal', () => {
|
||||||
|
isAllConnectionsModal.value = true;
|
||||||
|
});
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
changeApplicationTheme(applicationTheme.value);// Forces persistentStore to save on file and mail process
|
changeApplicationTheme(applicationTheme.value);// Forces persistentStore to save on file and mail process
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
onMounted(() => {
|
||||||
isLoading,
|
|
||||||
isSettingModal,
|
|
||||||
isScratchpad,
|
|
||||||
checkVersionUpdate,
|
|
||||||
changeApplicationTheme,
|
|
||||||
connections,
|
|
||||||
applicationTheme,
|
|
||||||
disableBlur,
|
|
||||||
selectedWorkspace
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
ipcRenderer.send('check-for-updates');
|
ipcRenderer.send('check-for-updates');
|
||||||
this.checkVersionUpdate();
|
checkVersionUpdate();
|
||||||
|
|
||||||
const InputMenu = Menu.buildFromTemplate([
|
const InputMenu = Menu.buildFromTemplate([
|
||||||
{
|
{
|
||||||
label: this.$t('word.cut'),
|
label: t('word.cut'),
|
||||||
role: 'cut'
|
role: 'cut'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('word.copy'),
|
label: t('word.copy'),
|
||||||
role: 'copy'
|
role: 'copy'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('word.paste'),
|
label: t('word.paste'),
|
||||||
role: 'paste'
|
role: 'paste'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.$t('message.selectAll'),
|
label: t('message.selectAll'),
|
||||||
role: 'selectAll'
|
role: 'selectAll'
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
@@ -125,8 +118,7 @@ export default {
|
|||||||
node = node.parentNode;
|
node = node.parentNode;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -159,7 +151,7 @@ export default {
|
|||||||
.connection-panel-wrapper {
|
.connection-panel-wrapper {
|
||||||
height: calc(100vh - #{$excluding-size});
|
height: calc(100vh - #{$excluding-size});
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-top: 15vh;
|
padding-top: 10vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
358
src/renderer/components/ModalAllConnections.vue
Normal file
358
src/renderer/components/ModalAllConnections.vue
Normal file
@@ -0,0 +1,358 @@
|
|||||||
|
<template>
|
||||||
|
<Teleport to="#window-content">
|
||||||
|
<div class="modal active">
|
||||||
|
<a class="modal-overlay" @click.stop="closeModal" />
|
||||||
|
<div ref="trapRef" class="modal-container p-0 pb-4">
|
||||||
|
<div class="modal-header pl-2">
|
||||||
|
<div class="modal-title h6">
|
||||||
|
<div class="d-flex">
|
||||||
|
<i class="mdi mdi-24px mdi-apps mr-1" />
|
||||||
|
<span class="cut-text">{{ $t('message.allConnections') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
|
||||||
|
</div>
|
||||||
|
<div class="modal-body py-0">
|
||||||
|
<div class="columns">
|
||||||
|
<div class="connections-search column col-12 columns col-gapless">
|
||||||
|
<div class="column col-12 mt-2">
|
||||||
|
<div ref="searchForm" class="form-group has-icon-right p-2 m-0">
|
||||||
|
<input
|
||||||
|
v-model="searchTerm"
|
||||||
|
class="form-input"
|
||||||
|
type="text"
|
||||||
|
:placeholder="t('message.searchForConnections')"
|
||||||
|
@keypress.esc="searchTerm = ''"
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<TransitionGroup name="fade" :duration="{ enter: 200, leave: 200 }">
|
||||||
|
<div
|
||||||
|
v-for="connection in filteredConnections"
|
||||||
|
:key="connection.uid"
|
||||||
|
class="connection-block column col-md-6 col-lg-4 col-3 p-3"
|
||||||
|
tabindex="0"
|
||||||
|
@click.stop="selectConnection(connection.uid)"
|
||||||
|
@keypress.stop.enter="selectConnection(connection.uid)"
|
||||||
|
@mouseover="connectionHover = connection.uid"
|
||||||
|
@mouseleave="connectionHover = null"
|
||||||
|
>
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-header p-2 text-center p-relative">
|
||||||
|
<figure class="avatar avatar-lg pt-1 mb-1">
|
||||||
|
<i class="settingbar-element-icon dbi" :class="[`dbi-${connection.client}`]" />
|
||||||
|
</figure>
|
||||||
|
<div class="panel-title h6 text-ellipsis">
|
||||||
|
{{ getConnectionName(connection.uid) }}
|
||||||
|
</div>
|
||||||
|
<div class="panel-subtitle">
|
||||||
|
{{ clients.get(connection.client) || connection.client }}
|
||||||
|
</div>
|
||||||
|
<div class="all-connections-buttons p-absolute d-flex" style="top: 0; right: 0;">
|
||||||
|
<i
|
||||||
|
v-if="connection.isPinned"
|
||||||
|
class="all-connections-pinned mdi mdi-18px"
|
||||||
|
:class="connectionHover === connection.uid ? 'mdi-pin-off' : 'mdi-pin'"
|
||||||
|
:title="t('word.unpin')"
|
||||||
|
@click.stop="unpinConnection(connection.uid)"
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
v-else
|
||||||
|
class="all-connections-pin mdi mdi-18px mdi-pin mdi-rotate-45"
|
||||||
|
:title="t('word.pin')"
|
||||||
|
@click.stop="pinConnection(connection.uid)"
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
class="all-connections-delete mdi mdi-delete mdi-18px ml-2"
|
||||||
|
:title="t('word.delete')"
|
||||||
|
@click.stop="askToDelete(connection)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body text-center">
|
||||||
|
<div v-if="connection.databasePath">
|
||||||
|
<div class="text-ellipsis" :title="connection.databasePath">
|
||||||
|
<i class="mdi mdi-database d-inline" /> <span class="text-bold">{{
|
||||||
|
connection.databasePath
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="text-ellipsis" :title="`${connection.host}:${connection.port}`">
|
||||||
|
<i class="mdi mdi-server d-inline" /> <span class="text-bold">{{ connection.host
|
||||||
|
}}:{{ connection.port }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="connection.user">
|
||||||
|
<div class="text-ellipsis">
|
||||||
|
<i class="mdi mdi-account d-inline" /> <span class="text-bold">{{ connection.user
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="connection.schema">
|
||||||
|
<div class="text-ellipsis">
|
||||||
|
<i class="mdi mdi-database d-inline" /> <span class="text-bold">{{ connection.schema
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="connection.database">
|
||||||
|
<div class="text-ellipsis">
|
||||||
|
<i class="mdi mdi-database d-inline" /> <span class="text-bold">{{
|
||||||
|
connection.database
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-footer text-center py-0">
|
||||||
|
<div v-if="connection.ssl" class="chip bg-success mt-2">
|
||||||
|
<i class="mdi mdi-lock mdi-18px mr-1" />
|
||||||
|
SSL
|
||||||
|
</div>
|
||||||
|
<div v-if="connection.ssh" class="chip bg-success mt-2">
|
||||||
|
<i class="mdi mdi-console-network mdi-18px mr-1" />
|
||||||
|
SSH
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
key="trick"
|
||||||
|
readonly
|
||||||
|
class="p-absolute"
|
||||||
|
style="width: 1px; height: 1px; opacity: 0"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
<!-- workaround for useFocusTrap $lastFocusable -->
|
||||||
|
</TransitionGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ConfirmModal
|
||||||
|
v-if="isConfirmModal"
|
||||||
|
@confirm="confirmDeleteConnection"
|
||||||
|
@hide="isConfirmModal = false"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div class="d-flex">
|
||||||
|
<i class="mdi mdi-24px mdi-server-remove mr-1" /> {{ t('message.deleteConnection') }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #body>
|
||||||
|
<div class="mb-2">
|
||||||
|
{{ t('message.deleteCorfirm') }} <b>{{ selectedConnectionName }}</b>?
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ConfirmModal>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, onBeforeUnmount, Ref, ref } from 'vue';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useFocusTrap } from '@/composables/useFocusTrap';
|
||||||
|
import { useConnectionsStore } from '@/stores/connections';
|
||||||
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
|
import ConfirmModal from '@/components/BaseConfirmModal.vue';
|
||||||
|
import { ConnectionParams } from 'common/interfaces/antares';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const connectionsStore = useConnectionsStore();
|
||||||
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
|
||||||
|
const { connections,
|
||||||
|
pinnedConnections,
|
||||||
|
lastConnections
|
||||||
|
} = storeToRefs(connectionsStore);
|
||||||
|
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||||
|
|
||||||
|
const {
|
||||||
|
getConnectionName,
|
||||||
|
pinConnection,
|
||||||
|
unpinConnection,
|
||||||
|
deleteConnection
|
||||||
|
} = connectionsStore;
|
||||||
|
const { selectWorkspace } = workspacesStore;
|
||||||
|
|
||||||
|
const { trapRef } = useFocusTrap();
|
||||||
|
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const clients = new Map([
|
||||||
|
['mysql', 'MySQL'],
|
||||||
|
['maria', 'MariaDB'],
|
||||||
|
['pg', 'PostgreSQL'],
|
||||||
|
['sqlite', 'SQLite']
|
||||||
|
]);
|
||||||
|
|
||||||
|
const searchTerm = ref('');
|
||||||
|
const isConfirmModal = ref(false);
|
||||||
|
const connectionHover: Ref<string> = ref(null);
|
||||||
|
const selectedConnection: Ref<ConnectionParams> = ref(null);
|
||||||
|
|
||||||
|
const sortedConnections = computed(() => {
|
||||||
|
return connections.value
|
||||||
|
.map(c => {
|
||||||
|
const connTime = lastConnections.value.find((lc) => lc.uid === c.uid)?.time || 0;
|
||||||
|
return {
|
||||||
|
...c,
|
||||||
|
time: connTime,
|
||||||
|
isPinned: pinnedConnections.value.has(c.uid)
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.isPinned < b.isPinned) return 1;
|
||||||
|
if (a.isPinned > b.isPinned) return -1;
|
||||||
|
if (a.time < b.time) return 1;
|
||||||
|
if (a.time > b.time) return -1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const filteredConnections = computed(() => {
|
||||||
|
return sortedConnections.value.filter(connection => {
|
||||||
|
return connection.name?.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase()) ||
|
||||||
|
connection.host?.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase()) ||
|
||||||
|
connection.database?.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase()) ||
|
||||||
|
connection.databasePath?.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase()) ||
|
||||||
|
connection.schema?.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase()) ||
|
||||||
|
connection.user?.toLocaleLowerCase().includes(searchTerm.value.toLocaleLowerCase()) ||
|
||||||
|
String(connection.port)?.includes(searchTerm.value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedConnectionName = computed(() => getConnectionName(selectedConnection.value?.uid));
|
||||||
|
|
||||||
|
const closeModal = () => emit('close');
|
||||||
|
|
||||||
|
const selectConnection = (uid: string) => {
|
||||||
|
selectWorkspace(uid);
|
||||||
|
closeModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const askToDelete = (connection: ConnectionParams) => {
|
||||||
|
selectedConnection.value = connection;
|
||||||
|
isConfirmModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmDeleteConnection = () => {
|
||||||
|
if (selectedWorkspace.value === selectedConnection.value.uid)
|
||||||
|
selectWorkspace(null);
|
||||||
|
deleteConnection(selectedConnection.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onKey = (e: KeyboardEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
if ((e.target as HTMLInputElement).tagName === 'INPUT' && searchTerm.value.length > 0)
|
||||||
|
searchTerm.value = '';
|
||||||
|
else
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('keydown', onKey);
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('keydown', onKey);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.vscroll {
|
||||||
|
height: 1000px;
|
||||||
|
overflow: auto;
|
||||||
|
overflow-anchor: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-resizable {
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
resize: horizontal;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-column-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-icon {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
line-height: 1;
|
||||||
|
margin-left: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
max-width: 75vw;
|
||||||
|
margin-top: 10vh;
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
height: 80vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.connections-search {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connection-block {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all .2s;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
box-shadow: 0 0 3px .1rem rgba($primary-color, 80%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.all-connections-buttons {
|
||||||
|
|
||||||
|
.all-connections-delete,
|
||||||
|
.all-connections-pinned,
|
||||||
|
.all-connections-pin {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-connections-buttons {
|
||||||
|
.all-connections-pinned {
|
||||||
|
opacity: .3;
|
||||||
|
transition: opacity .2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-connections-delete,
|
||||||
|
.all-connections-pin {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -269,8 +269,8 @@ import * as moment from 'moment';
|
|||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { SchemaInfos } from 'common/interfaces/antares';
|
import { ClientCode, SchemaInfos } from 'common/interfaces/antares';
|
||||||
import { ExportOptions, ExportState, TableParams } from 'common/interfaces/exporter';
|
import { ExportOptions, ExportState } from 'common/interfaces/exporter';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import { useFocusTrap } from '@/composables/useFocusTrap';
|
import { useFocusTrap } from '@/composables/useFocusTrap';
|
||||||
@@ -302,11 +302,15 @@ const isExporting = ref(false);
|
|||||||
const isRefreshing = ref(false);
|
const isRefreshing = ref(false);
|
||||||
const progressPercentage = ref(0);
|
const progressPercentage = ref(0);
|
||||||
const progressStatus = ref('');
|
const progressStatus = ref('');
|
||||||
const tables: Ref<TableParams[]> = ref([]);
|
const tables: Ref<{
|
||||||
const options: Ref<ExportOptions> = ref({
|
table: string;
|
||||||
|
includeStructure: boolean;
|
||||||
|
includeContent: boolean;
|
||||||
|
includeDropStatement: boolean;
|
||||||
|
}[]> = ref([]);
|
||||||
|
const options: Ref<Partial<ExportOptions>> = ref({
|
||||||
schema: props.selectedSchema,
|
schema: props.selectedSchema,
|
||||||
includes: {} as {[key: string]: boolean},
|
includes: {} as {[key: string]: boolean},
|
||||||
outputFile: '',
|
|
||||||
outputFormat: 'sql' as 'sql' | 'sql.zip',
|
outputFormat: 'sql' as 'sql' | 'sql.zip',
|
||||||
sqlInsertAfter: 250,
|
sqlInsertAfter: 250,
|
||||||
sqlInsertDivider: 'bytes' as 'bytes' | 'rows'
|
sqlInsertDivider: 'bytes' as 'bytes' | 'rows'
|
||||||
@@ -353,7 +357,7 @@ const startExport = async () => {
|
|||||||
outputFile: dumpFilePath.value,
|
outputFile: dumpFilePath.value,
|
||||||
tables: [...tables.value],
|
tables: [...tables.value],
|
||||||
...options.value
|
...options.value
|
||||||
};
|
} as ExportOptions & { uid: string; type: ClientCode };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { status, response } = await Schema.export(params);
|
const { status, response } = await Schema.export(params);
|
||||||
|
@@ -126,6 +126,19 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group column col-12 mb-0">
|
||||||
|
<div class="col-5 col-sm-12">
|
||||||
|
<label class="form-label">
|
||||||
|
{{ t('message.disableScratchpad') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 col-sm-12">
|
||||||
|
<label class="form-switch d-inline-block" @click.prevent="toggleDisableScratchpad">
|
||||||
|
<input type="checkbox" :checked="disableScratchpad">
|
||||||
|
<i class="form-icon" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group column col-12">
|
<div class="form-group column col-12">
|
||||||
<div class="col-5 col-sm-12">
|
<div class="col-5 col-sm-12">
|
||||||
<label class="form-label">
|
<label class="form-label">
|
||||||
@@ -337,6 +350,7 @@ const {
|
|||||||
notificationsTimeout,
|
notificationsTimeout,
|
||||||
restoreTabs,
|
restoreTabs,
|
||||||
disableBlur,
|
disableBlur,
|
||||||
|
disableScratchpad,
|
||||||
applicationTheme,
|
applicationTheme,
|
||||||
editorTheme,
|
editorTheme,
|
||||||
editorFontSize
|
editorFontSize
|
||||||
@@ -349,6 +363,7 @@ const {
|
|||||||
changePageSize,
|
changePageSize,
|
||||||
changeRestoreTabs,
|
changeRestoreTabs,
|
||||||
changeDisableBlur,
|
changeDisableBlur,
|
||||||
|
changeDisableScratchpad,
|
||||||
changeAutoComplete,
|
changeAutoComplete,
|
||||||
changeLineWrap,
|
changeLineWrap,
|
||||||
changeApplicationTheme,
|
changeApplicationTheme,
|
||||||
@@ -490,6 +505,10 @@ const toggleDisableBlur = () => {
|
|||||||
changeDisableBlur(!disableBlur.value);
|
changeDisableBlur(!disableBlur.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleDisableScratchpad = () => {
|
||||||
|
changeDisableScratchpad(!disableScratchpad.value);
|
||||||
|
};
|
||||||
|
|
||||||
const toggleAutoComplete = () => {
|
const toggleAutoComplete = () => {
|
||||||
changeAutoComplete(!selectedAutoComplete.value);
|
changeAutoComplete(!selectedAutoComplete.value);
|
||||||
};
|
};
|
||||||
|
@@ -47,10 +47,11 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
const cursorPosition = ref(0);
|
const cursorPosition = ref(0);
|
||||||
const fields = ref([]);
|
const lastTableFields = ref([]);
|
||||||
const customCompleter = ref([]);
|
const customCompleter = ref([]);
|
||||||
const id = ref(uidGen());
|
const id = ref(uidGen());
|
||||||
const lastSchema: Ref<string> = ref(null);
|
const lastSchema: Ref<string> = ref(null);
|
||||||
|
const fields: Ref<{name: string; type: string}[]> = ref([]);
|
||||||
|
|
||||||
const tables = computed(() => {
|
const tables = computed(() => {
|
||||||
return props.workspace
|
return props.workspace
|
||||||
@@ -61,13 +62,27 @@ const tables = computed(() => {
|
|||||||
}, []).map(table => {
|
}, []).map(table => {
|
||||||
return {
|
return {
|
||||||
name: table.name as string,
|
name: table.name as string,
|
||||||
type: table.type as string,
|
type: table.type as string
|
||||||
fields: []
|
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tablesInQuery = computed(() => {
|
||||||
|
if (!props.modelValue) return [];
|
||||||
|
const words = props.modelValue
|
||||||
|
.replaceAll(/[.'"`]/g, ' ')
|
||||||
|
.split(' ')
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
const includedTables = tables.value.reduce((acc, curr) => {
|
||||||
|
acc.push(curr.name);
|
||||||
|
return acc;
|
||||||
|
}, [] as string[]).filter((t) => words.includes(t));
|
||||||
|
|
||||||
|
return includedTables;
|
||||||
|
});
|
||||||
|
|
||||||
const triggers = computed(() => {
|
const triggers = computed(() => {
|
||||||
return props.workspace
|
return props.workspace
|
||||||
? props.workspace.structure.filter(schema => schema.name === props.schema)
|
? props.workspace.structure.filter(schema => schema.name === props.schema)
|
||||||
@@ -150,11 +165,11 @@ const lastWord = computed(() => {
|
|||||||
|
|
||||||
const isLastWordATable = computed(() => /\w+\.\w*/gm.test(lastWord.value));
|
const isLastWordATable = computed(() => /\w+\.\w*/gm.test(lastWord.value));
|
||||||
|
|
||||||
const fieldsCompleter = computed(() => {
|
const tableFieldsCompleter = computed(() => {
|
||||||
return {
|
return {
|
||||||
getCompletions: (editor: never, session: never, pos: never, prefix: never, callback: (err: null, response: ace.Ace.Completion[]) => void) => {
|
getCompletions: (editor: never, session: never, pos: never, prefix: never, callback: (err: null, response: ace.Ace.Completion[]) => void) => {
|
||||||
const completions: ace.Ace.Completion[] = [];
|
const completions: ace.Ace.Completion[] = [];
|
||||||
fields.value.forEach(field => {
|
lastTableFields.value.forEach(field => {
|
||||||
completions.push({
|
completions.push({
|
||||||
value: field,
|
value: field,
|
||||||
meta: 'column',
|
meta: 'column',
|
||||||
@@ -175,7 +190,8 @@ const setCustomCompleter = () => {
|
|||||||
...triggers.value,
|
...triggers.value,
|
||||||
...procedures.value,
|
...procedures.value,
|
||||||
...functions.value,
|
...functions.value,
|
||||||
...schedulers.value
|
...schedulers.value,
|
||||||
|
...fields.value
|
||||||
].forEach(el => {
|
].forEach(el => {
|
||||||
completions.push({
|
completions.push({
|
||||||
value: el.name,
|
value: el.name,
|
||||||
@@ -195,6 +211,29 @@ watch(() => props.modelValue, () => {
|
|||||||
cursorPosition.value = (editor.value.session as any).doc.positionToIndex(editor.value.getCursorPosition());
|
cursorPosition.value = (editor.value.session as any).doc.positionToIndex(editor.value.getCursorPosition());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(() => tablesInQuery.value.length, () => {
|
||||||
|
const localFields: {name: string; type: string}[] = [];
|
||||||
|
tablesInQuery.value.forEach(async table => {
|
||||||
|
const params = {
|
||||||
|
uid: props.workspace.uid,
|
||||||
|
schema: props.schema,
|
||||||
|
table: table
|
||||||
|
};
|
||||||
|
|
||||||
|
const { response } = await Tables.getTableColumns(params);
|
||||||
|
|
||||||
|
response.forEach((field: { name: string }) => {
|
||||||
|
localFields.push({
|
||||||
|
name: field.name,
|
||||||
|
type: 'column'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fields.value = localFields;
|
||||||
|
setCustomCompleter();
|
||||||
|
});
|
||||||
|
|
||||||
watch(editorTheme, () => {
|
watch(editorTheme, () => {
|
||||||
if (editor.value)
|
if (editor.value)
|
||||||
editor.value.setTheme(`ace/theme/${editorTheme.value}`);
|
editor.value.setTheme(`ace/theme/${editorTheme.value}`);
|
||||||
@@ -289,8 +328,8 @@ onMounted(() => {
|
|||||||
|
|
||||||
Tables.getTableColumns(params).then(res => {
|
Tables.getTableColumns(params).then(res => {
|
||||||
if (res.response.length)
|
if (res.response.length)
|
||||||
fields.value = res.response.map((field: { name: string }) => field.name);
|
lastTableFields.value = res.response.map((field: { name: string }) => field.name);
|
||||||
editor.value.completers = [fieldsCompleter.value];
|
editor.value.completers = [tableFieldsCompleter.value];
|
||||||
editor.value.execCommand('startAutocomplete');
|
editor.value.execCommand('startAutocomplete');
|
||||||
}).catch(console.log);
|
}).catch(console.log);
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,20 @@
|
|||||||
:context-event="contextEvent"
|
:context-event="contextEvent"
|
||||||
@close-context="$emit('close-context')"
|
@close-context="$emit('close-context')"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-if="isPinned"
|
||||||
|
class="context-element"
|
||||||
|
@click="unpin"
|
||||||
|
>
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-pin-off text-light pr-1" /> {{ $t('word.unpin') }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="context-element"
|
||||||
|
@click="pin"
|
||||||
|
>
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-pin mdi-rotate-45 text-light pr-1" /> {{ $t('word.pin') }}</span>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="isConnected"
|
v-if="isConnected"
|
||||||
class="context-element"
|
class="context-element"
|
||||||
@@ -46,11 +60,18 @@ import BaseContextMenu from '@/components/BaseContextMenu.vue';
|
|||||||
import ConfirmModal from '@/components/BaseConfirmModal.vue';
|
import ConfirmModal from '@/components/BaseConfirmModal.vue';
|
||||||
import { ConnectionParams } from 'common/interfaces/antares';
|
import { ConnectionParams } from 'common/interfaces/antares';
|
||||||
|
|
||||||
|
const connectionsStore = useConnectionsStore();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getConnectionName,
|
getConnectionName,
|
||||||
addConnection,
|
addConnection,
|
||||||
deleteConnection
|
deleteConnection,
|
||||||
} = useConnectionsStore();
|
pinConnection,
|
||||||
|
unpinConnection
|
||||||
|
} = connectionsStore;
|
||||||
|
|
||||||
|
const { pinnedConnections } = storeToRefs(connectionsStore);
|
||||||
|
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||||
|
|
||||||
@@ -71,6 +92,7 @@ const isConfirmModal = ref(false);
|
|||||||
|
|
||||||
const connectionName = computed(() => getConnectionName(props.contextConnection.uid));
|
const connectionName = computed(() => getConnectionName(props.contextConnection.uid));
|
||||||
const isConnected = computed(() => getWorkspace(props.contextConnection.uid).connectionStatus === 'connected');
|
const isConnected = computed(() => getWorkspace(props.contextConnection.uid).connectionStatus === 'connected');
|
||||||
|
const isPinned = computed(() => pinnedConnections.value.has(props.contextConnection.uid));
|
||||||
|
|
||||||
const confirmDeleteConnection = () => {
|
const confirmDeleteConnection = () => {
|
||||||
if (selectedWorkspace.value === props.contextConnection.uid)
|
if (selectedWorkspace.value === props.contextConnection.uid)
|
||||||
@@ -100,6 +122,16 @@ const hideConfirmModal = () => {
|
|||||||
closeContext();
|
closeContext();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pin = () => {
|
||||||
|
pinConnection(props.contextConnection.uid);
|
||||||
|
closeContext();
|
||||||
|
};
|
||||||
|
|
||||||
|
const unpin = () => {
|
||||||
|
unpinConnection(props.contextConnection.uid);
|
||||||
|
closeContext();
|
||||||
|
};
|
||||||
|
|
||||||
const disconnect = () => {
|
const disconnect = () => {
|
||||||
disconnectWorkspace(props.contextConnection.uid);
|
disconnectWorkspace(props.contextConnection.uid);
|
||||||
closeContext();
|
closeContext();
|
||||||
|
@@ -11,14 +11,30 @@
|
|||||||
|
|
||||||
<div class="footer-right-elements">
|
<div class="footer-right-elements">
|
||||||
<ul class="footer-elements">
|
<ul class="footer-elements">
|
||||||
|
<li
|
||||||
|
v-if="workspace.connectionStatus === 'connected' "
|
||||||
|
class="footer-element footer-link"
|
||||||
|
@click="toggleConsole()"
|
||||||
|
>
|
||||||
|
<i class="mdi mdi-18px mdi-console-line mr-1" />
|
||||||
|
<small>{{ t('word.console') }}</small>
|
||||||
|
</li>
|
||||||
<li class="footer-element footer-link" @click="openOutside('https://www.paypal.com/paypalme/fabiodistasio')">
|
<li class="footer-element footer-link" @click="openOutside('https://www.paypal.com/paypalme/fabiodistasio')">
|
||||||
<i class="mdi mdi-18px mdi-coffee mr-1" />
|
<i class="mdi mdi-18px mdi-coffee mr-1" />
|
||||||
<small>{{ $t('word.donate') }}</small>
|
<small>{{ t('word.donate') }}</small>
|
||||||
</li>
|
</li>
|
||||||
<li class="footer-element footer-link" @click="openOutside('https://github.com/antares-sql/antares/issues')">
|
<li
|
||||||
|
class="footer-element footer-link"
|
||||||
|
:title="t('message.reportABug')"
|
||||||
|
@click="openOutside('https://github.com/antares-sql/antares/issues')"
|
||||||
|
>
|
||||||
<i class="mdi mdi-18px mdi-bug" />
|
<i class="mdi mdi-18px mdi-bug" />
|
||||||
</li>
|
</li>
|
||||||
<li class="footer-element footer-link" @click="showSettingModal('about')">
|
<li
|
||||||
|
class="footer-element footer-link"
|
||||||
|
:title="t('word.about')"
|
||||||
|
@click="showSettingModal('about')"
|
||||||
|
>
|
||||||
<i class="mdi mdi-18px mdi-information-outline" />
|
<i class="mdi mdi-18px mdi-information-outline" />
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -29,9 +45,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { shell } from 'electron';
|
import { shell } from 'electron';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useApplicationStore } from '@/stores/application';
|
import { useApplicationStore } from '@/stores/application';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import { computed, ComputedRef } from 'vue';
|
import { computed, ComputedRef } from 'vue';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
interface DatabaseInfos {// TODO: temp
|
interface DatabaseInfos {// TODO: temp
|
||||||
name: string;
|
name: string;
|
||||||
@@ -43,13 +63,15 @@ interface DatabaseInfos {// TODO: temp
|
|||||||
const applicationStore = useApplicationStore();
|
const applicationStore = useApplicationStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
|
||||||
const { getSelected: workspace } = storeToRefs(workspacesStore);
|
const { getSelected: workspaceUid } = storeToRefs(workspacesStore);
|
||||||
|
const { toggleConsole } = useConsoleStore();
|
||||||
|
|
||||||
const { showSettingModal } = applicationStore;
|
const { showSettingModal } = applicationStore;
|
||||||
const { getWorkspace } = workspacesStore;
|
const { getWorkspace } = workspacesStore;
|
||||||
|
|
||||||
|
const workspace = computed(() => getWorkspace(workspaceUid.value));
|
||||||
const version: ComputedRef<DatabaseInfos> = computed(() => {
|
const version: ComputedRef<DatabaseInfos> = computed(() => {
|
||||||
return getWorkspace(workspace.value) ? getWorkspace(workspace.value).version : null;
|
return getWorkspace(workspaceUid.value) ? workspace.value.version : null;
|
||||||
});
|
});
|
||||||
|
|
||||||
const versionString = computed(() => {
|
const versionString = computed(() => {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="settingbar">
|
<div id="settingbar">
|
||||||
<div class="settingbar-top-elements">
|
<div ref="sidebarConnections" class="settingbar-top-elements">
|
||||||
<SettingBarContext
|
<SettingBarContext
|
||||||
v-if="isContext"
|
v-if="isContext"
|
||||||
:context-event="contextEvent"
|
:context-event="contextEvent"
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
/>
|
/>
|
||||||
<ul class="settingbar-elements">
|
<ul class="settingbar-elements">
|
||||||
<Draggable
|
<Draggable
|
||||||
v-model="connections"
|
v-model="pinnedConnectionsArr"
|
||||||
:item-key="'uid'"
|
:item-key="'uid'"
|
||||||
@start="isDragging = true"
|
@start="isDragging = true"
|
||||||
@end="dragStop"
|
@end="dragStop"
|
||||||
@@ -23,11 +23,40 @@
|
|||||||
@contextmenu.prevent="contextMenu($event, element)"
|
@contextmenu.prevent="contextMenu($event, element)"
|
||||||
@mouseover.self="tooltipPosition"
|
@mouseover.self="tooltipPosition"
|
||||||
>
|
>
|
||||||
<i class="settingbar-element-icon dbi" :class="`dbi-${element.client} ${getStatusBadge(element.uid)}`" />
|
<i class="settingbar-element-icon dbi" :class="[`dbi-${element.client}`, getStatusBadge(element.uid), (pinnedConnections.has(element.uid) ? 'settingbar-element-pin' : false)]" />
|
||||||
<span v-if="!isDragging" class="ex-tooltip-content">{{ getConnectionName(element.uid) }}</span>
|
<span v-if="!isDragging && !isScrolling" class="ex-tooltip-content">{{ getConnectionName(element.uid) }}</span>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
</Draggable>
|
</Draggable>
|
||||||
|
|
||||||
|
<div v-if="pinnedConnectionsArr.length" class="divider" />
|
||||||
|
|
||||||
|
<li
|
||||||
|
v-for="connection in unpinnedConnectionsArr"
|
||||||
|
:key="connection.uid"
|
||||||
|
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 && !isScrolling" class="ex-tooltip-content">{{ getConnectionName(connection.uid) }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settingbar-middle-elements">
|
||||||
|
<ul class="settingbar-elements">
|
||||||
|
<li
|
||||||
|
v-if="isScrollable"
|
||||||
|
class="settingbar-element btn btn-link ex-tooltip"
|
||||||
|
@click="emit('show-connections-modal')"
|
||||||
|
@mouseover.self="tooltipPosition"
|
||||||
|
>
|
||||||
|
<i class="settingbar-element-icon mdi mdi-24px mdi-dots-horizontal text-light" />
|
||||||
|
<span class="ex-tooltip-content">{{ $t('message.allConnections') }} (Shift+CTRL+Space)</span>
|
||||||
|
</li>
|
||||||
<li
|
<li
|
||||||
class="settingbar-element btn btn-link ex-tooltip"
|
class="settingbar-element btn btn-link ex-tooltip"
|
||||||
:class="{'selected': 'NEW' === selectedWorkspace}"
|
:class="{'selected': 'NEW' === selectedWorkspace}"
|
||||||
@@ -42,7 +71,11 @@
|
|||||||
|
|
||||||
<div class="settingbar-bottom-elements">
|
<div class="settingbar-bottom-elements">
|
||||||
<ul class="settingbar-elements">
|
<ul class="settingbar-elements">
|
||||||
<li class="settingbar-element btn btn-link ex-tooltip" @click="showScratchpad">
|
<li
|
||||||
|
v-if="!disableScratchpad"
|
||||||
|
class="settingbar-element btn btn-link ex-tooltip"
|
||||||
|
@click="showScratchpad"
|
||||||
|
>
|
||||||
<i class="settingbar-element-icon mdi mdi-24px mdi-notebook-edit-outline text-light" />
|
<i class="settingbar-element-icon mdi mdi-24px mdi-notebook-edit-outline text-light" />
|
||||||
<span class="ex-tooltip-content">{{ $t('word.scratchpad') }}</span>
|
<span class="ex-tooltip-content">{{ $t('word.scratchpad') }}</span>
|
||||||
</li>
|
</li>
|
||||||
@@ -56,42 +89,70 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, Ref, computed } from 'vue';
|
import { ref, Ref, computed, watch } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useApplicationStore } from '@/stores/application';
|
import { useApplicationStore } from '@/stores/application';
|
||||||
import { useConnectionsStore } from '@/stores/connections';
|
import { useConnectionsStore } from '@/stores/connections';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
|
import { useSettingsStore } from '@/stores/settings';
|
||||||
import * as Draggable from 'vuedraggable';
|
import * as Draggable from 'vuedraggable';
|
||||||
import SettingBarContext from '@/components/SettingBarContext.vue';
|
import SettingBarContext from '@/components/SettingBarContext.vue';
|
||||||
import { ConnectionParams } from 'common/interfaces/antares';
|
import { ConnectionParams } from 'common/interfaces/antares';
|
||||||
|
import { useElementBounding, useScroll } from '@vueuse/core';
|
||||||
|
|
||||||
const applicationStore = useApplicationStore();
|
const applicationStore = useApplicationStore();
|
||||||
const connectionsStore = useConnectionsStore();
|
const connectionsStore = useConnectionsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
const { updateStatus } = storeToRefs(applicationStore);
|
const { updateStatus } = storeToRefs(applicationStore);
|
||||||
const { connections: getConnections } = storeToRefs(connectionsStore);
|
const { connections: storedConnections, pinnedConnections, lastConnections } = storeToRefs(connectionsStore);
|
||||||
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
||||||
|
const { disableScratchpad } = storeToRefs(settingsStore);
|
||||||
|
|
||||||
const { showSettingModal, showScratchpad } = applicationStore;
|
const { showSettingModal, showScratchpad } = applicationStore;
|
||||||
const { getConnectionName, updateConnections } = connectionsStore;
|
const { getConnectionName, updatePinnedConnections } = connectionsStore;
|
||||||
const { getWorkspace, selectWorkspace } = workspacesStore;
|
const { getWorkspace, selectWorkspace } = workspacesStore;
|
||||||
|
|
||||||
|
const emit = defineEmits(['show-connections-modal']);
|
||||||
|
|
||||||
const isLinux = process.platform === 'linux';
|
const isLinux = process.platform === 'linux';
|
||||||
|
|
||||||
|
const sidebarConnections: Ref<HTMLDivElement> = ref(null);
|
||||||
const isContext: Ref<boolean> = ref(false);
|
const isContext: Ref<boolean> = ref(false);
|
||||||
const isDragging: Ref<boolean> = ref(false);
|
const isDragging: Ref<boolean> = ref(false);
|
||||||
|
const isScrollable: Ref<boolean> = ref(false);
|
||||||
|
const isScrolling = ref(useScroll(sidebarConnections)?.isScrolling);
|
||||||
const contextEvent: Ref<MouseEvent> = ref(null);
|
const contextEvent: Ref<MouseEvent> = ref(null);
|
||||||
const contextConnection: Ref<ConnectionParams> = ref(null);
|
const contextConnection: Ref<ConnectionParams> = ref(null);
|
||||||
|
const sidebarConnectionsHeight = ref(useElementBounding(sidebarConnections)?.height);
|
||||||
|
|
||||||
const connections = computed({
|
const pinnedConnectionsArr = computed({
|
||||||
get () {
|
get: () => [...pinnedConnections.value].map(c => storedConnections.value.find(sc => sc.uid === c)).filter(Boolean),
|
||||||
return getConnections.value;
|
set: (value: ConnectionParams[]) => {
|
||||||
},
|
const pinnedUid = value.reduce((acc, curr) => {
|
||||||
set (value: ConnectionParams[]) {
|
acc.push(curr.uid);
|
||||||
updateConnections(value);
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
updatePinnedConnections(pinnedUid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const unpinnedConnectionsArr = computed(() => {
|
||||||
|
return storedConnections.value
|
||||||
|
.filter(c => !pinnedConnections.value.has(c.uid))
|
||||||
|
.map(c => {
|
||||||
|
const connTime = lastConnections.value.find((lc) => lc.uid === c.uid)?.time || 0;
|
||||||
|
return { ...c, time: connTime };
|
||||||
|
})
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.time < b.time) return 1;
|
||||||
|
else if (a.time > b.time) return -1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const hasUpdates = computed(() => ['available', 'downloading', 'downloaded', 'link'].includes(updateStatus.value));
|
const hasUpdates = computed(() => ['available', 'downloading', 'downloaded', 'link'].includes(updateStatus.value));
|
||||||
|
|
||||||
const contextMenu = (event: MouseEvent, connection: ConnectionParams) => {
|
const contextMenu = (event: MouseEvent, connection: ConnectionParams) => {
|
||||||
@@ -101,11 +162,14 @@ const contextMenu = (event: MouseEvent, connection: ConnectionParams) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const tooltipPosition = (e: Event) => {
|
const tooltipPosition = (e: Event) => {
|
||||||
const el = e.target ? e.target : e;
|
const el = (e.target ? e.target : e) as unknown as HTMLElement;
|
||||||
|
const tooltip = el.querySelector<HTMLElement>('.ex-tooltip-content');
|
||||||
|
if (tooltip) {
|
||||||
const fromTop = isLinux
|
const fromTop = isLinux
|
||||||
? window.scrollY + (el as HTMLElement).getBoundingClientRect().top + ((el as HTMLElement).offsetHeight / 4)
|
? window.scrollY + el.getBoundingClientRect().top + (el.offsetHeight / 4)
|
||||||
: window.scrollY + (el as HTMLElement).getBoundingClientRect().top - ((el as HTMLElement).offsetHeight / 4);
|
: window.scrollY + el.getBoundingClientRect().top - (el.offsetHeight / 4);
|
||||||
(el as HTMLElement).querySelector<HTMLElement>('.ex-tooltip-content').style.top = `${fromTop}px`;
|
tooltip.style.top = `${fromTop}px`;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStatusBadge = (uid: string) => {
|
const getStatusBadge = (uid: string) => {
|
||||||
@@ -126,13 +190,50 @@ const getStatusBadge = (uid: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const dragStop = (e: any) => { // TODO: temp
|
const dragStop = (e: any) => {
|
||||||
isDragging.value = false;
|
isDragging.value = false;
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
tooltipPosition(e.originalEvent.target.parentNode);
|
tooltipPosition(e.originalEvent.target.parentNode);
|
||||||
}, 200);
|
}, 200);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(sidebarConnectionsHeight, (value) => {
|
||||||
|
isScrollable.value = value < sidebarConnections.value.scrollHeight;
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(unpinnedConnectionsArr, (newVal, oldVal) => {
|
||||||
|
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const element = document.querySelector<HTMLElement>('.settingbar-element.selected');
|
||||||
|
if (element) {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
const elemTop = rect.top;
|
||||||
|
const elemBottom = rect.bottom;
|
||||||
|
const isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
element.setAttribute('tabindex', '-1');
|
||||||
|
element.focus();
|
||||||
|
element.removeAttribute('tabindex');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(selectedWorkspace, (newVal, oldVal) => {
|
||||||
|
if (newVal !== oldVal) {
|
||||||
|
setTimeout(() => {
|
||||||
|
const element = document.querySelector<HTMLElement>('.settingbar-element.selected');
|
||||||
|
if (element) {
|
||||||
|
element.setAttribute('tabindex', '-1');
|
||||||
|
element.focus();
|
||||||
|
element.removeAttribute('tabindex');
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -141,7 +242,7 @@ const dragStop = (e: any) => { // TODO: temp
|
|||||||
height: calc(100vh - #{$excluding-size});
|
height: calc(100vh - #{$excluding-size});
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
// justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
@@ -149,7 +250,7 @@ const dragStop = (e: any) => { // TODO: temp
|
|||||||
.settingbar-top-elements {
|
.settingbar-top-elements {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: overlay;
|
overflow-y: overlay;
|
||||||
max-height: calc((100vh - 3.5rem) - #{$excluding-size});
|
// max-height: calc((100vh - 3.5rem) - #{$excluding-size});
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&::-webkit-scrollbar {
|
||||||
width: 3px;
|
width: 3px;
|
||||||
@@ -157,8 +258,8 @@ const dragStop = (e: any) => { // TODO: temp
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settingbar-bottom-elements {
|
.settingbar-bottom-elements {
|
||||||
padding-top: 0.5rem;
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
margin-top: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settingbar-elements {
|
.settingbar-elements {
|
||||||
@@ -214,6 +315,21 @@ const dragStop = (e: any) => { // TODO: temp
|
|||||||
bottom: initial;
|
bottom: initial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settingbar-element-pin{
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
font: normal normal normal 14px/1 "Material Design Icons";
|
||||||
|
content: "\F0403";
|
||||||
|
color: $body-font-color-dark;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
opacity: .25;
|
||||||
|
bottom: -8px;
|
||||||
|
left: -4px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -279,6 +279,12 @@
|
|||||||
<span>{{ $t('message.processesList') }}</span>
|
<span>{{ $t('message.processesList') }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="menu-item">
|
||||||
|
<a class="c-hand p-vcentered" @click="toggleConsole">
|
||||||
|
<i class="mdi mdi-console-line mr-1 tool-icon" />
|
||||||
|
<span>{{ $t('word.console') }}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li
|
<li
|
||||||
v-if="workspace.customizations.variables"
|
v-if="workspace.customizations.variables"
|
||||||
class="menu-item"
|
class="menu-item"
|
||||||
@@ -451,8 +457,9 @@
|
|||||||
:schema="tab.schema"
|
:schema="tab.schema"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
<WorkspaceQueryConsole v-if="isConsoleOpen(workspace.uid)" :uid="workspace.uid" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="connection-panel-wrapper">
|
<div v-else class="connection-panel-wrapper p-relative">
|
||||||
<WorkspaceEditConnectionPanel :connection="connection" />
|
<WorkspaceEditConnectionPanel :connection="connection" />
|
||||||
</div>
|
</div>
|
||||||
<ModalProcessesList
|
<ModalProcessesList
|
||||||
@@ -470,11 +477,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onBeforeUnmount, Prop, ref, watch } from 'vue';
|
import { ipcRenderer } from 'electron';
|
||||||
|
import { computed, onMounted, Prop, ref, watch } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import * as Draggable from 'vuedraggable';
|
import * as Draggable from 'vuedraggable';
|
||||||
import Connection from '@/ipc-api/Connection';
|
import Connection from '@/ipc-api/Connection';
|
||||||
import { useWorkspacesStore, WorkspaceTab } from '@/stores/workspaces';
|
import { useWorkspacesStore, WorkspaceTab } from '@/stores/workspaces';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { ConnectionParams } from 'common/interfaces/antares';
|
import { ConnectionParams } from 'common/interfaces/antares';
|
||||||
|
|
||||||
import WorkspaceEmptyState from '@/components/WorkspaceEmptyState.vue';
|
import WorkspaceEmptyState from '@/components/WorkspaceEmptyState.vue';
|
||||||
@@ -482,6 +491,7 @@ import WorkspaceExploreBar from '@/components/WorkspaceExploreBar.vue';
|
|||||||
import WorkspaceEditConnectionPanel from '@/components/WorkspaceEditConnectionPanel.vue';
|
import WorkspaceEditConnectionPanel from '@/components/WorkspaceEditConnectionPanel.vue';
|
||||||
import WorkspaceTabQuery from '@/components/WorkspaceTabQuery.vue';
|
import WorkspaceTabQuery from '@/components/WorkspaceTabQuery.vue';
|
||||||
import WorkspaceTabTable from '@/components/WorkspaceTabTable.vue';
|
import WorkspaceTabTable from '@/components/WorkspaceTabTable.vue';
|
||||||
|
import WorkspaceQueryConsole from '@/components/WorkspaceQueryConsole.vue';
|
||||||
|
|
||||||
import WorkspaceTabNewTable from '@/components/WorkspaceTabNewTable.vue';
|
import WorkspaceTabNewTable from '@/components/WorkspaceTabNewTable.vue';
|
||||||
import WorkspaceTabNewView from '@/components/WorkspaceTabNewView.vue';
|
import WorkspaceTabNewView from '@/components/WorkspaceTabNewView.vue';
|
||||||
@@ -512,9 +522,16 @@ const {
|
|||||||
selectTab,
|
selectTab,
|
||||||
newTab,
|
newTab,
|
||||||
removeTab,
|
removeTab,
|
||||||
updateTabs
|
updateTabs,
|
||||||
|
selectNextTab,
|
||||||
|
selectPrevTab
|
||||||
} = workspacesStore;
|
} = workspacesStore;
|
||||||
|
|
||||||
|
const consoleStore = useConsoleStore();
|
||||||
|
|
||||||
|
const { isConsoleOpen } = storeToRefs(consoleStore);
|
||||||
|
const { toggleConsole } = consoleStore;
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
connection: Object as Prop<ConnectionParams>
|
connection: Object as Prop<ConnectionParams>
|
||||||
});
|
});
|
||||||
@@ -566,30 +583,13 @@ watch(queryTabs, (newVal, oldVal) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const addQueryTab = () => {
|
const addQueryTab = () => {
|
||||||
newTab({ uid: props.connection.uid, type: 'query' });
|
newTab({ uid: props.connection.uid, type: 'query', schema: workspace.value.breadcrumbs.schema });
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSelectedTab = () => {
|
const getSelectedTab = () => {
|
||||||
return workspace.value.tabs.find(tab => tab.uid === selectedTab.value);
|
return workspace.value.tabs.find(tab => tab.uid === selectedTab.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onKey = (e: KeyboardEvent) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
if (!isSelected.value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((e.ctrlKey || e.metaKey) && e.key === 't' && !e.altKey) { // CTRL|Command + t
|
|
||||||
addQueryTab();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((e.ctrlKey || e.metaKey) && e.key === 'w' && !e.altKey) { // CTRL|Command + w
|
|
||||||
const currentTab = getSelectedTab();
|
|
||||||
if (currentTab)
|
|
||||||
closeTab(currentTab);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const openAsPermanentTab = (tab: WorkspaceTab) => {
|
const openAsPermanentTab = (tab: WorkspaceTab) => {
|
||||||
const permanentTabs = {
|
const permanentTabs = {
|
||||||
table: 'data',
|
table: 'data',
|
||||||
@@ -649,15 +649,42 @@ const cutText = (string: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
window.addEventListener('keydown', onKey);
|
|
||||||
await addWorkspace(props.connection.uid);
|
await addWorkspace(props.connection.uid);
|
||||||
const isInitiated = await Connection.checkConnection(props.connection.uid);
|
const isInitiated = await Connection.checkConnection(props.connection.uid);
|
||||||
if (isInitiated)
|
if (isInitiated)
|
||||||
connectWorkspace(props.connection);
|
connectWorkspace(props.connection);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onMounted(() => {
|
||||||
window.removeEventListener('keydown', onKey);
|
ipcRenderer.on('open-new-tab', () => {
|
||||||
|
if (!isSelected.value) return;
|
||||||
|
addQueryTab();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('close-tab', () => {
|
||||||
|
if (!isSelected.value) return;
|
||||||
|
const currentTab = getSelectedTab();
|
||||||
|
if (currentTab)
|
||||||
|
closeTab(currentTab);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('next-tab', () => {
|
||||||
|
if (!isSelected.value) return;
|
||||||
|
selectNextTab({ uid: props.connection.uid });
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('prev-tab', () => {
|
||||||
|
if (!isSelected.value) return;
|
||||||
|
selectPrevTab({ uid: props.connection.uid });
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 1; i <= 9; i++) {
|
||||||
|
ipcRenderer.on(`select-tab-${i}`, () => {
|
||||||
|
if (!isSelected.value) return;
|
||||||
|
if (workspace.value.tabs[i-1])
|
||||||
|
selectTab({ uid: props.connection.uid, tab: workspace.value.tabs[i-1].uid });
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -667,8 +694,9 @@ onBeforeUnmount(() => {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
.workspace-tabs {
|
.workspace-tabs {
|
||||||
overflow: hidden;
|
overflow-y: hidden;
|
||||||
height: calc(100vh - #{$excluding-size});
|
height: calc(100vh - #{$excluding-size});
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.tab-block {
|
.tab-block {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
@@ -411,12 +411,12 @@ const workspacesStore = useWorkspacesStore();
|
|||||||
|
|
||||||
const { connectWorkspace, selectWorkspace } = workspacesStore;
|
const { connectWorkspace, selectWorkspace } = workspacesStore;
|
||||||
|
|
||||||
const clients = ref([
|
const clients = [
|
||||||
{ name: 'MySQL', slug: 'mysql' },
|
{ name: 'MySQL', slug: 'mysql' },
|
||||||
{ name: 'MariaDB', slug: 'maria' },
|
{ name: 'MariaDB', slug: 'maria' },
|
||||||
{ name: 'PostgreSQL', slug: 'pg' },
|
{ name: 'PostgreSQL', slug: 'pg' },
|
||||||
{ name: 'SQLite', slug: 'sqlite' }
|
{ name: 'SQLite', slug: 'sqlite' }
|
||||||
]);
|
];
|
||||||
|
|
||||||
const connection = ref({
|
const connection = ref({
|
||||||
name: '',
|
name: '',
|
||||||
|
@@ -253,6 +253,14 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group columns">
|
||||||
|
<div class="column col-4 col-sm-12" />
|
||||||
|
<div class="column col-8 col-sm-12">
|
||||||
|
<label class="form-checkbox form-inline">
|
||||||
|
<input v-model="localConnection.untrustedConnection" type="checkbox"><i class="form-icon" /> {{ t('message.untrustedConnection') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -416,12 +424,12 @@ const { editConnection } = useConnectionsStore();
|
|||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const { connectWorkspace } = useWorkspacesStore();
|
const { connectWorkspace } = useWorkspacesStore();
|
||||||
|
|
||||||
const clients = ref([
|
const clients = [
|
||||||
{ name: 'MySQL', slug: 'mysql' },
|
{ name: 'MySQL', slug: 'mysql' },
|
||||||
{ name: 'MariaDB', slug: 'maria' },
|
{ name: 'MariaDB', slug: 'maria' },
|
||||||
{ name: 'PostgreSQL', slug: 'pg' },
|
{ name: 'PostgreSQL', slug: 'pg' },
|
||||||
{ name: 'SQLite', slug: 'sqlite' }
|
{ name: 'SQLite', slug: 'sqlite' }
|
||||||
]);
|
];
|
||||||
|
|
||||||
const firstInput: Ref<HTMLInputElement> = ref(null);
|
const firstInput: Ref<HTMLInputElement> = ref(null);
|
||||||
const localConnection: Ref<ConnectionParams & { pgConnString: string }> = ref(null);
|
const localConnection: Ref<ConnectionParams & { pgConnString: string }> = ref(null);
|
||||||
@@ -543,7 +551,8 @@ localConnection.value = JSON.parse(JSON.stringify(props.connection));
|
|||||||
.connection-panel {
|
.connection-panel {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: .5rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
min-width: 450px;
|
min-width: 450px;
|
||||||
|
@@ -235,17 +235,7 @@ const refresh = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const explorebarSearch = (e: KeyboardEvent) => {
|
const explorebarSearch = () => {
|
||||||
if (e.code === 'Backspace') {
|
|
||||||
e.preventDefault();
|
|
||||||
if (searchTerm.value.length)
|
|
||||||
searchTerm.value = searchTerm.value.slice(0, -1);
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (e.key.length > 1)// Prevent non-alphanumerics
|
|
||||||
return;
|
|
||||||
|
|
||||||
searchInput.value.focus();
|
searchInput.value.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -580,7 +580,7 @@ defineExpose({ selectSchema, schemaAccordion });
|
|||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 0.8;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
|
177
src/renderer/components/WorkspaceQueryConsole.vue
Normal file
177
src/renderer/components/WorkspaceQueryConsole.vue
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
ref="wrapper"
|
||||||
|
class="query-console-wrapper"
|
||||||
|
@mouseenter="isHover = true"
|
||||||
|
@mouseleave="isHover = false"
|
||||||
|
>
|
||||||
|
<div ref="resizer" class="query-console-resizer" />
|
||||||
|
<div
|
||||||
|
id="query-console"
|
||||||
|
ref="queryConsole"
|
||||||
|
class="query-console column col-12"
|
||||||
|
:style="{height: localHeight ? localHeight+'px' : ''}"
|
||||||
|
>
|
||||||
|
<div class="query-console-header">
|
||||||
|
<div>{{ t('word.console') }}</div>
|
||||||
|
<button class="btn btn-clear mr-1" @click="resizeConsole(0)" />
|
||||||
|
</div>
|
||||||
|
<div ref="queryConsoleBody" class="query-console-body">
|
||||||
|
<div
|
||||||
|
v-for="(wLog, i) in workspaceLogs"
|
||||||
|
:key="i"
|
||||||
|
class="query-console-log"
|
||||||
|
tabindex="0"
|
||||||
|
@contextmenu.prevent="contextMenu($event, wLog)"
|
||||||
|
>
|
||||||
|
<span class="type-datetime">{{ moment(wLog.date).format('HH:mm:ss') }}</span>: <code class="query-console-log-sql">{{ wLog.sql }}</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<BaseContextMenu
|
||||||
|
v-if="isContext"
|
||||||
|
:context-event="contextEvent"
|
||||||
|
@close-context="isContext = false"
|
||||||
|
>
|
||||||
|
<div class="context-element" @click="copyQuery">
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-content-copy text-light pr-1" /> {{ $t('word.copy') }}</span>
|
||||||
|
</div>
|
||||||
|
</BaseContextMenu>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, nextTick, onMounted, ref, Ref, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import BaseContextMenu from '@/components/BaseContextMenu.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const consoleStore = useConsoleStore();
|
||||||
|
|
||||||
|
const { resizeConsole, getLogsByWorkspace } = consoleStore;
|
||||||
|
const { consoleHeight } = storeToRefs(consoleStore);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
uid: String
|
||||||
|
});
|
||||||
|
|
||||||
|
const wrapper: Ref<HTMLInputElement> = ref(null);
|
||||||
|
const queryConsole: Ref<HTMLInputElement> = ref(null);
|
||||||
|
const queryConsoleBody: Ref<HTMLInputElement> = ref(null);
|
||||||
|
const resizer: Ref<HTMLInputElement> = ref(null);
|
||||||
|
const localHeight = ref(250);
|
||||||
|
const isHover = ref(false);
|
||||||
|
const isContext = ref(false);
|
||||||
|
const contextQuery: Ref<string> = ref(null);
|
||||||
|
const contextEvent: Ref<MouseEvent> = ref(null);
|
||||||
|
|
||||||
|
const resize = (e: MouseEvent) => {
|
||||||
|
const el = queryConsole.value;
|
||||||
|
let consoleHeight = el.getBoundingClientRect().bottom - e.pageY;
|
||||||
|
if (consoleHeight > 400) consoleHeight = 400;
|
||||||
|
localHeight.value = consoleHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
const workspaceLogs = computed(() => {
|
||||||
|
return getLogsByWorkspace(props.uid);
|
||||||
|
});
|
||||||
|
|
||||||
|
const stopResize = () => {
|
||||||
|
if (localHeight.value < 0) localHeight.value = 0;
|
||||||
|
resizeConsole(localHeight.value);
|
||||||
|
window.removeEventListener('mousemove', resize);
|
||||||
|
window.removeEventListener('mouseup', stopResize);
|
||||||
|
};
|
||||||
|
|
||||||
|
const contextMenu = (event: MouseEvent, wLog: {date: Date; sql: string}) => {
|
||||||
|
contextEvent.value = event;
|
||||||
|
contextQuery.value = wLog.sql;
|
||||||
|
isContext.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const copyQuery = () => {
|
||||||
|
navigator.clipboard.writeText(contextQuery.value);
|
||||||
|
isContext.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(workspaceLogs, async () => {
|
||||||
|
if (!isHover.value) {
|
||||||
|
await nextTick();
|
||||||
|
queryConsoleBody.value.scrollTop = queryConsoleBody.value.scrollHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
localHeight.value = consoleHeight.value;
|
||||||
|
queryConsoleBody.value.scrollTop = queryConsoleBody.value.scrollHeight;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
resizer.value.addEventListener('mousedown', (e: MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
window.addEventListener('mousemove', resize);
|
||||||
|
window.addEventListener('mouseup', stopResize);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.query-console-wrapper{
|
||||||
|
width: 100%;
|
||||||
|
z-index: 9;
|
||||||
|
margin-top: auto;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
.query-console-resizer{
|
||||||
|
height: 4px;
|
||||||
|
top: -1px;
|
||||||
|
width: 100%;
|
||||||
|
cursor: ns-resize;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 99;
|
||||||
|
transition: background 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba($primary-color, 50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-console {
|
||||||
|
padding: 0;
|
||||||
|
padding-bottom: $footer-height;
|
||||||
|
.query-console-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-console-body {
|
||||||
|
overflow: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 100%;
|
||||||
|
padding: 0 6px 3px;
|
||||||
|
|
||||||
|
.query-console-log {
|
||||||
|
padding: 1px 3px;
|
||||||
|
margin: 1px 0;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
|
||||||
|
.query-console-log-sql {
|
||||||
|
font-size: 95%;
|
||||||
|
opacity: .8;
|
||||||
|
font-weight: 700;
|
||||||
|
user-select: text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
@@ -179,6 +179,8 @@
|
|||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import Functions from '@/ipc-api/Functions';
|
import Functions from '@/ipc-api/Functions';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import BaseLoader from '@/components/BaseLoader.vue';
|
import BaseLoader from '@/components/BaseLoader.vue';
|
||||||
@@ -200,6 +202,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -274,8 +277,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -311,6 +318,10 @@ watch(isChanged, (val) => {
|
|||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
originalFunction.value = {
|
originalFunction.value = {
|
||||||
sql: customizations.value.functionSql,
|
sql: customizations.value.functionSql,
|
||||||
language: customizations.value.languages ? customizations.value.languages[0] : null,
|
language: customizations.value.languages ? customizations.value.languages[0] : null,
|
||||||
|
@@ -151,6 +151,8 @@
|
|||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import Routines from '@/ipc-api/Routines';
|
import Routines from '@/ipc-api/Routines';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import QueryEditor from '@/components/QueryEditor.vue';
|
import QueryEditor from '@/components/QueryEditor.vue';
|
||||||
@@ -169,6 +171,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -243,8 +246,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -280,6 +287,10 @@ watch(isChanged, (val) => {
|
|||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
originalRoutine.value = {
|
originalRoutine.value = {
|
||||||
sql: customizations.value.functionSql,
|
sql: customizations.value.functionSql,
|
||||||
language: customizations.value.languages ? customizations.value.languages[0] : null,
|
language: customizations.value.languages ? customizations.value.languages[0] : null,
|
||||||
|
@@ -125,10 +125,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Prop, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import { EventInfos } from 'common/interfaces/antares';
|
import { ConnectionParams, EventInfos } from 'common/interfaces/antares';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import BaseLoader from '@/components/BaseLoader.vue';
|
import BaseLoader from '@/components/BaseLoader.vue';
|
||||||
@@ -141,7 +143,7 @@ const { t } = useI18n();
|
|||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
tabUid: String,
|
tabUid: String,
|
||||||
connection: Object,
|
connection: Object as Prop<ConnectionParams>,
|
||||||
tab: Object,
|
tab: Object,
|
||||||
isSelected: Boolean,
|
isSelected: Boolean,
|
||||||
schema: String
|
schema: String
|
||||||
@@ -149,6 +151,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -233,8 +236,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -270,6 +277,10 @@ watch(isChanged, (val) => {
|
|||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
originalScheduler.value = {
|
originalScheduler.value = {
|
||||||
definer: '',
|
definer: '',
|
||||||
sql: 'BEGIN\r\n\r\nEND',
|
sql: 'BEGIN\r\n\r\nEND',
|
||||||
|
@@ -332,7 +332,10 @@ const addField = () => {
|
|||||||
collation: defaultCollation.value,
|
collation: defaultCollation.value,
|
||||||
autoIncrement: false,
|
autoIncrement: false,
|
||||||
onUpdate: '',
|
onUpdate: '',
|
||||||
comment: ''
|
comment: '',
|
||||||
|
alias: '',
|
||||||
|
tableAlias: '',
|
||||||
|
orgTable: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="px-2">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column col-auto">
|
<div class="column col-auto">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -118,8 +118,10 @@
|
|||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import QueryEditor from '@/components/QueryEditor.vue';
|
import QueryEditor from '@/components/QueryEditor.vue';
|
||||||
import BaseLoader from '@/components/BaseLoader.vue';
|
import BaseLoader from '@/components/BaseLoader.vue';
|
||||||
import Triggers from '@/ipc-api/Triggers';
|
import Triggers from '@/ipc-api/Triggers';
|
||||||
@@ -137,6 +139,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -254,8 +257,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -264,7 +271,7 @@ const resizeQueryEditor = () => {
|
|||||||
const onKey = (e: KeyboardEvent) => {
|
const onKey = (e: KeyboardEvent) => {
|
||||||
if (props.isSelected) {
|
if (props.isSelected) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (e.ctrlKey && e.keyCode === 83) { // CTRL + S
|
if (e.ctrlKey && e.key === 's') { // CTRL + S
|
||||||
if (isChanged.value)
|
if (isChanged.value)
|
||||||
saveChanges();
|
saveChanges();
|
||||||
}
|
}
|
||||||
@@ -288,6 +295,10 @@ originalTrigger.value = {
|
|||||||
name: ''
|
name: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
localTrigger.value = JSON.parse(JSON.stringify(originalTrigger.value));
|
localTrigger.value = JSON.parse(JSON.stringify(originalTrigger.value));
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@@ -99,6 +99,8 @@ import { Ace } from 'ace-builds';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import BaseLoader from '@/components/BaseLoader.vue';
|
import BaseLoader from '@/components/BaseLoader.vue';
|
||||||
import QueryEditor from '@/components/QueryEditor.vue';
|
import QueryEditor from '@/components/QueryEditor.vue';
|
||||||
import Functions from '@/ipc-api/Functions';
|
import Functions from '@/ipc-api/Functions';
|
||||||
@@ -116,6 +118,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -189,8 +192,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -212,6 +219,18 @@ originalFunction.value = {
|
|||||||
name: ''
|
name: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(() => props.isSelected, (val) => {
|
||||||
|
if (val) changeBreadcrumbs({ schema: props.schema });
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(isChanged, (val) => {
|
||||||
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
localFunction.value = JSON.parse(JSON.stringify(originalFunction.value));
|
localFunction.value = JSON.parse(JSON.stringify(originalFunction.value));
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -238,12 +257,4 @@ onUnmounted(() => {
|
|||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener('keydown', onKey);
|
window.removeEventListener('keydown', onKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => props.isSelected, (val) => {
|
|
||||||
if (val) changeBreadcrumbs({ schema: props.schema });
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(isChanged, (val) => {
|
|
||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
@@ -107,6 +107,8 @@
|
|||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import BaseLoader from '@/components/BaseLoader.vue';
|
import BaseLoader from '@/components/BaseLoader.vue';
|
||||||
@@ -126,6 +128,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -202,8 +205,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -233,6 +240,10 @@ watch(isChanged, (val) => {
|
|||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
originalView.value = {
|
originalView.value = {
|
||||||
algorithm: 'UNDEFINED',
|
algorithm: 'UNDEFINED',
|
||||||
definer: '',
|
definer: '',
|
||||||
|
@@ -194,6 +194,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import { uidGen } from 'common/libs/uidGen';
|
import { uidGen } from 'common/libs/uidGen';
|
||||||
@@ -218,6 +220,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -344,8 +347,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -443,6 +450,10 @@ watch(isChanged, (val) => {
|
|||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await getFunctionData();
|
await getFunctionData();
|
||||||
queryEditor.value.editor.session.setValue(localFunction.value.sql);
|
queryEditor.value.editor.session.setValue(localFunction.value.sql);
|
||||||
|
@@ -168,6 +168,8 @@ import { Component, computed, onUnmounted, onBeforeUnmount, onMounted, Ref, ref,
|
|||||||
import { AlterRoutineParams, FunctionParam, RoutineInfos } from 'common/interfaces/antares';
|
import { AlterRoutineParams, FunctionParam, RoutineInfos } from 'common/interfaces/antares';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import { uidGen } from 'common/libs/uidGen';
|
import { uidGen } from 'common/libs/uidGen';
|
||||||
@@ -190,6 +192,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -316,8 +319,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -413,6 +420,10 @@ watch(isChanged, (val) => {
|
|||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await getRoutineData();
|
await getRoutineData();
|
||||||
queryEditor.value.editor.session.setValue(localRoutine.value.sql);
|
queryEditor.value.editor.session.setValue(localRoutine.value.sql);
|
||||||
|
@@ -127,6 +127,8 @@ import { AlterEventParams, EventInfos } from 'common/interfaces/antares';
|
|||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import BaseLoader from '@/components/BaseLoader.vue';
|
import BaseLoader from '@/components/BaseLoader.vue';
|
||||||
@@ -147,6 +149,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -269,8 +272,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -331,6 +338,10 @@ watch(isChanged, (val) => {
|
|||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await getSchedulerData();
|
await getSchedulerData();
|
||||||
queryEditor.value.editor.session.setValue(localScheduler.value.sql);
|
queryEditor.value.editor.session.setValue(localScheduler.value.sql);
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
:confirm-text="t('word.confirm')"
|
:confirm-text="t('word.confirm')"
|
||||||
size="400"
|
size="400"
|
||||||
|
:disable-autofocus="true"
|
||||||
@confirm="confirmOptionsChange"
|
@confirm="confirmOptionsChange"
|
||||||
@hide="$emit('hide')"
|
@hide="$emit('hide')"
|
||||||
>
|
>
|
||||||
|
@@ -126,8 +126,10 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Component, computed, onMounted, onUnmounted, onUpdated, Prop, ref, Ref, watch } from 'vue';
|
import { Component, computed, onMounted, onUnmounted, onUpdated, Prop, ref, Ref, watch } from 'vue';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import * as Draggable from 'vuedraggable';
|
import * as Draggable from 'vuedraggable';
|
||||||
import TableRow from '@/components/WorkspaceTabPropsTableRow.vue';
|
import TableRow from '@/components/WorkspaceTabPropsTableRow.vue';
|
||||||
import TableContext from '@/components/WorkspaceTabPropsTableContext.vue';
|
import TableContext from '@/components/WorkspaceTabPropsTableContext.vue';
|
||||||
@@ -150,9 +152,12 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['add-new-index', 'add-to-index', 'rename-field', 'duplicate-field', 'remove-field']);
|
const emit = defineEmits(['add-new-index', 'add-to-index', 'rename-field', 'duplicate-field', 'remove-field']);
|
||||||
|
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const consoleStore = useConsoleStore();
|
||||||
|
|
||||||
const { getWorkspace } = workspacesStore;
|
const { getWorkspace } = workspacesStore;
|
||||||
|
|
||||||
|
const { consoleHeight } = storeToRefs(consoleStore);
|
||||||
|
|
||||||
const tableWrapper: Ref<HTMLDivElement> = ref(null);
|
const tableWrapper: Ref<HTMLDivElement> = ref(null);
|
||||||
const propTable: Ref<HTMLDivElement> = ref(null);
|
const propTable: Ref<HTMLDivElement> = ref(null);
|
||||||
const resultTable: Ref<Component> = ref(null);
|
const resultTable: Ref<Component> = ref(null);
|
||||||
@@ -172,8 +177,13 @@ const resizeResults = () => {
|
|||||||
const el = tableWrapper.value;
|
const el = tableWrapper.value;
|
||||||
|
|
||||||
if (el) {
|
if (el) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
resultsSize.value = size;
|
resultsSize.value = size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,6 +226,10 @@ watch(fieldsLength, () => {
|
|||||||
refreshScroller();
|
refreshScroller();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeResults();
|
||||||
|
});
|
||||||
|
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
if (propTable.value)
|
if (propTable.value)
|
||||||
refreshScroller();
|
refreshScroller();
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="px-2">
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column col-auto">
|
<div class="column col-auto">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -118,6 +118,8 @@
|
|||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
import QueryEditor from '@/components/QueryEditor.vue';
|
import QueryEditor from '@/components/QueryEditor.vue';
|
||||||
@@ -139,6 +141,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -304,8 +307,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -345,6 +352,10 @@ watch(isChanged, (val) => {
|
|||||||
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: val });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await getTriggerData();
|
await getTriggerData();
|
||||||
queryEditor.value.editor.session.setValue(localTrigger.value.sql);
|
queryEditor.value.editor.session.setValue(localTrigger.value.sql);
|
||||||
|
@@ -84,8 +84,10 @@
|
|||||||
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import BaseLoader from '@/components/BaseLoader.vue';
|
import BaseLoader from '@/components/BaseLoader.vue';
|
||||||
import QueryEditor from '@/components/QueryEditor.vue';
|
import QueryEditor from '@/components/QueryEditor.vue';
|
||||||
import Functions from '@/ipc-api/Functions';
|
import Functions from '@/ipc-api/Functions';
|
||||||
@@ -104,6 +106,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
@@ -209,8 +212,12 @@ const clearChanges = () => {
|
|||||||
|
|
||||||
const resizeQueryEditor = () => {
|
const resizeQueryEditor = () => {
|
||||||
if (queryEditor.value) {
|
if (queryEditor.value) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - queryEditor.value.$el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
editorHeight.value = size;
|
editorHeight.value = size;
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
}
|
}
|
||||||
@@ -242,6 +249,10 @@ watch(() => props.function, async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeQueryEditor();
|
||||||
|
});
|
||||||
|
|
||||||
watch(() => props.isSelected, (val) => {
|
watch(() => props.isSelected, (val) => {
|
||||||
if (val) changeBreadcrumbs({ schema: props.schema });
|
if (val) changeBreadcrumbs({ schema: props.schema });
|
||||||
});
|
});
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
<div class="workspace-query-runner column col-12">
|
<div class="workspace-query-runner column col-12">
|
||||||
<QueryEditor
|
<QueryEditor
|
||||||
v-show="isSelected"
|
v-show="isSelected"
|
||||||
|
id="query-editor"
|
||||||
ref="queryEditor"
|
ref="queryEditor"
|
||||||
v-model="query"
|
v-model="query"
|
||||||
:auto-focus="true"
|
:auto-focus="true"
|
||||||
@@ -187,18 +188,20 @@
|
|||||||
import { Component, computed, onBeforeUnmount, onMounted, Prop, ref, Ref, watch } from 'vue';
|
import { Component, computed, onBeforeUnmount, onMounted, Prop, ref, Ref, watch } from 'vue';
|
||||||
import { Ace } from 'ace-builds';
|
import { Ace } from 'ace-builds';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { storeToRefs } from 'pinia';
|
||||||
import { format } from 'sql-formatter';
|
import { format } from 'sql-formatter';
|
||||||
import { ConnectionParams } from 'common/interfaces/antares';
|
import { ConnectionParams } from 'common/interfaces/antares';
|
||||||
import { useHistoryStore } from '@/stores/history';
|
import { useHistoryStore } from '@/stores/history';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
|
import { useResultTables } from '@/composables/useResultTables';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import Schema from '@/ipc-api/Schema';
|
import Schema from '@/ipc-api/Schema';
|
||||||
import QueryEditor from '@/components/QueryEditor.vue';
|
import QueryEditor from '@/components/QueryEditor.vue';
|
||||||
import BaseLoader from '@/components/BaseLoader.vue';
|
import BaseLoader from '@/components/BaseLoader.vue';
|
||||||
import WorkspaceTabQueryTable from '@/components/WorkspaceTabQueryTable.vue';
|
import WorkspaceTabQueryTable from '@/components/WorkspaceTabQueryTable.vue';
|
||||||
import WorkspaceTabQueryEmptyState from '@/components/WorkspaceTabQueryEmptyState.vue';
|
import WorkspaceTabQueryEmptyState from '@/components/WorkspaceTabQueryEmptyState.vue';
|
||||||
import ModalHistory from '@/components/ModalHistory.vue';
|
import ModalHistory from '@/components/ModalHistory.vue';
|
||||||
import { useResultTables } from '@/composables/useResultTables';
|
|
||||||
import BaseSelect from '@/components/BaseSelect.vue';
|
import BaseSelect from '@/components/BaseSelect.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@@ -223,6 +226,8 @@ const { saveHistory } = useHistoryStore();
|
|||||||
const { addNotification } = useNotificationsStore();
|
const { addNotification } = useNotificationsStore();
|
||||||
const workspacesStore = useWorkspacesStore();
|
const workspacesStore = useWorkspacesStore();
|
||||||
|
|
||||||
|
const { consoleHeight } = storeToRefs(useConsoleStore());
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getWorkspace,
|
getWorkspace,
|
||||||
changeBreadcrumbs,
|
changeBreadcrumbs,
|
||||||
@@ -365,14 +370,17 @@ const resize = (e: MouseEvent) => {
|
|||||||
const el = queryEditor.value.$el;
|
const el = queryEditor.value.$el;
|
||||||
const queryFooterHeight = queryAreaFooter.value.clientHeight;
|
const queryFooterHeight = queryAreaFooter.value.clientHeight;
|
||||||
const bottom = e.pageY || resizer.value.getBoundingClientRect().bottom;
|
const bottom = e.pageY || resizer.value.getBoundingClientRect().bottom;
|
||||||
const maxHeight = window.innerHeight - 100 - queryFooterHeight;
|
const maxHeight = window.innerHeight - 100 - queryFooterHeight - consoleHeight.value;
|
||||||
let localEditorHeight = bottom - el.getBoundingClientRect().top;
|
let localEditorHeight = bottom - el.getBoundingClientRect().top;
|
||||||
if (localEditorHeight > maxHeight) localEditorHeight = maxHeight;
|
if (localEditorHeight > maxHeight) localEditorHeight = maxHeight;
|
||||||
if (localEditorHeight < 50) localEditorHeight = 50;
|
if (localEditorHeight < 50) localEditorHeight = 50;
|
||||||
editorHeight.value = localEditorHeight;
|
editorHeight.value = localEditorHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resizeResults = () => queryTable.value.resizeResults();
|
||||||
|
|
||||||
const onWindowResize = (e: MouseEvent) => {
|
const onWindowResize = (e: MouseEvent) => {
|
||||||
|
if (!queryEditor.value) return;
|
||||||
const el = queryEditor.value.$el;
|
const el = queryEditor.value.$el;
|
||||||
const queryFooterHeight = queryAreaFooter.value.clientHeight;
|
const queryFooterHeight = queryAreaFooter.value.clientHeight;
|
||||||
const bottom = e.pageY || resizer.value.getBoundingClientRect().bottom;
|
const bottom = e.pageY || resizer.value.getBoundingClientRect().bottom;
|
||||||
@@ -386,7 +394,7 @@ const onWindowResize = (e: MouseEvent) => {
|
|||||||
const stopResize = () => {
|
const stopResize = () => {
|
||||||
window.removeEventListener('mousemove', resize);
|
window.removeEventListener('mousemove', resize);
|
||||||
if (queryTable.value && results.value.length)
|
if (queryTable.value && results.value.length)
|
||||||
queryTable.value.resizeResults();
|
resizeResults();
|
||||||
|
|
||||||
if (queryEditor.value)
|
if (queryEditor.value)
|
||||||
queryEditor.value.editor.resize();
|
queryEditor.value.editor.resize();
|
||||||
@@ -476,6 +484,8 @@ const rollbackTab = async () => {
|
|||||||
isQuering.value = false;
|
isQuering.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
defineExpose({ resizeResults });
|
||||||
|
|
||||||
query.value = props.tab.content as string;
|
query.value = props.tab.content as string;
|
||||||
selectedSchema.value = props.tab.schema || breadcrumbsSchema.value;
|
selectedSchema.value = props.tab.schema || breadcrumbsSchema.value;
|
||||||
|
|
||||||
|
@@ -118,6 +118,7 @@ import { storeToRefs } from 'pinia';
|
|||||||
import { uidGen } from 'common/libs/uidGen';
|
import { uidGen } from 'common/libs/uidGen';
|
||||||
import { useSettingsStore } from '@/stores/settings';
|
import { useSettingsStore } from '@/stores/settings';
|
||||||
import { useWorkspacesStore } from '@/stores/workspaces';
|
import { useWorkspacesStore } from '@/stores/workspaces';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
import { arrayToFile } from '../libs/arrayToFile';
|
import { arrayToFile } from '../libs/arrayToFile';
|
||||||
import { TEXT, LONG_TEXT, BLOB } from 'common/fieldTypes';
|
import { TEXT, LONG_TEXT, BLOB } from 'common/fieldTypes';
|
||||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
|
import BaseVirtualScroll from '@/components/BaseVirtualScroll.vue';
|
||||||
@@ -132,10 +133,13 @@ import { TableUpdateParams } from 'common/interfaces/tableApis';
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
const consoleStore = useConsoleStore();
|
||||||
const { getWorkspace } = useWorkspacesStore();
|
const { getWorkspace } = useWorkspacesStore();
|
||||||
|
|
||||||
const { dataTabLimit: pageSize } = storeToRefs(settingsStore);
|
const { dataTabLimit: pageSize } = storeToRefs(settingsStore);
|
||||||
|
|
||||||
|
const { consoleHeight } = storeToRefs(consoleStore);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
results: Array as Prop<QueryResult[]>,
|
results: Array as Prop<QueryResult[]>,
|
||||||
connUid: String,
|
connUid: String,
|
||||||
@@ -272,6 +276,8 @@ const getSchema = (index: number) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getPrimaryValue = (row: any) => {
|
const getPrimaryValue = (row: any) => {
|
||||||
|
if (!primaryField.value) return null;
|
||||||
|
|
||||||
const primaryFieldName = Object.keys(row).find(prop => [
|
const primaryFieldName = Object.keys(row).find(prop => [
|
||||||
primaryField.value.alias,
|
primaryField.value.alias,
|
||||||
primaryField.value.name,
|
primaryField.value.name,
|
||||||
@@ -296,8 +302,13 @@ const resizeResults = () => {
|
|||||||
const el = tableWrapper.value;
|
const el = tableWrapper.value;
|
||||||
|
|
||||||
if (el) {
|
if (el) {
|
||||||
|
let sizeToSubtract = 0;
|
||||||
const footer = document.getElementById('footer');
|
const footer = document.getElementById('footer');
|
||||||
const size = window.innerHeight - el.getBoundingClientRect().top - footer.offsetHeight;
|
if (footer) sizeToSubtract += footer.offsetHeight;
|
||||||
|
|
||||||
|
sizeToSubtract += consoleHeight.value;
|
||||||
|
|
||||||
|
const size = window.innerHeight - el.getBoundingClientRect().top - sizeToSubtract;
|
||||||
resultsSize.value = size;
|
resultsSize.value = size;
|
||||||
}
|
}
|
||||||
resultTable.value.updateWindow();
|
resultTable.value.updateWindow();
|
||||||
@@ -321,7 +332,7 @@ const updateField = (payload: { field: string; type: string; content: any }, row
|
|||||||
});
|
});
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
primary: primaryField.value.name,
|
primary: primaryField.value?.name,
|
||||||
schema: getSchema(resultsetIndex.value),
|
schema: getSchema(resultsetIndex.value),
|
||||||
table: getTable(resultsetIndex.value),
|
table: getTable(resultsetIndex.value),
|
||||||
id: getPrimaryValue(orgRow),
|
id: getPrimaryValue(orgRow),
|
||||||
@@ -662,6 +673,10 @@ watch(() => props.isSelected, async (val) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(consoleHeight, () => {
|
||||||
|
resizeResults();
|
||||||
|
});
|
||||||
|
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
if (table.value)
|
if (table.value)
|
||||||
refreshScroller();
|
refreshScroller();
|
||||||
|
@@ -194,9 +194,9 @@
|
|||||||
import { computed, onBeforeUnmount, Prop, ref, Ref, watch, nextTick } from 'vue';
|
import { computed, onBeforeUnmount, Prop, ref, Ref, watch, nextTick } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import { ModelOperations } from '@vscode/vscode-languagedetection';
|
|
||||||
import { mimeFromHex } from 'common/libs/mimeFromHex';
|
import { mimeFromHex } from 'common/libs/mimeFromHex';
|
||||||
import { formatBytes } from 'common/libs/formatBytes';
|
import { formatBytes } from 'common/libs/formatBytes';
|
||||||
|
import { langDetector } from 'common/libs/langDetector';
|
||||||
import { bufferToBase64 } from 'common/libs/bufferToBase64';
|
import { bufferToBase64 } from 'common/libs/bufferToBase64';
|
||||||
import hexToBinary, { HexChar } from 'common/libs/hexToBinary';
|
import hexToBinary, { HexChar } from 'common/libs/hexToBinary';
|
||||||
import {
|
import {
|
||||||
@@ -604,19 +604,8 @@ watch(() => props.fields, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
watch(isTextareaEditor, (val) => {
|
watch(isTextareaEditor, (val) => {
|
||||||
if (val) {
|
if (val)
|
||||||
const modelOperations = new ModelOperations();
|
editorMode.value = langDetector(editingContent.value);
|
||||||
(async () => {
|
|
||||||
const detected = await modelOperations.runModel(editingContent.value);
|
|
||||||
const filteredLanguages = detected.filter(dLang =>
|
|
||||||
availableLanguages.value.some(aLang => aLang.id === dLang.languageId) &&
|
|
||||||
dLang.confidence > 0.1
|
|
||||||
);
|
|
||||||
|
|
||||||
if (filteredLanguages.length)
|
|
||||||
editorMode.value = availableLanguages.value.find(lang => lang.id === filteredLanguages[0].languageId).slug;
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => props.selected, (isSelected) => {
|
watch(() => props.selected, (isSelected) => {
|
||||||
|
@@ -56,7 +56,8 @@ const useFocusTrap = (args?: {disableAutofocus?: boolean}) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initFocusTrap () {
|
function initFocusTrap () {
|
||||||
if (!trapRef.value || isInitiated.value) return;
|
if (!trapRef.value || (isInitiated.value)) return;
|
||||||
|
|
||||||
focusableElements = (trapRef.value as HTMLElement).querySelectorAll(
|
focusableElements = (trapRef.value as HTMLElement).querySelectorAll(
|
||||||
focusableElementsSelector
|
focusableElementsSelector
|
||||||
);
|
);
|
||||||
|
@@ -139,7 +139,10 @@ module.exports = {
|
|||||||
commit: 'Commit',
|
commit: 'Commit',
|
||||||
rollback: 'Rollback',
|
rollback: 'Rollback',
|
||||||
connectionString: 'Connection string',
|
connectionString: 'Connection string',
|
||||||
contributors: 'Contributors'
|
contributors: 'Contributors',
|
||||||
|
pin: 'Pin',
|
||||||
|
unpin: 'Unpin',
|
||||||
|
console: 'Console'
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
appWelcome: 'Welcome to Antares SQL Client!',
|
appWelcome: 'Welcome to Antares SQL Client!',
|
||||||
@@ -291,7 +294,11 @@ module.exports = {
|
|||||||
untrustedConnection: 'Untrusted connection',
|
untrustedConnection: 'Untrusted connection',
|
||||||
missingOrIncompleteTranslation: 'Missing or incomplete translation?',
|
missingOrIncompleteTranslation: 'Missing or incomplete translation?',
|
||||||
findOutHowToContribute: 'Find out how to contribute',
|
findOutHowToContribute: 'Find out how to contribute',
|
||||||
disableFKChecks: 'Disable foreigh key checks'
|
disableFKChecks: 'Disable foreigh key checks',
|
||||||
|
allConnections: 'All connections',
|
||||||
|
searchForConnections: 'Search for connections',
|
||||||
|
disableScratchpad: 'Disable scratchpad',
|
||||||
|
reportABug: 'Report a bug'
|
||||||
},
|
},
|
||||||
faker: {
|
faker: {
|
||||||
address: 'Address',
|
address: 'Address',
|
||||||
|
@@ -51,12 +51,12 @@ module.exports = {
|
|||||||
unsigned: '无符号',
|
unsigned: '无符号',
|
||||||
default: '默认',
|
default: '默认',
|
||||||
comment: '注释',
|
comment: '注释',
|
||||||
key: '键',
|
key: 'Key | Keys',
|
||||||
order: 'Order',
|
order: 'Order',
|
||||||
expression: '表达式',
|
expression: '表达式',
|
||||||
autoIncrement: '自动增量',
|
autoIncrement: '自动增量',
|
||||||
engine: 'Engine',
|
engine: 'Engine',
|
||||||
field: '字段',
|
field: 'Field | 字段',
|
||||||
approximately: '大约',
|
approximately: '大约',
|
||||||
total: '总计',
|
total: '总计',
|
||||||
table: '表',
|
table: '表',
|
||||||
@@ -71,15 +71,16 @@ module.exports = {
|
|||||||
view: '视图',
|
view: '视图',
|
||||||
definer: '定义者',
|
definer: '定义者',
|
||||||
algorithm: 'Algorithm',
|
algorithm: 'Algorithm',
|
||||||
trigger: '触发器',
|
trigger: 'Trigger | 触发器',
|
||||||
storedRoutine: '存储例程',
|
storedRoutine: 'Stored routine | 存储例程',
|
||||||
scheduler: '调度器',
|
scheduler: 'Scheduler | 调度器',
|
||||||
event: '事件',
|
event: '事件',
|
||||||
parameters: '参数',
|
parameters: '参数',
|
||||||
function: '函数',
|
function: 'Function | 函数',
|
||||||
deterministic: 'Deterministic',
|
deterministic: 'Deterministic',
|
||||||
context: '上下文',
|
context: '上下文',
|
||||||
export: '导出',
|
export: '导出',
|
||||||
|
import: '导入',
|
||||||
returns: '返回',
|
returns: '返回',
|
||||||
timing: '定时器',
|
timing: '定时器',
|
||||||
state: '状态',
|
state: '状态',
|
||||||
@@ -111,9 +112,9 @@ module.exports = {
|
|||||||
small: '小',
|
small: '小',
|
||||||
medium: '中',
|
medium: '中',
|
||||||
large: '大',
|
large: '大',
|
||||||
row: '行',
|
row: 'Row | 行',
|
||||||
cell: '单元格',
|
cell: 'Cell | 单元格',
|
||||||
triggerFunction: '触发函数',
|
triggerFunction: 'Trigger function | 触发函数',
|
||||||
all: '全部',
|
all: '全部',
|
||||||
duplicate: '重复',
|
duplicate: '重复',
|
||||||
routine: '例程',
|
routine: '例程',
|
||||||
@@ -122,9 +123,25 @@ module.exports = {
|
|||||||
select: '选择',
|
select: '选择',
|
||||||
passphrase: '密码',
|
passphrase: '密码',
|
||||||
filter: '过滤器',
|
filter: '过滤器',
|
||||||
|
change: '变更',
|
||||||
|
views: '视图',
|
||||||
|
triggers: '触发器',
|
||||||
|
routines: '例程',
|
||||||
|
functions: '函数',
|
||||||
|
schedulers: '调度器',
|
||||||
|
includes: '包括',
|
||||||
|
drop: '按下([使]掉下)',
|
||||||
|
completed: '完成',
|
||||||
|
aborted: '中止',
|
||||||
disabled: '禁用',
|
disabled: '禁用',
|
||||||
enable: '启用',
|
enable: '启用',
|
||||||
disable: '是否禁用'
|
disable: '是否禁用',
|
||||||
|
commit: '提交',
|
||||||
|
rollback: '回滚',
|
||||||
|
connectionString: '连接字符串',
|
||||||
|
contributors: '贡献者',
|
||||||
|
pin: 'Pin',
|
||||||
|
unpin: 'Unpin'
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
appWelcome: '欢迎来到Antares SQL Client!',
|
appWelcome: '欢迎来到Antares SQL Client!',
|
||||||
@@ -250,9 +267,36 @@ module.exports = {
|
|||||||
searchForQueries: '搜索查询',
|
searchForQueries: '搜索查询',
|
||||||
killProcess: '杀死进程',
|
killProcess: '杀死进程',
|
||||||
closeTab: '关闭标签',
|
closeTab: '关闭标签',
|
||||||
|
exportSchema: '导出 schema',
|
||||||
|
importSchema: '导入 schema',
|
||||||
|
directoryPath: '目录路径',
|
||||||
|
newInserStmtEvery: '新的 INSERT 语句每个',
|
||||||
|
processingTableExport: '处理 {table}',
|
||||||
|
fechingTableExport: '正在从 {table} 获取数据中',
|
||||||
|
writingTableExport: '正在将 {table} 数据写入中',
|
||||||
|
checkAllTables: '检查所有表格',
|
||||||
|
uncheckAllTables: '取消选中所有表格',
|
||||||
goToDownloadPage: '跳转到下载页面',
|
goToDownloadPage: '跳转到下载页面',
|
||||||
readOnlyMode: '只读模式',
|
readOnlyMode: '只读模式',
|
||||||
killQuery: '停止查询'
|
killQuery: '停止查询',
|
||||||
|
insertRow: '插入行 | 插入多行',
|
||||||
|
commitMode: '提交模式',
|
||||||
|
autoCommit: '自动提交',
|
||||||
|
manualCommit: '手动提交',
|
||||||
|
actionSuccessful: '{action} 成功',
|
||||||
|
importQueryErrors: '警告: {n} 错误已发生 | 警告: 发生 {n} 个错误',
|
||||||
|
executedQueries: '{n} 个查询已执行 | {n} 个查询已执行',
|
||||||
|
ourputFormat: '输出格式',
|
||||||
|
singleFile: '单个 {ext} 文件',
|
||||||
|
zipCompressedFile: 'ZIP 压缩 {ext} 文件',
|
||||||
|
disableBlur: '禁用模糊',
|
||||||
|
untrustedConnection: '不受信任的连接',
|
||||||
|
missingOrIncompleteTranslation: '翻译缺失或不完整?',
|
||||||
|
findOutHowToContribute: '找出如何贡献',
|
||||||
|
disableFKChecks: '禁用外键检查',
|
||||||
|
allConnections: '所有连接',
|
||||||
|
searchForConnections: '搜索连接',
|
||||||
|
disableScratchpad: '禁用暂存器'
|
||||||
},
|
},
|
||||||
faker: {
|
faker: {
|
||||||
address: '地址',
|
address: '地址',
|
||||||
@@ -262,8 +306,8 @@ module.exports = {
|
|||||||
date: '日期',
|
date: '日期',
|
||||||
finance: '财务',
|
finance: '财务',
|
||||||
git: 'Git',
|
git: 'Git',
|
||||||
hacker: '黑客',
|
hacker: 'Hacker',
|
||||||
internet: '互联网',
|
internet: 'Internet',
|
||||||
lorem: 'Lorem',
|
lorem: 'Lorem',
|
||||||
name: '姓名',
|
name: '姓名',
|
||||||
music: '音乐',
|
music: '音乐',
|
||||||
|
@@ -10,6 +10,7 @@ import { VueMaskDirective } from 'v-mask';
|
|||||||
import { useApplicationStore } from '@/stores/application';
|
import { useApplicationStore } from '@/stores/application';
|
||||||
import { useSettingsStore } from '@/stores/settings';
|
import { useSettingsStore } from '@/stores/settings';
|
||||||
import { useNotificationsStore } from '@/stores/notifications';
|
import { useNotificationsStore } from '@/stores/notifications';
|
||||||
|
import { useConsoleStore } from '@/stores/console';
|
||||||
|
|
||||||
import App from '@/App.vue';
|
import App from '@/App.vue';
|
||||||
import i18n from '@/i18n';
|
import i18n from '@/i18n';
|
||||||
@@ -36,6 +37,11 @@ ipcRenderer.on('unhandled-exception', (event, error) => {
|
|||||||
useNotificationsStore().addNotification({ status: 'error', message: error.message });
|
useNotificationsStore().addNotification({ status: 'error', message: error.message });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// IPC query logs
|
||||||
|
ipcRenderer.on('query-log', (event, logRecord) => {
|
||||||
|
useConsoleStore().putLog(logRecord);
|
||||||
|
});
|
||||||
|
|
||||||
// IPC app updates
|
// IPC app updates
|
||||||
ipcRenderer.on('checking-for-update', () => {
|
ipcRenderer.on('checking-for-update', () => {
|
||||||
useApplicationStore().updateStatus = 'checking';
|
useApplicationStore().updateStatus = 'checking';
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
width: 42px;
|
width: 42px;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&.dbi-mysql {
|
&.dbi-mysql {
|
||||||
background-image: url("../images/svg/mysql.svg");
|
background-image: url("../images/svg/mysql.svg");
|
||||||
|
@@ -264,6 +264,12 @@ option:checked {
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tooltip:hover {
|
||||||
|
&::after {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
&[data-badge],
|
&[data-badge],
|
||||||
&:not([data-badge]) {
|
&:not([data-badge]) {
|
||||||
@@ -356,6 +362,16 @@ option:checked {
|
|||||||
.accordion-body {
|
.accordion-body {
|
||||||
max-height: 5000rem !important;
|
max-height: 5000rem !important;
|
||||||
}
|
}
|
||||||
|
.btn {
|
||||||
|
&:focus{
|
||||||
|
box-shadow: 0 0 3px 1px rgba($primary-color, 90%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.btn-success:focus {
|
||||||
|
border-color: $primary-color;
|
||||||
|
box-shadow: 0 0 3px 1px rgba($primary-color, 90%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.btn-group {
|
.btn-group {
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
@@ -368,6 +384,10 @@ option:checked {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
margin: 0.15rem 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
.table-dropdown {
|
.table-dropdown {
|
||||||
.menu {
|
.menu {
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
|
@@ -148,6 +148,10 @@
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
border-top: 0.05rem solid rgba($body-font-color-dark, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
.form-switch .form-icon::before {
|
.form-switch .form-icon::before {
|
||||||
background: $bg-color-light-dark;
|
background: $bg-color-light-dark;
|
||||||
}
|
}
|
||||||
@@ -252,6 +256,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.connection-block{
|
||||||
|
&:hover {
|
||||||
|
background: $bg-color-light-dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.bg-checkered {
|
.bg-checkered {
|
||||||
background-image:
|
background-image:
|
||||||
linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)),
|
linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)),
|
||||||
@@ -295,6 +305,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.query-console {
|
||||||
|
border-top: 1px solid #444;
|
||||||
|
background-color: $bg-color-dark;
|
||||||
|
|
||||||
|
.query-console-log {
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background: $bg-color-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tile {
|
.tile {
|
||||||
transition: background 0.2s;
|
transition: background 0.2s;
|
||||||
|
|
||||||
@@ -396,9 +418,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settingbar-bottom-elements {
|
.settingbar-bottom-elements {
|
||||||
padding-top: 0.5rem;
|
|
||||||
background: $bg-color-light-dark;
|
background: $bg-color-light-dark;
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.settingbar-elements {
|
.settingbar-elements {
|
||||||
|
@@ -94,6 +94,10 @@
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
border-top: 0.05rem solid rgba($body-font-color-dark, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
.tile {
|
.tile {
|
||||||
transition: background 0.2s;
|
transition: background 0.2s;
|
||||||
|
|
||||||
@@ -124,6 +128,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.query-console {
|
||||||
|
border-top: 1px solid darken($bg-color-light-gray, 15%);
|
||||||
|
background-color: $bg-color-light;
|
||||||
|
|
||||||
|
.query-console-log {
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background: $bg-color-light-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#titlebar {
|
#titlebar {
|
||||||
background: $bg-color-light;
|
background: $bg-color-light;
|
||||||
box-shadow: 0 0 1px 0 #000;
|
box-shadow: 0 0 1px 0 #000;
|
||||||
@@ -165,9 +181,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.settingbar-bottom-elements {
|
.settingbar-bottom-elements {
|
||||||
padding-top: 0.5rem;
|
|
||||||
background: $bg-color-light-dark;
|
background: $bg-color-light-dark;
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.settingbar-elements {
|
.settingbar-elements {
|
||||||
@@ -220,6 +234,10 @@
|
|||||||
|
|
||||||
.table-size {
|
.table-size {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,6 +291,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.connection-block{
|
||||||
|
&:hover {
|
||||||
|
background: $bg-color-light-gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.context {
|
.context {
|
||||||
color: $body-font-color-dark;
|
color: $body-font-color-dark;
|
||||||
|
|
||||||
|
@@ -17,7 +17,9 @@ const persistentStore = new Store({
|
|||||||
|
|
||||||
export const useConnectionsStore = defineStore('connections', {
|
export const useConnectionsStore = defineStore('connections', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
connections: persistentStore.get('connections', []) as ConnectionParams[]
|
connections: persistentStore.get('connections', []) as ConnectionParams[],
|
||||||
|
pinnedConnections: new Set([...persistentStore.get('pinnedConnections', []) as string[]]) as Set<string>,
|
||||||
|
lastConnections: persistentStore.get('lastConnections', []) as {uid: string; time: number}[]
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getConnectionName: state => (uid: string) => {
|
getConnectionName: state => (uid: string) => {
|
||||||
@@ -50,6 +52,8 @@ export const useConnectionsStore = defineStore('connections', {
|
|||||||
deleteConnection (connection: ConnectionParams) {
|
deleteConnection (connection: ConnectionParams) {
|
||||||
this.connections = (this.connections as ConnectionParams[]).filter(el => el.uid !== connection.uid);
|
this.connections = (this.connections as ConnectionParams[]).filter(el => el.uid !== connection.uid);
|
||||||
persistentStore.set('connections', this.connections);
|
persistentStore.set('connections', this.connections);
|
||||||
|
(this.pinnedConnections as Set<string>).delete(connection.uid);
|
||||||
|
persistentStore.set('pinnedConnections', [...this.pinnedConnections]);
|
||||||
},
|
},
|
||||||
editConnection (connection: ConnectionParams) {
|
editConnection (connection: ConnectionParams) {
|
||||||
const editedConnections = (this.connections as ConnectionParams[]).map(conn => {
|
const editedConnections = (this.connections as ConnectionParams[]).map(conn => {
|
||||||
@@ -63,6 +67,28 @@ export const useConnectionsStore = defineStore('connections', {
|
|||||||
updateConnections (connections: ConnectionParams[]) {
|
updateConnections (connections: ConnectionParams[]) {
|
||||||
this.connections = connections;
|
this.connections = connections;
|
||||||
persistentStore.set('connections', this.connections);
|
persistentStore.set('connections', this.connections);
|
||||||
|
},
|
||||||
|
updatePinnedConnections (pinned: string[]) {
|
||||||
|
this.pinnedConnections = new Set(pinned);
|
||||||
|
persistentStore.set('pinnedConnections', [...this.pinnedConnections]);
|
||||||
|
},
|
||||||
|
pinConnection (uid: string) {
|
||||||
|
(this.pinnedConnections as Set<string>).add(uid);
|
||||||
|
persistentStore.set('pinnedConnections', [...this.pinnedConnections]);
|
||||||
|
},
|
||||||
|
unpinConnection (uid: string) {
|
||||||
|
(this.pinnedConnections as Set<string>).delete(uid);
|
||||||
|
persistentStore.set('pinnedConnections', [...this.pinnedConnections]);
|
||||||
|
},
|
||||||
|
updateLastConnection (uid: string) {
|
||||||
|
const cIndex = (this.lastConnections as {uid: string; time: number}[]).findIndex((c) => c.uid === uid);
|
||||||
|
|
||||||
|
if (cIndex >= 0)
|
||||||
|
this.lastConnections[cIndex].time = new Date().getTime();
|
||||||
|
else
|
||||||
|
this.lastConnections.push({ uid, time: new Date().getTime() });
|
||||||
|
|
||||||
|
persistentStore.set('lastConnections', this.lastConnections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
63
src/renderer/stores/console.ts
Normal file
63
src/renderer/stores/console.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import { ipcRenderer } from 'electron';
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { useWorkspacesStore } from './workspaces';
|
||||||
|
const logsSize = 1000;
|
||||||
|
|
||||||
|
export interface ConsoleRecord {
|
||||||
|
cUid: string;
|
||||||
|
sql: string;
|
||||||
|
date: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useConsoleStore = defineStore('console', {
|
||||||
|
state: () => ({
|
||||||
|
records: [] as ConsoleRecord[],
|
||||||
|
consolesHeight: new Map<string, number>(),
|
||||||
|
consolesOpened: new Set([])
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
getLogsByWorkspace: state => (uid: string) => state.records.filter(r => r.cUid === uid),
|
||||||
|
isConsoleOpen: state => (uid: string) => state.consolesOpened.has(uid),
|
||||||
|
consoleHeight: state => {
|
||||||
|
const uid = useWorkspacesStore().getSelected;
|
||||||
|
return state.consolesHeight.get(uid) || 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
putLog (record: ConsoleRecord) {
|
||||||
|
this.records.push(record);
|
||||||
|
|
||||||
|
if (this.records.length > logsSize)
|
||||||
|
this.records = this.records.slice(0, logsSize);
|
||||||
|
},
|
||||||
|
openConsole () {
|
||||||
|
const uid = useWorkspacesStore().getSelected;
|
||||||
|
this.consolesOpened.add(uid);
|
||||||
|
this.consolesHeight.set(uid, 250);
|
||||||
|
},
|
||||||
|
closeConsole () {
|
||||||
|
const uid = useWorkspacesStore().getSelected;
|
||||||
|
this.consolesOpened.delete(uid);
|
||||||
|
this.consolesHeight.set(uid, 0);
|
||||||
|
},
|
||||||
|
resizeConsole (height: number) {
|
||||||
|
const uid = useWorkspacesStore().getSelected;
|
||||||
|
if (height < 30)
|
||||||
|
this.closeConsole();
|
||||||
|
else
|
||||||
|
this.consolesHeight.set(uid, height);
|
||||||
|
},
|
||||||
|
toggleConsole () {
|
||||||
|
const uid = useWorkspacesStore().getSelected;
|
||||||
|
|
||||||
|
if (this.consolesOpened.has(uid))
|
||||||
|
this.closeConsole();
|
||||||
|
else
|
||||||
|
this.openConsole();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('toggle-console', () => {
|
||||||
|
useConsoleStore().toggleConsole();
|
||||||
|
});
|
@@ -23,7 +23,8 @@ export const useSettingsStore = defineStore('settings', {
|
|||||||
editorTheme: persistentStore.get('editor_theme', defaultEditorTheme) as string,
|
editorTheme: persistentStore.get('editor_theme', defaultEditorTheme) as string,
|
||||||
editorFontSize: persistentStore.get('editor_font_size', 'medium') as EditorFontSize,
|
editorFontSize: persistentStore.get('editor_font_size', 'medium') as EditorFontSize,
|
||||||
restoreTabs: persistentStore.get('restore_tabs', true) as boolean,
|
restoreTabs: persistentStore.get('restore_tabs', true) as boolean,
|
||||||
disableBlur: persistentStore.get('disable_blur', false) as boolean
|
disableBlur: persistentStore.get('disable_blur', false) as boolean,
|
||||||
|
disableScratchpad: persistentStore.get('disable_scratchpad', false) as boolean
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
changeLocale (locale: string) {
|
changeLocale (locale: string) {
|
||||||
@@ -75,6 +76,10 @@ export const useSettingsStore = defineStore('settings', {
|
|||||||
changeDisableBlur (val: boolean) {
|
changeDisableBlur (val: boolean) {
|
||||||
this.disableBlur = val;
|
this.disableBlur = val;
|
||||||
persistentStore.set('disable_blur', this.disableBlur);
|
persistentStore.set('disable_blur', this.disableBlur);
|
||||||
|
},
|
||||||
|
changeDisableScratchpad (val: boolean) {
|
||||||
|
this.disableScratchpad = val;
|
||||||
|
persistentStore.set('disable_scratchpad', this.disableScratchpad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -100,6 +100,15 @@ export const useWorkspacesStore = defineStore('workspaces', {
|
|||||||
getSelected: state => {
|
getSelected: state => {
|
||||||
if (!state.workspaces.length) return 'NEW';
|
if (!state.workspaces.length) return 'NEW';
|
||||||
if (state.selectedWorkspace) return state.selectedWorkspace;
|
if (state.selectedWorkspace) return state.selectedWorkspace;
|
||||||
|
const connectionsStore = useConnectionsStore();
|
||||||
|
if (connectionsStore.lastConnections.length) {
|
||||||
|
return connectionsStore.lastConnections.sort((a, b) => {
|
||||||
|
if (a.time < b.time) return 1;
|
||||||
|
else if (a.time > b.time) return -1;
|
||||||
|
return 0;
|
||||||
|
})[0].uid;
|
||||||
|
}
|
||||||
|
|
||||||
return state.workspaces[0].uid;
|
return state.workspaces[0].uid;
|
||||||
},
|
},
|
||||||
getWorkspace: state => (uid: string) => {
|
getWorkspace: state => (uid: string) => {
|
||||||
@@ -170,6 +179,9 @@ export const useWorkspacesStore = defineStore('workspaces', {
|
|||||||
let dataTypes: TypesGroup[] = [];
|
let dataTypes: TypesGroup[] = [];
|
||||||
let indexTypes: string[] = [];
|
let indexTypes: string[] = [];
|
||||||
let clientCustomizations: Customizations;
|
let clientCustomizations: Customizations;
|
||||||
|
const { updateLastConnection } = connectionsStore;
|
||||||
|
|
||||||
|
updateLastConnection(connection.uid);
|
||||||
|
|
||||||
switch (connection.client) {
|
switch (connection.client) {
|
||||||
case 'mysql':
|
case 'mysql':
|
||||||
@@ -715,44 +727,6 @@ export const useWorkspacesStore = defineStore('workspaces', {
|
|||||||
);
|
);
|
||||||
persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs);
|
persistentStore.set(uid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === uid).tabs);
|
||||||
},
|
},
|
||||||
// setTabFields ({ cUid, tUid, fields }: { cUid: string; tUid: string; fields: any }) {
|
|
||||||
// this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
|
||||||
// if (workspace.uid === cUid) {
|
|
||||||
// return {
|
|
||||||
// ...workspace,
|
|
||||||
// tabs: workspace.tabs.map(tab => {
|
|
||||||
// if (tab.uid === tUid)
|
|
||||||
// return { ...tab, fields };
|
|
||||||
// else
|
|
||||||
// return tab;
|
|
||||||
// })
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// return workspace;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// persistentStore.set(cUid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === cUid).tabs);
|
|
||||||
// },
|
|
||||||
// setTabKeyUsage ({ cUid, tUid, keyUsage }: { cUid: string; tUid: string; keyUsage: any }) {
|
|
||||||
// this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
|
||||||
// if (workspace.uid === cUid) {
|
|
||||||
// return {
|
|
||||||
// ...workspace,
|
|
||||||
// tabs: workspace.tabs.map(tab => {
|
|
||||||
// if (tab.uid === tUid)
|
|
||||||
// return { ...tab, keyUsage };
|
|
||||||
// else
|
|
||||||
// return tab;
|
|
||||||
// })
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// return workspace;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// persistentStore.set(cUid, (this.workspaces as Workspace[]).find(workspace => workspace.uid === cUid).tabs);
|
|
||||||
// },
|
|
||||||
setUnsavedChanges ({ uid, tUid, isChanged }: { uid: string; tUid: string; isChanged: boolean }) {
|
setUnsavedChanges ({ uid, tUid, isChanged }: { uid: string; tUid: string; isChanged: boolean }) {
|
||||||
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
this.workspaces = (this.workspaces as Workspace[]).map(workspace => {
|
||||||
if (workspace.uid === uid) {
|
if (workspace.uid === uid) {
|
||||||
|
@@ -23,8 +23,8 @@ test('main window elements visibility', async () => {
|
|||||||
const visibleSelectors = [
|
const visibleSelectors = [
|
||||||
// '#titlebar',
|
// '#titlebar',
|
||||||
'#window-content',
|
'#window-content',
|
||||||
'#settingbar',
|
'#settingbar'
|
||||||
'#footer'
|
// '#footer'
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const selector of visibleSelectors)
|
for (const selector of visibleSelectors)
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
"./src/renderer/**/*",
|
"./src/renderer/**/*",
|
||||||
"./src/common/interfaces/antares.ts"
|
"./src/common/interfaces/antares.ts"
|
||||||
],
|
],
|
||||||
|
"exclude": ["./src/renderer/libs/ext-language_tools.js"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"target": "es2021",
|
"target": "es2021",
|
||||||
|
Reference in New Issue
Block a user