mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
Compare commits
64 Commits
Author | SHA1 | Date | |
---|---|---|---|
420255cdd4 | |||
a8a47ed5f7 | |||
425f0663f9 | |||
e106d100b5 | |||
d7fdf53932 | |||
62f7e57d0c | |||
14577d14bb | |||
f5f2a697e8 | |||
a0105cf1c3 | |||
77c5d28032 | |||
d1d8592f79 | |||
1f828f69a0 | |||
adc5477673 | |||
1e543aa6b0 | |||
c41e059b0b | |||
e6ef5ffa56 | |||
d67d122270 | |||
b837e2fc68 | |||
a73a2f483e | |||
0a9983d30d | |||
58b91ebfe0 | |||
e78ca2417e | |||
e1855a262d | |||
6b725b1d40 | |||
f6faad98f8 | |||
320aa8ba04 | |||
9f0280b991 | |||
04fa320820 | |||
f7c3aa883d | |||
f7a74df009 | |||
003c02b1fb | |||
ef21ea7448 | |||
525c964c62 | |||
7845e3e501 | |||
0c29e0d566 | |||
d38097d056 | |||
c87b8dc738 | |||
ed6e7fa72d | |||
f0fa7c81b7 | |||
5bb4e496f2 | |||
01057332b0 | |||
ab382dfbcd | |||
88c4cdc8e2 | |||
15ff211a41 | |||
5c855a520a | |||
7488bc7a17 | |||
|
fd85cf43a2 | ||
a87079cd17 | |||
14d5842056 | |||
f19f9e23a2 | |||
0252a064d9 | |||
439356a019 | |||
c6897af22d | |||
7e40dbfba3 | |||
27a153ef43 | |||
56fcc2650b | |||
9622dbec6b | |||
a0ab63bdb5 | |||
8cd76e711c | |||
9af71a6e34 | |||
e7b3c28826 | |||
7570b0add8 | |||
|
1801bef019 | ||
0db5ebd7bf |
@@ -9,7 +9,8 @@
|
||||
],
|
||||
"rules": {
|
||||
"at-rule-no-unknown": null,
|
||||
"no-descending-specificity": null
|
||||
"no-descending-specificity": null,
|
||||
"declaration-colon-newline-after": "always-multi-line"
|
||||
},
|
||||
"syntax": "scss"
|
||||
}
|
72
CHANGELOG.md
72
CHANGELOG.md
@@ -2,6 +2,78 @@
|
||||
|
||||
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.3.1](https://github.com/Fabio286/antares/compare/v0.3.0...v0.3.1) (2021-07-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **UI:** tabs or explorebar elements selected with mouse wheel or right button ([a8a47ed](https://github.com/Fabio286/antares/commit/a8a47ed5f7d5d8cbbdd6c33ef8307d9dce5b193b))
|
||||
|
||||
## [0.3.0](https://github.com/Fabio286/antares/compare/v0.2.1...v0.3.0) (2021-07-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* close tabs if element deleted ([320aa8b](https://github.com/Fabio286/antares/commit/320aa8ba04d464f628b938b812165cd1ec786492))
|
||||
* new data tabs ([ab382df](https://github.com/Fabio286/antares/commit/ab382dfbcd89f8ab38a8cbdb4d87e1705618fd0d))
|
||||
* new function, procedure and scheduler tabs ([0a9983d](https://github.com/Fabio286/antares/commit/0a9983d30d6aeb9aee1c68b31a31f8c605deea45))
|
||||
* new trigger function tabs ([58b91eb](https://github.com/Fabio286/antares/commit/58b91ebfe0ab200d76d4cfd442b9f2970ae97384))
|
||||
* new trigger setting tabs ([f6faad9](https://github.com/Fabio286/antares/commit/f6faad98f88222500dfb7265b74c1be914b894cd))
|
||||
* new unsaved change reminder ([f7a74df](https://github.com/Fabio286/antares/commit/f7a74df0097867a82a2a2d8b3c278a81897d7898))
|
||||
* new view setting tabs ([003c02b](https://github.com/Fabio286/antares/commit/003c02b1fbe5aba7f53f3faa5610b0c2f7706793))
|
||||
* option to restore session on startup ([adc5477](https://github.com/Fabio286/antares/commit/adc5477673603cd63fabf77a53db5397e3774e0e))
|
||||
* option to select schema in query tabs ([a73a2f4](https://github.com/Fabio286/antares/commit/a73a2f483ef6927def4ba635e306277c34ae4b53))
|
||||
* **UI:** empty workspace view ([e1855a2](https://github.com/Fabio286/antares/commit/e1855a262dc24363fc143a38a70154938308bd71))
|
||||
* rename tabs if element is renamed ([ef21ea7](https://github.com/Fabio286/antares/commit/ef21ea74481839ba67ca79d40d5f47e1c12aebc0))
|
||||
* **MySQL:** improved schema detection for queries ([5bb4e49](https://github.com/Fabio286/antares/commit/5bb4e496f289f3ae8a46f24d1a2fbb896d9da86e))
|
||||
* **UI:** close temp data tabs ([88c4cdc](https://github.com/Fabio286/antares/commit/88c4cdc8e2a60ffbe26b0f831184c3a6dd9a1637))
|
||||
* **UI:** display schema in data tabs ([0105733](https://github.com/Fabio286/antares/commit/01057332b090997c107bf395bb1fc3b9195e8218))
|
||||
* **UI:** new table settings tabs ([7845e3e](https://github.com/Fabio286/antares/commit/7845e3e501bb7f890d07b42d4f3eb5f9f4bc8586))
|
||||
* **UI:** sortable tabs ([d38097d](https://github.com/Fabio286/antares/commit/d38097d0567020b5265b5a0b347f5e1f38e0b1d4))
|
||||
* **UI:** temporary table data tabs ([a87079c](https://github.com/Fabio286/antares/commit/a87079cd179033cebb6fd228ad7f1b991f3b6c46))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clear empty indexes and foreign keys on confirm respective modals ([04fa320](https://github.com/Fabio286/antares/commit/04fa320820df1f70a4ef05e4a6e4cbcd4081d047))
|
||||
* enabled copy context on non editable rows ([525c964](https://github.com/Fabio286/antares/commit/525c964c623e7574f6abe732a2b315b8805d5eee))
|
||||
* issues with trigger temp tabs ([6b725b1](https://github.com/Fabio286/antares/commit/6b725b1d40753ad89bfad6f1df57c6fb737e5262))
|
||||
* manual page input not disabled when only one page is available ([62f7e57](https://github.com/Fabio286/antares/commit/62f7e57d0ccf6041b5469bec6a1864aa5b045609))
|
||||
* new field default value unknown instead 'noval' ([77c5d28](https://github.com/Fabio286/antares/commit/77c5d280325792e20befc845f3a6834837131e39))
|
||||
* reload twice after element rename ([1e543aa](https://github.com/Fabio286/antares/commit/1e543aa6b0b63e9134bf544682a26bd98573b794))
|
||||
* solved a vulnerability in table names ([5c855a5](https://github.com/Fabio286/antares/commit/5c855a520a6bc66cc00b0b8afc6d2c03c75c0fab))
|
||||
* sort order of tables is lost switching pages ([14577d1](https://github.com/Fabio286/antares/commit/14577d14bb337898a1fd0fdee1c3760812b9d21f))
|
||||
* wrong editor height with some conditions ([d7fdf53](https://github.com/Fabio286/antares/commit/d7fdf53932a4d0609a88641c40d451c71b12c242))
|
||||
* **UI:** multiple trigger tabs open on single click on explore bar ([e78ca24](https://github.com/Fabio286/antares/commit/e78ca2417e8f996fa0507c5a5586a75393dfe8ee))
|
||||
* **UI:** not disabled buttons during save table setting tabs ([a0105cf](https://github.com/Fabio286/antares/commit/a0105cf1c37144ea27b212029d39275918f4f95e))
|
||||
* tab won't open after table or view creation ([f7c3aa8](https://github.com/Fabio286/antares/commit/f7c3aa883dfcad0a28222c53cf22ab49d381559c))
|
||||
* wrong loaded schema change ([c41e059](https://github.com/Fabio286/antares/commit/c41e059b0ba6d8c6d545c3b86a21a9a2abb6f537))
|
||||
* **UI:** table icon in view data tabs ([f0fa7c8](https://github.com/Fabio286/antares/commit/f0fa7c81b7aa2a05833ce0b243afed39db98d66b))
|
||||
|
||||
|
||||
### Improvements
|
||||
|
||||
* **UI:** improvements in setting bar connections sort ([0c29e0d](https://github.com/Fabio286/antares/commit/0c29e0d566c792ffd1b2b7045124e170b9c51985))
|
||||
|
||||
### [0.2.1](https://github.com/Fabio286/antares/compare/v0.2.0...v0.2.1) (2021-07-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **UI:** contextual menu shortcuts to create new elements on folders ([0252a06](https://github.com/Fabio286/antares/commit/0252a064d99df09b01c020c7d10c76dd43d4ede8))
|
||||
* context menu option to duplicate connections ([439356a](https://github.com/Fabio286/antares/commit/439356a01993a6a248f5a7d7df305ac5e0e63775))
|
||||
* **MySQL:** possibility to set a default schema in connection parameters ([c6897af](https://github.com/Fabio286/antares/commit/c6897af22d04ed930289a55124b3e8d080fbae3a))
|
||||
* **UI:** new connection add panel ([8cd76e7](https://github.com/Fabio286/antares/commit/8cd76e711c9328254d498b4f9afa221311f5a487))
|
||||
* **UI:** new connection edit panel ([9af71a6](https://github.com/Fabio286/antares/commit/9af71a6e343deda1bf79d8410511cf861af3c304))
|
||||
* SSH Tunnel functionality ([#81](https://github.com/Fabio286/antares/issues/81)) ([1801bef](https://github.com/Fabio286/antares/commit/1801bef019cee77a99df7e3822145ad952465abb))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* clear corrupted configurations to avoid exceptions ([56fcc26](https://github.com/Fabio286/antares/commit/56fcc2650b93ece398118f39f027dc9520dd8a6a))
|
||||
* **UI:** connection tab indicator when scrolling ([a0ab63b](https://github.com/Fabio286/antares/commit/a0ab63bdb533aac9b2bdc2ee07a3b1f2b70ea227))
|
||||
* avoid to trigger schema loading multiple times ([7570b0a](https://github.com/Fabio286/antares/commit/7570b0add8cb9130f15cf8cb807a96dbfd2837d0))
|
||||
|
||||
## [0.2.0](https://github.com/Fabio286/antares/compare/v0.1.13...v0.2.0) (2021-07-03)
|
||||
|
||||
|
||||
|
18
README.md
18
README.md
@@ -9,9 +9,9 @@
|
||||
Antares is an SQL client based on [Electron.js](https://github.com/electron/electron) and [Vue.js](https://github.com/vuejs/vue) that aims to become a useful tool, especially for developers.
|
||||
My target is to support as many databases as possible, and all major operating systems, including the ARM versions.
|
||||
|
||||
**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB and PostgreSQL (partially).
|
||||
Many of its current features are enough to have a pleasant user experience with MySQL/MariaDB, and basic functionalites with PostgreSQL, so give it a chance and send me your feedback, I would really appreciate it.
|
||||
I'm actively working on it, hoping to provide cool features and fixes as soon as possible.
|
||||
**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB and PostgreSQL.
|
||||
At the moment, however, there are all the features necessary to have a pleasant database management experience, so give it a chance and send us your feedback, we would really appreciate it.
|
||||
We are actively working on it, hoping to provide new cool features, improvements and fixes as soon as possible.
|
||||
|
||||
🔗 If you are curious to try Antares you can download and install the [latest release](https://github.com/Fabio286/antares/releases/latest).
|
||||
👁 To stay tuned for new releases [follow Antares SQL](https://twitter.com/AntaresSQL) on Twitter.
|
||||
@@ -19,9 +19,9 @@ I'm actively working on it, hoping to provide cool features and fixes as soon as
|
||||
|
||||
## Philosophy
|
||||
|
||||
Why am I developing an SQL client when there are a lot of them on the market?
|
||||
Why are we developing an SQL client when there are a lot of them on the market?
|
||||
The main goal is to develop a totally free, full featured, cross platform and open source alternative, empowered by JavaScript's ecosystem.
|
||||
A modern application created with minimalism and semplicity in mind, with features in the right places, not hundreds of tiny buttons, tabs or submenu.
|
||||
A modern application created with minimalism and semplicity in mind, with features in the right places, not hundreds of tiny buttons, nested tabs or submenu; productivity comes first.
|
||||
|
||||
## Download
|
||||
|
||||
@@ -43,6 +43,7 @@ A modern application created with minimalism and semplicity in mind, with featur
|
||||
- Fake table data filler.
|
||||
- Run queries on multiple tabs.
|
||||
- Query suggestions and auto complete.
|
||||
- SSH tunnel support.
|
||||
- Dark and light theme.
|
||||
- Scratchpad.
|
||||
- Multi language.
|
||||
@@ -54,13 +55,10 @@ This is a roadmap with major features will come in near future.
|
||||
|
||||
- Support for other databases.
|
||||
- Database tools.
|
||||
- SSH tunnel support.
|
||||
- Users management (add/edit/delete).
|
||||
- UI/UX improvements.
|
||||
- Query history.
|
||||
- Query history and bookmarks.
|
||||
- More context menu shortcuts.
|
||||
- More keyboard shortcuts.
|
||||
- Query logs console.
|
||||
- Import/export and migration.
|
||||
|
||||
## Currently supported
|
||||
@@ -68,7 +66,7 @@ This is a roadmap with major features will come in near future.
|
||||
### Databases
|
||||
|
||||
- [x] MySQL/MariaDB
|
||||
- [x] PostgreSQL (partially, work in progress)
|
||||
- [x] PostgreSQL
|
||||
- [ ] SQLite
|
||||
- [ ] MSSQL
|
||||
- [ ] OracleDB
|
||||
|
BIN
docs/gh-logo-2.png
Normal file
BIN
docs/gh-logo-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
BIN
docs/gh-logo.png
BIN
docs/gh-logo.png
Binary file not shown.
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 304 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "antares",
|
||||
"productName": "Antares",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.1",
|
||||
"description": "A cross-platform easy to use SQL client.",
|
||||
"license": "MIT",
|
||||
"repository": "https://github.com/Fabio286/antares.git",
|
||||
@@ -102,6 +102,7 @@
|
||||
"source-map-support": "^0.5.16",
|
||||
"spectre.css": "^0.5.9",
|
||||
"sql-formatter": "^4.0.2",
|
||||
"ssh2-promise": "^0.2.0",
|
||||
"v-mask": "^2.2.4",
|
||||
"vue-i18n": "^8.24.4",
|
||||
"vuedraggable": "^2.24.3",
|
||||
@@ -126,7 +127,7 @@
|
||||
"standard-version": "^9.3.0",
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"stylelint-scss": "^3.19.0",
|
||||
"stylelint-scss": "^3.20.1",
|
||||
"vue": "^2.6.14",
|
||||
"vue-template-compiler": "^2.6.14",
|
||||
"webpack": "^4.46.0"
|
||||
|
@@ -4,9 +4,7 @@ summary: Open source SQL client made to be simple and complete.
|
||||
description: |
|
||||
Antares is an SQL client that aims to become an useful and complete tool, especially for developers.
|
||||
The target is to support as many databases as possible, and all major operating systems, including the ARM versions.
|
||||
At the moment this application is an alpha and supports only MySQL and x86 architecture.
|
||||
Most of its current features might be enough for MySQL management, so give it a chance and send us your feedback, we would really appreciate it.
|
||||
base: core18
|
||||
base: core20
|
||||
|
||||
grade: stable
|
||||
confinement: strict
|
||||
@@ -60,6 +58,7 @@ parts:
|
||||
- fcitx-frontend-gtk3
|
||||
- libappindicator3-1
|
||||
- libasound2
|
||||
- libcurl4
|
||||
- libgconf-2-4
|
||||
- libgtk-3-0
|
||||
- libnotify4
|
||||
@@ -71,13 +70,59 @@ parts:
|
||||
- libsecret-1-0
|
||||
- libxtst6
|
||||
- libxkbfile1
|
||||
- gcc-10-base
|
||||
- libapparmor1
|
||||
- libblkid1
|
||||
- libbsd0
|
||||
- libcom-err2
|
||||
- libcrypt1
|
||||
- libdb5.3
|
||||
- libdbus-1-3
|
||||
- libexpat1
|
||||
- libffi7
|
||||
- libgcc-s1
|
||||
- libgcrypt20
|
||||
- libglib2.0-0
|
||||
- libgmp10
|
||||
- libgnutls30
|
||||
- libgpg-error0
|
||||
- libgssapi-krb5-2
|
||||
- libhogweed5
|
||||
- libidn2-0
|
||||
- libjson-c4
|
||||
- libk5crypto3
|
||||
- libkeyutils1
|
||||
- libkrb5-3
|
||||
- libkrb5support0
|
||||
- liblz4-1
|
||||
- liblzma5
|
||||
- libmount1
|
||||
- libnettle7
|
||||
- libp11-kit0
|
||||
- libpcre2-8-0
|
||||
- libselinux1
|
||||
- libsqlite3-0
|
||||
- libssl1.1
|
||||
- libstdc++6
|
||||
- libsystemd0
|
||||
- libtasn1-6
|
||||
- libudev1
|
||||
- libunistring2
|
||||
- libuuid1
|
||||
- libwrap0
|
||||
- libzstd1
|
||||
- zlib1g
|
||||
- libx11-xcb1
|
||||
- libdrm2
|
||||
- libgbm1
|
||||
- libxcb-dri3-0
|
||||
cleanup:
|
||||
after: [antares]
|
||||
plugin: nil
|
||||
build-snaps: [gnome-3-28-1804]
|
||||
build-snaps: [gnome-3-38-2004]
|
||||
override-prime: |
|
||||
set -eux
|
||||
cd /snap/gnome-3-28-1804/current
|
||||
cd /snap/gnome-3-38-2004/current
|
||||
find . -type f,l -exec rm -f $SNAPCRAFT_PRIME/{} \;
|
||||
|
||||
mdns-lookup:
|
||||
@@ -91,7 +136,7 @@ parts:
|
||||
- libnss-mdns
|
||||
override-prime: |
|
||||
set -eux
|
||||
sed -Ee 's/^\s*hosts:(\s+)files/hosts:\1files mdns4_minimal \[NOTFOUND=return\]/' /snap/core18/current/etc/nsswitch.conf > $SNAPCRAFT_STAGE/etc/nsswitch.conf
|
||||
sed -Ee 's/^\s*hosts:(\s+)files/hosts:\1files mdns4_minimal \[NOTFOUND=return\]/' /snap/core20/current/etc/nsswitch.conf > $SNAPCRAFT_STAGE/etc/nsswitch.conf
|
||||
snapcraftctl prime
|
||||
prime:
|
||||
- lib/$SNAPCRAFT_ARCH_TRIPLET/libnss_mdns4_minimal*
|
||||
@@ -101,7 +146,7 @@ apps:
|
||||
antares:
|
||||
command: opt/Antares/antares --no-sandbox
|
||||
desktop: usr/share/applications/antares.desktop
|
||||
extensions: [gnome-3-28]
|
||||
extensions: [gnome-3-38]
|
||||
environment:
|
||||
# Fallback to XWayland if running in a Wayland session.
|
||||
DISABLE_WAYLAND: 1
|
||||
|
@@ -7,6 +7,7 @@ module.exports = {
|
||||
database: false,
|
||||
collations: false,
|
||||
engines: false,
|
||||
connectionSchema: false,
|
||||
// Tools
|
||||
processesList: false,
|
||||
usersManagement: false,
|
||||
|
@@ -7,6 +7,7 @@ module.exports = {
|
||||
defaultUser: 'root',
|
||||
defaultDatabase: null,
|
||||
// Core
|
||||
connectionSchema: true,
|
||||
collations: true,
|
||||
engines: true,
|
||||
// Tools
|
||||
|
@@ -24,13 +24,23 @@ export default connections => {
|
||||
};
|
||||
}
|
||||
|
||||
const connection = ClientsFactory.getConnection({
|
||||
client: conn.client,
|
||||
params
|
||||
});
|
||||
if (conn.ssh) {
|
||||
params.ssh = {
|
||||
host: conn.sshHost,
|
||||
username: conn.sshUser,
|
||||
password: conn.sshPass,
|
||||
port: conn.sshPort ? conn.sshPort : 22,
|
||||
identity: conn.sshKey
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = await ClientsFactory.getConnection({
|
||||
client: conn.client,
|
||||
params
|
||||
});
|
||||
await connection.connect();
|
||||
|
||||
await connection.select('1+1').run();
|
||||
connection.destroy();
|
||||
|
||||
@@ -57,6 +67,9 @@ export default connections => {
|
||||
if (conn.database)
|
||||
params.database = conn.database;
|
||||
|
||||
if (conn.schema)
|
||||
params.schema = conn.schema;
|
||||
|
||||
if (conn.ssl) {
|
||||
params.ssl = {
|
||||
key: conn.key ? fs.readFileSync(conn.key) : null,
|
||||
@@ -66,6 +79,16 @@ export default connections => {
|
||||
};
|
||||
}
|
||||
|
||||
if (conn.ssh) {
|
||||
params.ssh = {
|
||||
host: conn.sshHost,
|
||||
username: conn.sshUser,
|
||||
password: conn.sshPass,
|
||||
port: conn.sshPort ? conn.sshPort : 22,
|
||||
identity: conn.sshKey
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const connection = ClientsFactory.getConnection({
|
||||
client: conn.client,
|
||||
|
@@ -128,7 +128,12 @@ export default connections => {
|
||||
if (!query) return;
|
||||
|
||||
try {
|
||||
const result = await connections[uid].raw(query, { nest: true, details: true, schema });
|
||||
const result = await connections[uid].raw(query, {
|
||||
nest: true,
|
||||
details: true,
|
||||
schema,
|
||||
comments: false
|
||||
});
|
||||
|
||||
return { status: 'success', response: result };
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ export default (connections) => {
|
||||
if (sortParams && sortParams.field && sortParams.dir)
|
||||
query.orderBy({ [sortParams.field]: sortParams.dir.toUpperCase() });
|
||||
|
||||
const result = await query.run({ details: true });
|
||||
const result = await query.run({ details: true, schema });
|
||||
|
||||
return { status: 'success', response: result };
|
||||
}
|
||||
|
@@ -12,6 +12,12 @@ export class ClientsFactory {
|
||||
* @param {String} args.params.host
|
||||
* @param {Number} args.params.port
|
||||
* @param {String} args.params.password
|
||||
* @param {String=} args.params.database
|
||||
* @param {String=} args.params.schema
|
||||
* @param {String} args.params.ssh.host
|
||||
* @param {String} args.params.ssh.username
|
||||
* @param {String} args.params.ssh.password
|
||||
* @param {Number} args.params.ssh.port
|
||||
* @param {Number=} args.poolSize
|
||||
* @returns Database Connection
|
||||
* @memberof ClientsFactory
|
||||
|
@@ -2,6 +2,7 @@
|
||||
import mysql from 'mysql2/promise';
|
||||
import { AntaresCore } from '../AntaresCore';
|
||||
import dataTypes from 'common/data-types/mysql';
|
||||
import * as SSH2Promise from 'ssh2-promise';
|
||||
|
||||
export class MySQLClient extends AntaresCore {
|
||||
constructor (args) {
|
||||
@@ -104,11 +105,33 @@ export class MySQLClient extends AntaresCore {
|
||||
async connect () {
|
||||
delete this._params.application_name;
|
||||
|
||||
const dbConfig = {
|
||||
host: this._params.host,
|
||||
port: this._params.port,
|
||||
user: this._params.user,
|
||||
password: this._params.password,
|
||||
ssl: null
|
||||
};
|
||||
|
||||
if (this._params.schema?.length) dbConfig.database = this._params.schema;
|
||||
|
||||
if (this._params.ssl) dbConfig.ssl = { ...this._params.ssl };
|
||||
|
||||
if (this._params.ssh) {
|
||||
this._ssh = new SSH2Promise({ ...this._params.ssh });
|
||||
|
||||
this._tunnel = await this._ssh.addTunnel({
|
||||
remoteAddr: this._params.host,
|
||||
remotePort: this._params.port
|
||||
});
|
||||
dbConfig.port = this._tunnel.localPort;
|
||||
}
|
||||
|
||||
if (!this._poolSize)
|
||||
this._connection = await mysql.createConnection(this._params);
|
||||
this._connection = await mysql.createConnection(dbConfig);
|
||||
else {
|
||||
this._connection = mysql.createPool({
|
||||
...this._params,
|
||||
...dbConfig,
|
||||
connectionLimit: this._poolSize,
|
||||
typeCast: (field, next) => {
|
||||
if (field.type === 'DATETIME')
|
||||
@@ -125,6 +148,7 @@ export class MySQLClient extends AntaresCore {
|
||||
*/
|
||||
destroy () {
|
||||
this._connection.end();
|
||||
if (this._ssh) this._ssh.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,6 +169,12 @@ export class MySQLClient extends AntaresCore {
|
||||
*/
|
||||
async getStructure (schemas) {
|
||||
const { rows: databases } = await this.raw('SHOW DATABASES');
|
||||
|
||||
let filteredDatabases = databases;
|
||||
|
||||
if (this._params.schema)
|
||||
filteredDatabases = filteredDatabases.filter(db => db.Database === this._params.schema);
|
||||
|
||||
const { rows: functions } = await this.raw('SHOW FUNCTION STATUS');
|
||||
const { rows: procedures } = await this.raw('SHOW PROCEDURE STATUS');
|
||||
const { rows: schedulers } = await this.raw('SELECT *, EVENT_SCHEMA AS `Db`, EVENT_NAME AS `Name` FROM information_schema.`EVENTS`');
|
||||
@@ -152,7 +182,7 @@ export class MySQLClient extends AntaresCore {
|
||||
const tablesArr = [];
|
||||
const triggersArr = [];
|
||||
|
||||
for (const db of databases) {
|
||||
for (const db of filteredDatabases) {
|
||||
if (!schemas.has(db.Database)) continue;
|
||||
|
||||
let { rows: tables } = await this.raw(`SHOW TABLE STATUS FROM \`${db.Database}\``);
|
||||
@@ -174,7 +204,7 @@ export class MySQLClient extends AntaresCore {
|
||||
}
|
||||
}
|
||||
|
||||
return databases.map(db => {
|
||||
return filteredDatabases.map(db => {
|
||||
if (schemas.has(db.Database)) {
|
||||
// TABLES
|
||||
const remappedTables = tablesArr.filter(table => table.Db === db.Database).map(table => {
|
||||
@@ -305,11 +335,11 @@ export class MySQLClient extends AntaresCore {
|
||||
.select('*')
|
||||
.schema('information_schema')
|
||||
.from('COLUMNS')
|
||||
.where({ TABLE_SCHEMA: `= '${this._schema || schema}'`, TABLE_NAME: `= '${table}'` })
|
||||
.where({ TABLE_SCHEMA: `= '${schema}'`, TABLE_NAME: `= '${table}'` })
|
||||
.orderBy({ ORDINAL_POSITION: 'ASC' })
|
||||
.run();
|
||||
|
||||
const { rows: fields } = await this.raw(`SHOW CREATE TABLE \`${this._schema || schema}\`.\`${table}\``);
|
||||
const { rows: fields } = await this.raw(`SHOW CREATE TABLE \`${schema}\`.\`${table}\``);
|
||||
|
||||
const remappedFields = fields.map(row => {
|
||||
if (!row['Create Table']) return false;
|
||||
@@ -333,15 +363,14 @@ export class MySQLClient extends AntaresCore {
|
||||
|
||||
const details = fieldArr.slice(2).join(' ');
|
||||
let defaultValue = null;
|
||||
if (details.includes('DEFAULT')) {
|
||||
if (details.includes('DEFAULT'))
|
||||
defaultValue = details.match(/(?<=DEFAULT ).*?$/gs)[0].split(' COMMENT')[0];
|
||||
const defaultValueArr = defaultValue.split('');
|
||||
if (defaultValueArr[0] === '\'') {
|
||||
defaultValueArr.shift();
|
||||
defaultValueArr.pop();
|
||||
defaultValue = defaultValueArr.join('');
|
||||
}
|
||||
}
|
||||
// const defaultValueArr = defaultValue.split('');
|
||||
// if (defaultValueArr[0] === '\'') {
|
||||
// defaultValueArr.shift();
|
||||
// defaultValueArr.pop();
|
||||
// defaultValue = defaultValueArr.join('');
|
||||
// }
|
||||
|
||||
const typeAndLength = nameAndType[1].replace(')', '').split('(');
|
||||
|
||||
@@ -544,7 +573,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async dropView (params) {
|
||||
const sql = `DROP VIEW \`${this._schema}\`.\`${params.view}\``;
|
||||
const sql = `DROP VIEW \`${params.schema}\`.\`${params.view}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -556,10 +585,10 @@ export class MySQLClient extends AntaresCore {
|
||||
*/
|
||||
async alterView (params) {
|
||||
const { view } = params;
|
||||
let sql = `ALTER ALGORITHM = ${view.algorithm}${view.definer ? ` DEFINER=${view.definer}` : ''} SQL SECURITY ${view.security} VIEW \`${this._schema}\`.\`${view.oldName}\` AS ${view.sql} ${view.updateOption ? `WITH ${view.updateOption} CHECK OPTION` : ''}`;
|
||||
let sql = `ALTER ALGORITHM = ${view.algorithm}${view.definer ? ` DEFINER=${view.definer}` : ''} SQL SECURITY ${view.security} VIEW \`${view.schema}\`.\`${view.oldName}\` AS ${view.sql} ${view.updateOption ? `WITH ${view.updateOption} CHECK OPTION` : ''}`;
|
||||
|
||||
if (view.name !== view.oldName)
|
||||
sql += `; RENAME TABLE \`${this._schema}\`.\`${view.oldName}\` TO \`${this._schema}\`.\`${view.name}\``;
|
||||
sql += `; RENAME TABLE \`${view.schema}\`.\`${view.oldName}\` TO \`${view.schema}\`.\`${view.name}\``;
|
||||
|
||||
return await this.raw(sql);
|
||||
}
|
||||
@@ -570,8 +599,8 @@ export class MySQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async createView (view) {
|
||||
const sql = `CREATE ALGORITHM = ${view.algorithm} ${view.definer ? `DEFINER=${view.definer} ` : ''}SQL SECURITY ${view.security} VIEW \`${this._schema}\`.\`${view.name}\` AS ${view.sql} ${view.updateOption ? `WITH ${view.updateOption} CHECK OPTION` : ''}`;
|
||||
async createView (params) {
|
||||
const sql = `CREATE ALGORITHM = ${params.algorithm} ${params.definer ? `DEFINER=${params.definer} ` : ''}SQL SECURITY ${params.security} VIEW \`${params.schema}\`.\`${params.name}\` AS ${params.sql} ${params.updateOption ? `WITH ${params.updateOption} CHECK OPTION` : ''}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -604,7 +633,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async dropTrigger (params) {
|
||||
const sql = `DROP TRIGGER \`${this._schema}\`.\`${params.trigger}\``;
|
||||
const sql = `DROP TRIGGER \`${params.schema}\`.\`${params.trigger}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -621,8 +650,8 @@ export class MySQLClient extends AntaresCore {
|
||||
|
||||
try {
|
||||
await this.createTrigger(tempTrigger);
|
||||
await this.dropTrigger({ trigger: tempTrigger.name });
|
||||
await this.dropTrigger({ trigger: trigger.oldName });
|
||||
await this.dropTrigger({ schema: trigger.schema, trigger: tempTrigger.name });
|
||||
await this.dropTrigger({ schema: trigger.schema, trigger: trigger.oldName });
|
||||
await this.createTrigger(trigger);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -636,8 +665,8 @@ export class MySQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async createTrigger (trigger) {
|
||||
const sql = `CREATE ${trigger.definer ? `DEFINER=${trigger.definer} ` : ''}TRIGGER \`${this._schema}\`.\`${trigger.name}\` ${trigger.activation} ${trigger.event} ON \`${trigger.table}\` FOR EACH ROW ${trigger.sql}`;
|
||||
async createTrigger (params) {
|
||||
const sql = `CREATE ${params.definer ? `DEFINER=${params.definer} ` : ''}TRIGGER \`${params.schema}\`.\`${params.name}\` ${params.activation} ${params.event} ON \`${params.table}\` FOR EACH ROW ${params.sql}`;
|
||||
return await this.raw(sql, { split: false });
|
||||
}
|
||||
|
||||
@@ -711,7 +740,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async dropRoutine (params) {
|
||||
const sql = `DROP PROCEDURE \`${this._schema}\`.\`${params.routine}\``;
|
||||
const sql = `DROP PROCEDURE \`${params.schema}\`.\`${params.routine}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -728,8 +757,8 @@ export class MySQLClient extends AntaresCore {
|
||||
|
||||
try {
|
||||
await this.createRoutine(tempProcedure);
|
||||
await this.dropRoutine({ routine: tempProcedure.name });
|
||||
await this.dropRoutine({ routine: routine.oldName });
|
||||
await this.dropRoutine({ schema: routine.schema, routine: tempProcedure.name });
|
||||
await this.dropRoutine({ schema: routine.schema, routine: routine.oldName });
|
||||
await this.createRoutine(routine);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -743,21 +772,21 @@ export class MySQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async createRoutine (routine) {
|
||||
const parameters = 'parameters' in routine
|
||||
? routine.parameters.reduce((acc, curr) => {
|
||||
async createRoutine (params) {
|
||||
const parameters = 'parameters' in params
|
||||
? params.parameters.reduce((acc, curr) => {
|
||||
acc.push(`${curr.context} \`${curr.name}\` ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||
return acc;
|
||||
}, []).join(',')
|
||||
: '';
|
||||
|
||||
const sql = `CREATE ${routine.definer ? `DEFINER=${routine.definer} ` : ''}PROCEDURE \`${this._schema}\`.\`${routine.name}\`(${parameters})
|
||||
const sql = `CREATE ${params.definer ? `DEFINER=${params.definer} ` : ''}PROCEDURE \`${params.schema}\`.\`${params.name}\`(${parameters})
|
||||
LANGUAGE SQL
|
||||
${routine.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}
|
||||
${routine.dataAccess}
|
||||
SQL SECURITY ${routine.security}
|
||||
COMMENT '${routine.comment}'
|
||||
${routine.sql}`;
|
||||
${params.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}
|
||||
${params.dataAccess}
|
||||
SQL SECURITY ${params.security}
|
||||
COMMENT '${params.comment}'
|
||||
${params.sql}`;
|
||||
|
||||
return await this.raw(sql, { split: false });
|
||||
}
|
||||
@@ -838,7 +867,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async dropFunction (params) {
|
||||
const sql = `DROP FUNCTION \`${this._schema}\`.\`${params.func}\``;
|
||||
const sql = `DROP FUNCTION \`${params.schema}\`.\`${params.func}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -855,8 +884,8 @@ export class MySQLClient extends AntaresCore {
|
||||
|
||||
try {
|
||||
await this.createFunction(tempProcedure);
|
||||
await this.dropFunction({ func: tempProcedure.name });
|
||||
await this.dropFunction({ func: func.oldName });
|
||||
await this.dropFunction({ schema: func.schema, func: tempProcedure.name });
|
||||
await this.dropFunction({ schema: func.schema, func: func.oldName });
|
||||
await this.createFunction(func);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -870,20 +899,20 @@ export class MySQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async createFunction (func) {
|
||||
const parameters = func.parameters.reduce((acc, curr) => {
|
||||
async createFunction (params) {
|
||||
const parameters = params.parameters.reduce((acc, curr) => {
|
||||
acc.push(`\`${curr.name}\` ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||
return acc;
|
||||
}, []).join(',');
|
||||
|
||||
const body = func.returns ? func.sql : 'BEGIN\n RETURN 0;\nEND';
|
||||
const body = params.returns ? params.sql : 'BEGIN\n RETURN 0;\nEND';
|
||||
|
||||
const sql = `CREATE ${func.definer ? `DEFINER=${func.definer} ` : ''}FUNCTION \`${this._schema}\`.\`${func.name}\`(${parameters}) RETURNS ${func.returns || 'SMALLINT'}${func.returnsLength ? `(${func.returnsLength})` : ''}
|
||||
const sql = `CREATE ${params.definer ? `DEFINER=${params.definer} ` : ''}FUNCTION \`${params.schema}\`.\`${params.name}\`(${parameters}) RETURNS ${params.returns || 'SMALLINT'}${params.returnsLength ? `(${params.returnsLength})` : ''}
|
||||
LANGUAGE SQL
|
||||
${func.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}
|
||||
${func.dataAccess}
|
||||
SQL SECURITY ${func.security}
|
||||
COMMENT '${func.comment}'
|
||||
${params.deterministic ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'}
|
||||
${params.dataAccess}
|
||||
SQL SECURITY ${params.security}
|
||||
COMMENT '${params.comment}'
|
||||
${body}`;
|
||||
|
||||
return await this.raw(sql, { split: false });
|
||||
@@ -930,7 +959,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async dropEvent (params) {
|
||||
const sql = `DROP EVENT \`${this._schema}\`.\`${params.scheduler}\``;
|
||||
const sql = `DROP EVENT \`${params.schema}\`.\`${params.scheduler}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -946,13 +975,13 @@ export class MySQLClient extends AntaresCore {
|
||||
if (scheduler.execution === 'EVERY' && scheduler.every[0].includes('-'))
|
||||
scheduler.every[0] = `'${scheduler.every[0]}'`;
|
||||
|
||||
const sql = `ALTER ${scheduler.definer ? ` DEFINER=${scheduler.definer}` : ''} EVENT \`${this._schema}\`.\`${scheduler.oldName}\`
|
||||
const sql = `ALTER ${scheduler.definer ? ` DEFINER=${scheduler.definer}` : ''} EVENT \`${scheduler.schema}\`.\`${scheduler.oldName}\`
|
||||
ON SCHEDULE
|
||||
${scheduler.execution === 'EVERY'
|
||||
? `EVERY ${scheduler.every.join(' ')}${scheduler.starts ? ` STARTS '${scheduler.starts}'` : ''}${scheduler.ends ? ` ENDS '${scheduler.ends}'` : ''}`
|
||||
: `AT '${scheduler.at}'`}
|
||||
ON COMPLETION${!scheduler.preserve ? ' NOT' : ''} PRESERVE
|
||||
${scheduler.name !== scheduler.oldName ? `RENAME TO \`${this._schema}\`.\`${scheduler.name}\`` : ''}
|
||||
${scheduler.name !== scheduler.oldName ? `RENAME TO \`${scheduler.schema}\`.\`${scheduler.name}\`` : ''}
|
||||
${scheduler.state}
|
||||
COMMENT '${scheduler.comment}'
|
||||
DO ${scheduler.sql}`;
|
||||
@@ -966,16 +995,16 @@ export class MySQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async createEvent (scheduler) {
|
||||
const sql = `CREATE ${scheduler.definer ? ` DEFINER=${scheduler.definer}` : ''} EVENT \`${this._schema}\`.\`${scheduler.name}\`
|
||||
async createEvent (params) {
|
||||
const sql = `CREATE ${params.definer ? ` DEFINER=${params.definer}` : ''} EVENT \`${params.schema}\`.\`${params.name}\`
|
||||
ON SCHEDULE
|
||||
${scheduler.execution === 'EVERY'
|
||||
? `EVERY ${scheduler.every.join(' ')}${scheduler.starts ? ` STARTS '${scheduler.starts}'` : ''}${scheduler.ends ? ` ENDS '${scheduler.ends}'` : ''}`
|
||||
: `AT '${scheduler.at}'`}
|
||||
ON COMPLETION${!scheduler.preserve ? ' NOT' : ''} PRESERVE
|
||||
${scheduler.state}
|
||||
COMMENT '${scheduler.comment}'
|
||||
DO ${scheduler.sql}`;
|
||||
${params.execution === 'EVERY'
|
||||
? `EVERY ${params.every.join(' ')}${params.starts ? ` STARTS '${params.starts}'` : ''}${params.ends ? ` ENDS '${params.ends}'` : ''}`
|
||||
: `AT '${params.at}'`}
|
||||
ON COMPLETION${!params.preserve ? ' NOT' : ''} PRESERVE
|
||||
${params.state}
|
||||
COMMENT '${params.comment}'
|
||||
DO ${params.sql}`;
|
||||
|
||||
return await this.raw(sql, { split: false });
|
||||
}
|
||||
@@ -1097,14 +1126,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async createTable (params) {
|
||||
const {
|
||||
name,
|
||||
collation,
|
||||
comment,
|
||||
engine
|
||||
} = params;
|
||||
|
||||
const sql = `CREATE TABLE \`${this._schema}\`.\`${name}\` (\`${name}_ID\` INT NULL) COMMENT='${comment}', COLLATE='${collation}', ENGINE=${engine}`;
|
||||
const sql = `CREATE TABLE \`${params.schema}\`.\`${params.name}\` (\`${params.name}_ID\` INT NULL) COMMENT='${params.comment}', COLLATE='${params.collation}', ENGINE=${params.engine}`;
|
||||
|
||||
return await this.raw(sql);
|
||||
}
|
||||
@@ -1118,6 +1140,7 @@ export class MySQLClient extends AntaresCore {
|
||||
async alterTable (params) {
|
||||
const {
|
||||
table,
|
||||
schema,
|
||||
additions,
|
||||
deletions,
|
||||
changes,
|
||||
@@ -1126,7 +1149,7 @@ export class MySQLClient extends AntaresCore {
|
||||
options
|
||||
} = params;
|
||||
|
||||
let sql = `ALTER TABLE \`${this._schema || params.options.schema}\`.\`${table}\` `;
|
||||
let sql = `ALTER TABLE \`${schema}\`.\`${table}\` `;
|
||||
const alterColumns = [];
|
||||
|
||||
// OPTIONS
|
||||
@@ -1238,7 +1261,7 @@ export class MySQLClient extends AntaresCore {
|
||||
sql += alterColumns.join(', ');
|
||||
|
||||
// RENAME
|
||||
if (options.name) sql += `; RENAME TABLE \`${this._schema}\`.\`${table}\` TO \`${this._schema}\`.\`${options.name}\``;
|
||||
if (options.name) sql += `; RENAME TABLE \`${schema}\`.\`${table}\` TO \`${schema}\`.\`${options.name}\``;
|
||||
|
||||
return await this.raw(sql);
|
||||
}
|
||||
@@ -1250,7 +1273,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async duplicateTable (params) {
|
||||
const sql = `CREATE TABLE \`${this._schema}\`.\`${params.table}_copy\` LIKE \`${this._schema}\`.\`${params.table}\``;
|
||||
const sql = `CREATE TABLE \`${params.schema}\`.\`${params.table}_copy\` LIKE \`${params.schema}\`.\`${params.table}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -1261,7 +1284,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async truncateTable (params) {
|
||||
const sql = `TRUNCATE TABLE \`${this._schema}\`.\`${params.table}\``;
|
||||
const sql = `TRUNCATE TABLE \`${params.schema}\`.\`${params.table}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -1272,7 +1295,7 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async dropTable (params) {
|
||||
const sql = `DROP TABLE \`${this._schema}\`.\`${params.table}\``;
|
||||
const sql = `DROP TABLE \`${params.schema}\`.\`${params.table}\``;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -1343,16 +1366,19 @@ export class MySQLClient extends AntaresCore {
|
||||
* @memberof MySQLClient
|
||||
*/
|
||||
async raw (sql, args) {
|
||||
sql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '');
|
||||
if (process.env.NODE_ENV === 'development') this._logger(sql);// TODO: replace BLOB content with a placeholder
|
||||
|
||||
args = {
|
||||
nest: false,
|
||||
details: false,
|
||||
split: true,
|
||||
comments: true,
|
||||
...args
|
||||
};
|
||||
|
||||
if (!args.comments)
|
||||
sql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '');// Remove comments
|
||||
|
||||
const nestTables = args.nest ? '.' : false;
|
||||
const resultsArr = [];
|
||||
let paramsArr = [];
|
||||
@@ -1389,7 +1415,7 @@ export class MySQLClient extends AntaresCore {
|
||||
name: field.orgName,
|
||||
alias: field.name,
|
||||
orgName: field.orgName,
|
||||
schema: field.schema,
|
||||
schema: args.schema || field.schema,
|
||||
table: field.table,
|
||||
tableAlias: field.table,
|
||||
orgTable: field.orgTable,
|
||||
|
@@ -3,6 +3,7 @@ import { Pool, Client, types } from 'pg';
|
||||
import { parse } from 'pgsql-ast-parser';
|
||||
import { AntaresCore } from '../AntaresCore';
|
||||
import dataTypes from 'common/data-types/postgresql';
|
||||
import * as SSH2Promise from 'ssh2-promise';
|
||||
|
||||
function pgToString (value) {
|
||||
return value.toString();
|
||||
@@ -51,13 +52,35 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async connect () {
|
||||
const dbConfig = {
|
||||
host: this._params.host,
|
||||
port: this._params.port,
|
||||
user: this._params.user,
|
||||
password: this._params.password,
|
||||
ssl: null
|
||||
};
|
||||
|
||||
if (this._params.database?.length) dbConfig.database = this._params.database;
|
||||
|
||||
if (this._params.ssl) dbConfig.ssl = { ...this._params.ssl };
|
||||
|
||||
if (this._params.ssh) {
|
||||
this._ssh = new SSH2Promise({ ...this._params.ssh });
|
||||
|
||||
this._tunnel = await this._ssh.addTunnel({
|
||||
remoteAddr: this._params.host,
|
||||
remotePort: this._params.port
|
||||
});
|
||||
dbConfig.port = this._tunnel.localPort;
|
||||
}
|
||||
|
||||
if (!this._poolSize) {
|
||||
const client = new Client(this._params);
|
||||
const client = new Client(dbConfig);
|
||||
await client.connect();
|
||||
this._connection = client;
|
||||
}
|
||||
else {
|
||||
const pool = new Pool({ ...this._params, max: this._poolSize });
|
||||
const pool = new Pool({ ...dbConfig, max: this._poolSize });
|
||||
this._connection = pool;
|
||||
}
|
||||
}
|
||||
@@ -67,6 +90,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
*/
|
||||
destroy () {
|
||||
this._connection.end();
|
||||
if (this._ssh) this._ssh.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -459,7 +483,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropView (params) {
|
||||
const sql = `DROP VIEW ${this._schema}.${params.view}`;
|
||||
const sql = `DROP VIEW ${params.schema}.${params.view}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -471,10 +495,10 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
*/
|
||||
async alterView (params) {
|
||||
const { view } = params;
|
||||
let sql = `CREATE OR REPLACE VIEW ${this._schema}.${view.oldName} AS ${view.sql}`;
|
||||
let sql = `CREATE OR REPLACE VIEW ${view.schema}.${view.oldName} AS ${view.sql}`;
|
||||
|
||||
if (view.name !== view.oldName)
|
||||
sql += `; ALTER VIEW ${this._schema}.${view.oldName} RENAME TO ${view.name}`;
|
||||
sql += `; ALTER VIEW ${view.schema}.${view.oldName} RENAME TO ${view.name}`;
|
||||
|
||||
return await this.raw(sql);
|
||||
}
|
||||
@@ -485,8 +509,8 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async createView (view) {
|
||||
const sql = `CREATE VIEW ${this._schema}.${view.name} AS ${view.sql}`;
|
||||
async createView (params) {
|
||||
const sql = `CREATE VIEW ${params.schema}.${params.name} AS ${params.sql}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -536,7 +560,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
*/
|
||||
async dropTrigger (params) {
|
||||
const triggerParts = params.trigger.split('.');
|
||||
const sql = `DROP TRIGGER "${triggerParts[1]}" ON "${triggerParts[0]}"`;
|
||||
const sql = `DROP TRIGGER "${triggerParts[1]}" ON "${params.schema}"."${triggerParts[0]}"`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -553,8 +577,8 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
|
||||
try {
|
||||
await this.createTrigger(tempTrigger);
|
||||
await this.dropTrigger({ trigger: `${tempTrigger.table}.${tempTrigger.name}` });
|
||||
await this.dropTrigger({ trigger: `${trigger.table}.${trigger.oldName}` });
|
||||
await this.dropTrigger({ schema: trigger.schema, trigger: `${tempTrigger.table}.${tempTrigger.name}` });
|
||||
await this.dropTrigger({ schema: trigger.schema, trigger: `${trigger.table}.${trigger.oldName}` });
|
||||
await this.createTrigger(trigger);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -568,9 +592,9 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @returns {Array.<Object>} parameters
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async createTrigger (trigger) {
|
||||
const eventsString = Array.isArray(trigger.event) ? trigger.event.join(' OR ') : trigger.event;
|
||||
const sql = `CREATE TRIGGER "${trigger.name}" ${trigger.activation} ${eventsString} ON "${trigger.table}" FOR EACH ROW ${trigger.sql}`;
|
||||
async createTrigger (params) {
|
||||
const eventsString = Array.isArray(params.event) ? params.event.join(' OR ') : params.event;
|
||||
const sql = `CREATE TRIGGER "${params.name}" ${params.activation} ${eventsString} ON "${params.schema}"."${params.table}" FOR EACH ROW ${params.sql}`;
|
||||
return await this.raw(sql, { split: false });
|
||||
}
|
||||
|
||||
@@ -613,6 +637,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
AND proc.routine_type = 'PROCEDURE'
|
||||
AND proc.routine_name = '${routine}'
|
||||
AND proc.specific_schema = '${schema}'
|
||||
AND args.data_type != NULL
|
||||
ORDER BY procedure_schema,
|
||||
specific_name,
|
||||
procedure_name,
|
||||
@@ -651,7 +676,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropRoutine (params) {
|
||||
const sql = `DROP PROCEDURE ${this._schema}.${params.routine}`;
|
||||
const sql = `DROP PROCEDURE "${params.schema}"."${params.routine}"`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -668,8 +693,8 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
|
||||
try {
|
||||
await this.createRoutine(tempProcedure);
|
||||
await this.dropRoutine({ routine: tempProcedure.name });
|
||||
await this.dropRoutine({ routine: routine.oldName });
|
||||
await this.dropRoutine({ schema: routine.schema, routine: tempProcedure.name });
|
||||
await this.dropRoutine({ schema: routine.schema, routine: routine.oldName });
|
||||
await this.createRoutine(routine);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -691,10 +716,10 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
}, []).join(',')
|
||||
: '';
|
||||
|
||||
if (this._schema !== 'public')
|
||||
await this.use(this._schema);
|
||||
if (routine.schema !== 'public')
|
||||
await this.use(routine.schema);
|
||||
|
||||
const sql = `CREATE PROCEDURE ${this._schema}.${routine.name}(${parameters})
|
||||
const sql = `CREATE PROCEDURE "${routine.schema}"."${routine.name}"(${parameters})
|
||||
LANGUAGE ${routine.language}
|
||||
SECURITY ${routine.security}
|
||||
AS ${routine.sql}`;
|
||||
@@ -780,7 +805,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropFunction (params) {
|
||||
const sql = `DROP FUNCTION ${this._schema}.${params.func}`;
|
||||
const sql = `DROP FUNCTION "${params.schema}"."${params.func}"`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -797,8 +822,8 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
|
||||
try {
|
||||
await this.createFunction(tempProcedure);
|
||||
await this.dropFunction({ func: tempProcedure.name });
|
||||
await this.dropFunction({ func: func.oldName });
|
||||
await this.dropFunction({ schema: func.schema, func: tempProcedure.name });
|
||||
await this.dropFunction({ schema: func.schema, func: func.oldName });
|
||||
await this.createFunction(func);
|
||||
}
|
||||
catch (err) {
|
||||
@@ -815,17 +840,17 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
async createFunction (func) {
|
||||
const parameters = 'parameters' in func
|
||||
? func.parameters.reduce((acc, curr) => {
|
||||
acc.push(`${curr.context} ${curr.name} ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||
acc.push(`${curr.context} ${curr.name || ''} ${curr.type}${curr.length ? `(${curr.length})` : ''}`);
|
||||
return acc;
|
||||
}, []).join(',')
|
||||
: '';
|
||||
|
||||
if (this._schema !== 'public')
|
||||
await this.use(this._schema);
|
||||
if (func.schema !== 'public')
|
||||
await this.use(func.schema);
|
||||
|
||||
const body = func.returns ? func.sql : '$function$\n$function$';
|
||||
|
||||
const sql = `CREATE FUNCTION ${this._schema}.${func.name}(${parameters})
|
||||
const sql = `CREATE FUNCTION "${func.schema}"."${func.name}" (${parameters})
|
||||
RETURNS ${func.returns || 'void'}
|
||||
LANGUAGE ${func.language}
|
||||
SECURITY ${func.security}
|
||||
@@ -843,12 +868,12 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
async alterTriggerFunction (params) {
|
||||
const { func } = params;
|
||||
|
||||
if (this._schema !== 'public')
|
||||
await this.use(this._schema);
|
||||
if (func.schema !== 'public')
|
||||
await this.use(func.schema);
|
||||
|
||||
const body = func.returns ? func.sql : '$function$\n$function$';
|
||||
|
||||
const sql = `CREATE OR REPLACE FUNCTION ${this._schema}.${func.name}()
|
||||
const sql = `CREATE OR REPLACE FUNCTION "${func.schema}"."${func.name}" ()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE ${func.language}
|
||||
AS ${body}`;
|
||||
@@ -863,12 +888,12 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async createTriggerFunction (func) {
|
||||
if (this._schema !== 'public')
|
||||
await this.use(this._schema);
|
||||
if (func.schema !== 'public')
|
||||
await this.use(func.schema);
|
||||
|
||||
const body = func.returns ? func.sql : '$function$\r\nBEGIN\r\n\r\nEND\r\n$function$';
|
||||
|
||||
const sql = `CREATE FUNCTION ${this._schema}.${func.name}()
|
||||
const sql = `CREATE FUNCTION "${func.schema}"."${func.name}" ()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE ${func.language}
|
||||
AS ${body}`;
|
||||
@@ -964,11 +989,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async createTable (params) {
|
||||
const {
|
||||
name
|
||||
} = params;
|
||||
|
||||
const sql = `CREATE TABLE ${this._schema}.${name} (${name}_id INTEGER NULL); ALTER TABLE ${this._schema}.${name} DROP COLUMN ${name}_id`;
|
||||
const sql = `CREATE TABLE "${params.schema}"."${params.name}" (${params.name}_id INTEGER NULL); ALTER TABLE "${params.schema}"."${params.name}" DROP COLUMN ${params.name}_id`;
|
||||
|
||||
return await this.raw(sql);
|
||||
}
|
||||
@@ -982,6 +1003,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
async alterTable (params) {
|
||||
const {
|
||||
table,
|
||||
schema,
|
||||
additions,
|
||||
deletions,
|
||||
changes,
|
||||
@@ -990,8 +1012,8 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
options
|
||||
} = params;
|
||||
|
||||
if (this._schema !== 'public')
|
||||
await this.use(this._schema);
|
||||
if (schema !== 'public')
|
||||
await this.use(schema);
|
||||
|
||||
let sql = '';
|
||||
const alterColumns = [];
|
||||
@@ -1032,7 +1054,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
else if (type === 'UNIQUE')
|
||||
alterColumns.push(`ADD CONSTRAINT ${addition.name} UNIQUE (${fields})`);
|
||||
else
|
||||
manageIndexes.push(`CREATE INDEX ${addition.name} ON ${this._schema}.${table}(${fields})`);
|
||||
manageIndexes.push(`CREATE INDEX ${addition.name} ON "${schema}"."${table}" (${fields})`);
|
||||
});
|
||||
|
||||
// ADD FOREIGN KEYS
|
||||
@@ -1070,7 +1092,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
}
|
||||
|
||||
if (change.orgName !== change.name)
|
||||
renameColumns.push(`ALTER TABLE "${this._schema}"."${table}" RENAME COLUMN "${change.orgName}" TO "${change.name}"`);
|
||||
renameColumns.push(`ALTER TABLE "${schema}"."${table}" RENAME COLUMN "${change.orgName}" TO "${change.name}"`);
|
||||
});
|
||||
|
||||
// CHANGE INDEX
|
||||
@@ -1088,7 +1110,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
else if (type === 'UNIQUE')
|
||||
alterColumns.push(`ADD CONSTRAINT ${change.name} UNIQUE (${fields})`);
|
||||
else
|
||||
manageIndexes.push(`CREATE INDEX ${change.name} ON ${this._schema}.${table}(${fields})`);
|
||||
manageIndexes.push(`CREATE INDEX ${change.name} ON "${schema}"."${table}" (${fields})`);
|
||||
});
|
||||
|
||||
// CHANGE FOREIGN KEYS
|
||||
@@ -1115,10 +1137,10 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
alterColumns.push(`DROP CONSTRAINT ${deletion.constraintName}`);
|
||||
});
|
||||
|
||||
if (alterColumns.length) sql += `ALTER TABLE "${this._schema}"."${table}" ${alterColumns.join(', ')}; `;
|
||||
if (alterColumns.length) sql += `ALTER TABLE "${schema}"."${table}" ${alterColumns.join(', ')}; `;
|
||||
if (createSequences.length) sql = `${createSequences.join(';')}; ${sql}`;
|
||||
if (manageIndexes.length) sql = `${manageIndexes.join(';')}; ${sql}`;
|
||||
if (options.name) sql += `ALTER TABLE "${this._schema}"."${table}" RENAME TO "${options.name}"; `;
|
||||
if (options.name) sql += `ALTER TABLE "${schema}"."${table}" RENAME TO "${options.name}"; `;
|
||||
|
||||
// RENAME
|
||||
if (renameColumns.length) sql = `${renameColumns.join(';')}; ${sql}`;
|
||||
@@ -1133,7 +1155,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async duplicateTable (params) {
|
||||
const sql = `CREATE TABLE ${this._schema}.${params.table}_copy (LIKE ${this._schema}.${params.table} INCLUDING ALL)`;
|
||||
const sql = `CREATE TABLE ${params.schema}.${params.table}_copy (LIKE ${params.schema}.${params.table} INCLUDING ALL)`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -1144,7 +1166,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async truncateTable (params) {
|
||||
const sql = `TRUNCATE TABLE ${this._schema}.${params.table}`;
|
||||
const sql = `TRUNCATE TABLE ${params.schema}.${params.table}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -1155,7 +1177,7 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async dropTable (params) {
|
||||
const sql = `DROP TABLE ${this._schema}.${params.table}`;
|
||||
const sql = `DROP TABLE ${params.schema}.${params.table}`;
|
||||
return await this.raw(sql);
|
||||
}
|
||||
|
||||
@@ -1226,18 +1248,20 @@ export class PostgreSQLClient extends AntaresCore {
|
||||
* @memberof PostgreSQLClient
|
||||
*/
|
||||
async raw (sql, args) {
|
||||
sql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '');
|
||||
|
||||
args = {
|
||||
nest: false,
|
||||
details: false,
|
||||
split: true,
|
||||
comments: true,
|
||||
...args
|
||||
};
|
||||
|
||||
if (args.schema && args.schema !== 'public')
|
||||
await this.use(args.schema);
|
||||
|
||||
if (!args.comments)
|
||||
sql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '');// Remove comments
|
||||
|
||||
const resultsArr = [];
|
||||
let paramsArr = [];
|
||||
const queries = args.split
|
||||
|
@@ -4,22 +4,20 @@
|
||||
<div id="window-content">
|
||||
<TheSettingBar />
|
||||
<div id="main-content" class="container">
|
||||
<TheAppWelcome v-if="!connections.length" @new-conn="showNewConnModal" />
|
||||
<div v-else class="columns col-gapless">
|
||||
<div class="columns col-gapless">
|
||||
<Workspace
|
||||
v-for="connection in connections"
|
||||
:key="connection.uid"
|
||||
:connection="connection"
|
||||
/>
|
||||
<WorkspaceAddConnectionPanel v-if="selectedWorkspace === 'NEW'" />
|
||||
</div>
|
||||
<TheFooter />
|
||||
<TheNotificationsBoard />
|
||||
<TheScratchpad v-if="isScratchpad" />
|
||||
<ModalSettings v-if="isSettingModal" />
|
||||
<BaseTextEditor class="d-none" value="" />
|
||||
</div>
|
||||
<TheFooter />
|
||||
<TheNotificationsBoard />
|
||||
<ModalNewConnection v-if="isNewConnModal" />
|
||||
<TheScratchpad v-if="isScratchpad" />
|
||||
<ModalSettings v-if="isSettingModal" />
|
||||
<ModalDiscardChanges v-if="isUnsavedDiscardModal" />
|
||||
<BaseTextEditor class="d-none" value="" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -36,12 +34,10 @@ export default {
|
||||
TheSettingBar: () => import(/* webpackChunkName: "TheSettingBar" */'@/components/TheSettingBar'),
|
||||
TheFooter: () => import(/* webpackChunkName: "TheFooter" */'@/components/TheFooter'),
|
||||
TheNotificationsBoard: () => import(/* webpackChunkName: "TheNotificationsBoard" */'@/components/TheNotificationsBoard'),
|
||||
TheAppWelcome: () => import(/* webpackChunkName: "TheAppWelcome" */'@/components/TheAppWelcome'),
|
||||
Workspace: () => import(/* webpackChunkName: "Workspace" */'@/components/Workspace'),
|
||||
ModalNewConnection: () => import(/* webpackChunkName: "ModalNewConnection" */'@/components/ModalNewConnection'),
|
||||
WorkspaceAddConnectionPanel: () => import(/* webpackChunkName: "WorkspaceAddConnectionPanel" */'@/components/WorkspaceAddConnectionPanel'),
|
||||
ModalSettings: () => import(/* webpackChunkName: "ModalSettings" */'@/components/ModalSettings'),
|
||||
TheScratchpad: () => import(/* webpackChunkName: "TheScratchpad" */'@/components/TheScratchpad'),
|
||||
ModalDiscardChanges: () => import(/* webpackChunkName: "ModalDiscardChanges" */'@/components/ModalDiscardChanges'),
|
||||
BaseTextEditor: () => import(/* webpackChunkName: "BaseTextEditor" */'@/components/BaseTextEditor')
|
||||
},
|
||||
data () {
|
||||
@@ -49,9 +45,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
isLoading: 'application/isLoading',
|
||||
isNewConnModal: 'application/isNewModal',
|
||||
isEditModal: 'application/isEditModal',
|
||||
isSettingModal: 'application/isSettingModal',
|
||||
isScratchpad: 'application/isScratchpad',
|
||||
connections: 'connections/getConnections',
|
||||
|
@@ -41,7 +41,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer text-light">
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary mr-2" @click.stop="sendCredentials">
|
||||
{{ $t('word.send') }}
|
||||
</button>
|
||||
|
@@ -2,8 +2,8 @@
|
||||
<ConfirmModal
|
||||
:confirm-text="$t('word.discard')"
|
||||
:cancel-text="$t('word.stay')"
|
||||
@confirm="discardUnsavedChanges"
|
||||
@hide="closeUnsavedChangesModal"
|
||||
@confirm="$emit('confirm')"
|
||||
@hide="$emit('close')"
|
||||
>
|
||||
<template slot="header">
|
||||
<div class="d-flex">
|
||||
@@ -19,7 +19,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
|
||||
export default {
|
||||
@@ -34,13 +33,6 @@ export default {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
discardUnsavedChanges: 'workspaces/discardUnsavedChanges',
|
||||
closeUnsavedChangesModal: 'workspaces/closeUnsavedChangesModal'
|
||||
}),
|
||||
closeModal () {
|
||||
this.$emit('close');
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
|
@@ -1,391 +0,0 @@
|
||||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay c-hand" @click="closeModal" />
|
||||
<div class="modal-container">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-server mr-1" /> {{ $t('message.editConnection') }}
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<div class="panel">
|
||||
<div class="panel-nav">
|
||||
<ul class="tab tab-block">
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'general'}"
|
||||
@click="selectTab('general')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.general') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssl'}"
|
||||
@click="selectTab('ssl')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.ssl') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'general'" class="panel-body py-0">
|
||||
<div class="container">
|
||||
<form class="form-horizontal">
|
||||
<fieldset class="m-0" :disabled="isTesting">
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.connectionName') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="localConnection.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<select v-model="localConnection.client" class="form-select">
|
||||
<option value="mysql">
|
||||
MySQL
|
||||
</option>
|
||||
<option value="maria">
|
||||
MariaDB
|
||||
</option>
|
||||
<option value="pg">
|
||||
PostgreSQL
|
||||
</option>
|
||||
<!-- <option value="mssql">
|
||||
Microsoft SQL
|
||||
</option>
|
||||
<option value="oracledb">
|
||||
Oracle DB
|
||||
</option> -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.host"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.port"
|
||||
class="form-input"
|
||||
type="number"
|
||||
min="1"
|
||||
max="65535"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.database" class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.database') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.database"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.user"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:disabled="localConnection.ask"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.password"
|
||||
class="form-input"
|
||||
type="password"
|
||||
:disabled="localConnection.ask"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12" />
|
||||
<div class="col-8 col-sm-12">
|
||||
<label class="form-checkbox form-inline">
|
||||
<input v-model="localConnection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<BaseToast
|
||||
class="mb-2"
|
||||
:message="toast.message"
|
||||
:status="toast.status"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'ssl'" class="panel-body py-0">
|
||||
<div class="container">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.enableSsl') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleSsl">
|
||||
<input type="checkbox" :checked="localConnection.ssl">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="m-0" :disabled="isTesting || !localConnection.ssl">
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="localConnection.key"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('key')"
|
||||
@change="pathSelection($event, 'key')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.certificate') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="localConnection.cert"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('cert')"
|
||||
@change="pathSelection($event, 'cert')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.caCertificate') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="localConnection.ca"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('ca')"
|
||||
@change="pathSelection($event, 'ca')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.ciphers') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="localConnection.ciphers"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<BaseToast
|
||||
class="mb-2"
|
||||
:message="toast.message"
|
||||
:status="toast.status"
|
||||
/>
|
||||
</div>
|
||||
<div class="modal-footer text-light">
|
||||
<button
|
||||
class="btn btn-gray mr-2"
|
||||
:class="{'loading': isTesting}"
|
||||
@click="startTest"
|
||||
>
|
||||
{{ $t('message.testConnection') }}
|
||||
</button>
|
||||
<button class="btn btn-primary mr-2" @click="saveEditConnection">
|
||||
{{ $t('word.save') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ModalAskCredentials
|
||||
v-if="isAsking"
|
||||
@close-asking="closeAsking"
|
||||
@credentials="continueTest"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import customizations from 'common/customizations';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseToast from '@/components/BaseToast';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
|
||||
export default {
|
||||
name: 'ModalEditConnection',
|
||||
components: {
|
||||
ModalAskCredentials,
|
||||
BaseToast,
|
||||
BaseUploadInput
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
toast: {
|
||||
status: '',
|
||||
message: ''
|
||||
},
|
||||
isTesting: false,
|
||||
isAsking: false,
|
||||
localConnection: null,
|
||||
selectedTab: 'general'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
customizations () {
|
||||
return customizations[this.connection.client];
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.localConnection = Object.assign({}, this.connection);
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
|
||||
setTimeout(() => {
|
||||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
editConnection: 'connections/editConnection'
|
||||
}),
|
||||
async startTest () {
|
||||
this.isTesting = true;
|
||||
this.toast = {
|
||||
status: '',
|
||||
message: ''
|
||||
};
|
||||
|
||||
if (this.localConnection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
try {
|
||||
const res = await Connection.makeTest(this.localConnection);
|
||||
if (res.status === 'error')
|
||||
this.toast = { status: 'error', message: res.response.message };
|
||||
else
|
||||
this.toast = { status: 'success', message: this.$t('message.connectionSuccessfullyMade') };
|
||||
}
|
||||
catch (err) {
|
||||
this.toast = { status: 'error', message: err.stack };
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
}
|
||||
},
|
||||
async continueTest (credentials) { // if "Ask for credentials" is true
|
||||
this.isAsking = false;
|
||||
const params = Object.assign({}, this.localConnection, credentials);
|
||||
try {
|
||||
const res = await Connection.makeTest(params);
|
||||
if (res.status === 'error')
|
||||
this.toast = { status: 'error', message: res.response.message };
|
||||
else
|
||||
this.toast = { status: 'success', message: this.$t('message.connectionSuccessfullyMade') };
|
||||
}
|
||||
catch (err) {
|
||||
this.toast = { status: 'error', message: err.stack };
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
},
|
||||
saveEditConnection () {
|
||||
this.editConnection(this.localConnection);
|
||||
this.closeModal();
|
||||
},
|
||||
closeAsking () {
|
||||
this.isTesting = false;
|
||||
this.isAsking = false;
|
||||
},
|
||||
closeModal () {
|
||||
this.$emit('close');
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
selectTab (tab) {
|
||||
this.selectedTab = tab;
|
||||
},
|
||||
toggleSsl () {
|
||||
this.localConnection.ssl = !this.localConnection.ssl;
|
||||
},
|
||||
pathSelection (event, name) {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
this.localConnection[name] = files[0].path;
|
||||
},
|
||||
pathClear (name) {
|
||||
this.localConnection[name] = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-container {
|
||||
position: absolute;
|
||||
max-width: 450px;
|
||||
top: 17.5vh;
|
||||
}
|
||||
</style>
|
@@ -53,7 +53,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer text-light">
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary mr-2" @click.stop="updateSchema">
|
||||
{{ $t('word.update') }}
|
||||
</button>
|
||||
@@ -72,7 +72,7 @@ import Schema from '@/ipc-api/Schema';
|
||||
export default {
|
||||
name: 'ModalEditSchema',
|
||||
props: {
|
||||
selectedDatabase: String
|
||||
selectedSchema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -99,7 +99,7 @@ export default {
|
||||
async created () {
|
||||
let actualCollation;
|
||||
try {
|
||||
const { status, response } = await Schema.getDatabaseCollation({ uid: this.selectedWorkspace, database: this.selectedDatabase });
|
||||
const { status, response } = await Schema.getDatabaseCollation({ uid: this.selectedWorkspace, database: this.selectedSchema });
|
||||
|
||||
if (status === 'success')
|
||||
actualCollation = response;
|
||||
@@ -112,8 +112,8 @@ export default {
|
||||
}
|
||||
|
||||
this.database = {
|
||||
name: this.selectedDatabase,
|
||||
prevName: this.selectedDatabase,
|
||||
name: this.selectedSchema,
|
||||
prevName: this.selectedSchema,
|
||||
collation: actualCollation || this.defaultCollation,
|
||||
prevCollation: actualCollation || this.defaultCollation
|
||||
};
|
||||
|
@@ -52,7 +52,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer text-light columns">
|
||||
<div class="modal-footer columns">
|
||||
<div class="column d-flex" :class="hasFakes ? 'col-4' : 'col-2'">
|
||||
<div class="input-group tooltip tooltip-right" :data-tooltip="$t('message.numberOfInserts')">
|
||||
<input
|
||||
|
@@ -1,415 +0,0 @@
|
||||
<template>
|
||||
<div class="modal active">
|
||||
<a class="modal-overlay c-hand" @click="closeModal" />
|
||||
<div class="modal-container">
|
||||
<div class="modal-header pl-2">
|
||||
<div class="modal-title h6">
|
||||
<div class="d-flex">
|
||||
<i class="mdi mdi-24px mdi-server-plus mr-1" />
|
||||
<span class="cut-text">{{ $t('message.createNewConnection') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn btn-clear c-hand" @click="closeModal" />
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<div class="panel">
|
||||
<div class="panel-nav">
|
||||
<ul class="tab tab-block">
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'general'}"
|
||||
@click="selectTab('general')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.general') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssl'}"
|
||||
@click="selectTab('ssl')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.ssl') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'general'" class="panel-body py-0">
|
||||
<div class="container">
|
||||
<form class="form-horizontal">
|
||||
<fieldset class="m-0" :disabled="isTesting">
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.connectionName') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="connection.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<select
|
||||
v-model="connection.client"
|
||||
class="form-select"
|
||||
@change="setDefaults"
|
||||
>
|
||||
<option value="mysql">
|
||||
MySQL
|
||||
</option>
|
||||
<option value="maria">
|
||||
MariaDB
|
||||
</option>
|
||||
<option value="pg">
|
||||
PostgreSQL
|
||||
</option>
|
||||
<!-- <option value="mssql">
|
||||
Microsoft SQL
|
||||
</option>
|
||||
<option value="oracledb">
|
||||
Oracle DB
|
||||
</option> -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.host"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.port"
|
||||
class="form-input"
|
||||
type="number"
|
||||
min="1"
|
||||
max="65535"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.database" class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.database') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.database"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.user"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:disabled="connection.ask"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.password"
|
||||
class="form-input"
|
||||
type="password"
|
||||
:disabled="connection.ask"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12" />
|
||||
<div class="col-8 col-sm-12">
|
||||
<label class="form-checkbox form-inline">
|
||||
<input v-model="connection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<BaseToast
|
||||
class="mb-2"
|
||||
:message="toast.message"
|
||||
:status="toast.status"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'ssl'" class="panel-body py-0">
|
||||
<div class="container">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.enableSsl') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleSsl">
|
||||
<input type="checkbox" :checked="connection.ssl">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="m-0" :disabled="isTesting || !connection.ssl">
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="connection.key"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('key')"
|
||||
@change="pathSelection($event, 'key')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.certificate') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="connection.cert"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('cert')"
|
||||
@change="pathSelection($event, 'cert')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.caCertificate') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="connection.ca"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('ca')"
|
||||
@change="pathSelection($event, 'ca')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.ciphers') }}</label>
|
||||
</div>
|
||||
<div class="col-8 col-sm-12">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="connection.ciphers"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
<BaseToast
|
||||
class="mb-2"
|
||||
:message="toast.message"
|
||||
:status="toast.status"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer text-light">
|
||||
<button
|
||||
class="btn btn-gray mr-2"
|
||||
:class="{'loading': isTesting}"
|
||||
@click="startTest"
|
||||
>
|
||||
{{ $t('message.testConnection') }}
|
||||
</button>
|
||||
<button class="btn btn-primary mr-2" @click="saveNewConnection">
|
||||
{{ $t('word.save') }}
|
||||
</button>
|
||||
<button class="btn btn-link" @click="closeModal">
|
||||
{{ $t('word.close') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ModalAskCredentials
|
||||
v-if="isAsking"
|
||||
@close-asking="closeAsking"
|
||||
@credentials="continueTest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import customizations from 'common/customizations';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseToast from '@/components/BaseToast';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
|
||||
export default {
|
||||
name: 'ModalNewConnection',
|
||||
components: {
|
||||
ModalAskCredentials,
|
||||
BaseToast,
|
||||
BaseUploadInput
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
connection: {
|
||||
name: '',
|
||||
client: 'mysql',
|
||||
host: '127.0.0.1',
|
||||
database: null,
|
||||
port: null,
|
||||
user: null,
|
||||
password: '',
|
||||
ask: false,
|
||||
uid: uidGen('C'),
|
||||
ssl: false,
|
||||
cert: '',
|
||||
key: '',
|
||||
ca: '',
|
||||
ciphers: ''
|
||||
|
||||
},
|
||||
toast: {
|
||||
status: '',
|
||||
message: ''
|
||||
},
|
||||
isTesting: false,
|
||||
isAsking: false,
|
||||
selectedTab: 'general'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
customizations () {
|
||||
return customizations[this.connection.client];
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.setDefaults();
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
|
||||
setTimeout(() => {
|
||||
this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
closeModal: 'application/hideNewConnModal',
|
||||
addConnection: 'connections/addConnection'
|
||||
}),
|
||||
setDefaults () {
|
||||
this.connection.user = this.customizations.defaultUser;
|
||||
this.connection.port = this.customizations.defaultPort;
|
||||
this.connection.database = this.customizations.defaultDatabase;
|
||||
},
|
||||
async startTest () {
|
||||
this.isTesting = true;
|
||||
this.toast = {
|
||||
status: '',
|
||||
message: ''
|
||||
};
|
||||
|
||||
if (this.connection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
try {
|
||||
const res = await Connection.makeTest(this.connection);
|
||||
console.log(res.response);
|
||||
if (res.status === 'error')
|
||||
this.toast = { status: 'error', message: res.response.message };
|
||||
else
|
||||
this.toast = { status: 'success', message: this.$t('message.connectionSuccessfullyMade') };
|
||||
}
|
||||
catch (err) {
|
||||
this.toast = { status: 'error', message: err.stack };
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
}
|
||||
},
|
||||
async continueTest (credentials) { // if "Ask for credentials" is true
|
||||
this.isAsking = false;
|
||||
const params = Object.assign({}, this.connection, credentials);
|
||||
|
||||
try {
|
||||
const res = await Connection.makeTest(params);
|
||||
if (res.status === 'error')
|
||||
this.toast = { status: 'error', message: res.response.message };
|
||||
else
|
||||
this.toast = { status: 'success', message: this.$t('message.connectionSuccessfullyMade') };
|
||||
}
|
||||
catch (err) {
|
||||
this.toast = { status: 'error', message: err.stack };
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
},
|
||||
saveNewConnection () {
|
||||
this.addConnection(this.connection);
|
||||
this.closeModal();
|
||||
},
|
||||
closeAsking () {
|
||||
this.isAsking = false;
|
||||
this.isTesting = false;
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
selectTab (tab) {
|
||||
this.selectedTab = tab;
|
||||
},
|
||||
toggleSsl () {
|
||||
this.connection.ssl = !this.connection.ssl;
|
||||
},
|
||||
pathSelection (event, name) {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
this.connection[name] = files[0].path;
|
||||
},
|
||||
pathClear (name) {
|
||||
this.connection[name] = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-container {
|
||||
position: absolute;
|
||||
max-width: 450px;
|
||||
top: 17.5vh;
|
||||
}
|
||||
</style>
|
@@ -49,7 +49,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer text-light">
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
class="btn btn-primary mr-2"
|
||||
:class="{'loading': isLoading}"
|
||||
|
@@ -86,7 +86,7 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer text-light">
|
||||
<div class="modal-footer">
|
||||
<div class="input-group col-3 tooltip tooltip-right" :data-tooltip="$t('message.numberOfInserts')">
|
||||
<input
|
||||
v-model="nInserts"
|
||||
|
@@ -60,7 +60,7 @@
|
||||
{{ $t('word.application') }}
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12 mb-2">
|
||||
<div class="form-group mb-4">
|
||||
<div class="form-group">
|
||||
<div class="col-6 col-sm-12">
|
||||
<label class="form-label">
|
||||
<i class="mdi mdi-18px mdi-translate mr-1" />
|
||||
@@ -104,6 +104,19 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-6 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.restorePreviourSession') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-6 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleRestoreSession">
|
||||
<input type="checkbox" :checked="restoreTabs">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-6 col-sm-12">
|
||||
<label class="form-label">
|
||||
@@ -369,6 +382,7 @@ export default {
|
||||
selectedAutoComplete: 'settings/getAutoComplete',
|
||||
selectedLineWrap: 'settings/getLineWrap',
|
||||
notificationsTimeout: 'settings/getNotificationsTimeout',
|
||||
restoreTabs: 'settings/getRestoreTabs',
|
||||
applicationTheme: 'settings/getApplicationTheme',
|
||||
editorTheme: 'settings/getEditorTheme',
|
||||
editorFontSize: 'settings/getEditorFontSize',
|
||||
@@ -423,6 +437,7 @@ ORDER BY
|
||||
closeModal: 'application/hideSettingModal',
|
||||
changeLocale: 'settings/changeLocale',
|
||||
changePageSize: 'settings/changePageSize',
|
||||
changeRestoreTabs: 'settings/changeRestoreTabs',
|
||||
changeAutoComplete: 'settings/changeAutoComplete',
|
||||
changeLineWrap: 'settings/changeLineWrap',
|
||||
changeApplicationTheme: 'settings/changeApplicationTheme',
|
||||
@@ -447,6 +462,9 @@ ORDER BY
|
||||
if (e.key === 'Escape')
|
||||
this.closeModal();
|
||||
},
|
||||
toggleRestoreSession () {
|
||||
this.changeRestoreTabs(!this.restoreTabs);
|
||||
},
|
||||
toggleAutoComplete () {
|
||||
this.changeAutoComplete(!this.selectedAutoComplete);
|
||||
},
|
||||
|
@@ -3,18 +3,13 @@
|
||||
:context-event="contextEvent"
|
||||
@close-context="$emit('close-context')"
|
||||
>
|
||||
<div class="context-element" @click="showEditModal(contextConnection)">
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-pencil text-light pr-1" /> {{ $t('word.edit') }}</span>
|
||||
<div class="context-element" @click="duplicateConnection">
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-content-duplicate text-light pr-1" /> {{ $t('word.duplicate') }}</span>
|
||||
</div>
|
||||
<div class="context-element" @click="showConfirmModal">
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-delete text-light pr-1" /> {{ $t('word.delete') }}</span>
|
||||
</div>
|
||||
|
||||
<ModalEditConnection
|
||||
v-if="isEditModal"
|
||||
:connection="contextConnection"
|
||||
@close="hideEditModal"
|
||||
/>
|
||||
<ConfirmModal
|
||||
v-if="isConfirmModal"
|
||||
@confirm="confirmDeleteConnection"
|
||||
@@ -36,15 +31,14 @@
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
import ModalEditConnection from '@/components/ModalEditConnection';
|
||||
|
||||
export default {
|
||||
name: 'SettingBarContext',
|
||||
components: {
|
||||
BaseContextMenu,
|
||||
ModalEditConnection,
|
||||
ConfirmModal
|
||||
},
|
||||
props: {
|
||||
@@ -59,7 +53,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getConnectionName: 'connections/getConnectionName'
|
||||
getConnectionName: 'connections/getConnectionName',
|
||||
selectedWorkspace: 'workspaces/getSelected'
|
||||
}),
|
||||
connectionName () {
|
||||
return this.getConnectionName(this.contextConnection.uid);
|
||||
@@ -67,17 +62,25 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
deleteConnection: 'connections/deleteConnection'
|
||||
addConnection: 'connections/addConnection',
|
||||
deleteConnection: 'connections/deleteConnection',
|
||||
selectWorkspace: 'workspaces/selectWorkspace'
|
||||
}),
|
||||
confirmDeleteConnection () {
|
||||
if (this.selectedWorkspace === this.contextConnection.uid)
|
||||
this.selectWorkspace();
|
||||
this.deleteConnection(this.contextConnection);
|
||||
this.closeContext();
|
||||
},
|
||||
showEditModal () {
|
||||
this.isEditModal = true;
|
||||
},
|
||||
hideEditModal () {
|
||||
this.isEditModal = false;
|
||||
duplicateConnection () {
|
||||
let connectionCopy = Object.assign({}, this.contextConnection);
|
||||
connectionCopy = {
|
||||
...connectionCopy,
|
||||
uid: uidGen('C'),
|
||||
name: connectionCopy.name ? `${connectionCopy.name}_copy` : ''
|
||||
};
|
||||
|
||||
this.addConnection(connectionCopy);
|
||||
this.closeContext();
|
||||
},
|
||||
showConfirmModal () {
|
||||
|
@@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<div class="columns">
|
||||
<div class="column col-12 empty text-light">
|
||||
<div class="empty-icon">
|
||||
<i class="mdi mdi-48px mdi-emoticon" />
|
||||
</div>
|
||||
<p class="empty-title h5">
|
||||
{{ $t('message.appWelcome') }}
|
||||
</p>
|
||||
<p class="empty-subtitle">
|
||||
{{ $t('message.appFirstStep') }}
|
||||
</p>
|
||||
<div class="empty-action">
|
||||
<button class="btn btn-primary" @click="$emit('new-conn')">
|
||||
{{ $t('message.createConnection') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TheAppWelcome'
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.empty {
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
@@ -8,24 +8,29 @@
|
||||
@close-context="isContext = false"
|
||||
/>
|
||||
<ul class="settingbar-elements">
|
||||
<draggable v-model="connections">
|
||||
<Draggable
|
||||
v-model="connections"
|
||||
@start="isDragging = true"
|
||||
@end="dragStop"
|
||||
>
|
||||
<li
|
||||
v-for="connection in connections"
|
||||
:key="connection.uid"
|
||||
draggable="true"
|
||||
class="settingbar-element btn btn-link ex-tooltip"
|
||||
:class="{'selected': connection.uid === selectedWorkspace}"
|
||||
@click="selectWorkspace(connection.uid)"
|
||||
@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 class="ex-tooltip-content">{{ getConnectionName(connection.uid) }}</span>
|
||||
<span v-if="!isDragging" class="ex-tooltip-content">{{ getConnectionName(connection.uid) }}</span>
|
||||
</li>
|
||||
</draggable>
|
||||
</Draggable>
|
||||
<li
|
||||
class="settingbar-element btn btn-link ex-tooltip"
|
||||
@click="showNewConnModal"
|
||||
:class="{'selected': 'NEW' === selectedWorkspace}"
|
||||
@click="selectWorkspace('NEW')"
|
||||
@mouseover.self="tooltipPosition"
|
||||
>
|
||||
<i class="settingbar-element-icon mdi mdi-24px mdi-plus text-light" />
|
||||
@@ -51,19 +56,20 @@
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import draggable from 'vuedraggable';
|
||||
import Draggable from 'vuedraggable';
|
||||
import SettingBarContext from '@/components/SettingBarContext';
|
||||
|
||||
export default {
|
||||
name: 'TheSettingBar',
|
||||
components: {
|
||||
draggable,
|
||||
Draggable,
|
||||
SettingBarContext
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
dragElement: null,
|
||||
isContext: false,
|
||||
isDragging: false,
|
||||
contextEvent: null,
|
||||
contextConnection: {},
|
||||
scale: 0
|
||||
@@ -92,7 +98,6 @@ export default {
|
||||
methods: {
|
||||
...mapActions({
|
||||
updateConnections: 'connections/updateConnections',
|
||||
showNewConnModal: 'application/showNewConnModal',
|
||||
showSettingModal: 'application/showSettingModal',
|
||||
showScratchpad: 'application/showScratchpad',
|
||||
selectWorkspace: 'workspaces/selectWorkspace'
|
||||
@@ -106,7 +111,7 @@ export default {
|
||||
return connection.ask ? '' : `${connection.user + '@'}${connection.host}:${connection.port}`;
|
||||
},
|
||||
tooltipPosition (e) {
|
||||
const el = e.target;
|
||||
const el = e.target ? e.target : e;
|
||||
const fromTop = window.pageYOffset + el.getBoundingClientRect().top - (el.offsetHeight / 4);
|
||||
el.querySelector('.ex-tooltip-content').style.top = `${fromTop}px`;
|
||||
},
|
||||
@@ -125,6 +130,13 @@ export default {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
dragStop (e) {
|
||||
this.isDragging = false;
|
||||
|
||||
setTimeout(() => {
|
||||
this.tooltipPosition(e.originalEvent.target.parentNode);
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -167,14 +179,13 @@ export default {
|
||||
height: $settingbar-width;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border-left: 3px solid transparent;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.2s;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
@@ -194,12 +205,12 @@ export default {
|
||||
width: 3px;
|
||||
transition: height 0.2s;
|
||||
background-color: $primary-color;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
border-radius: $border-radius;
|
||||
}
|
||||
|
||||
.settingbar-element-icon {
|
||||
margin: 0 auto;
|
||||
|
||||
&.badge::after {
|
||||
bottom: -10px;
|
||||
right: 0;
|
||||
@@ -236,7 +247,13 @@ export default {
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
&:hover .ex-tooltip-content {
|
||||
&.sortable-chosen {
|
||||
.ex-tooltip-content {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover:not(.selected) .ex-tooltip-content {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
@@ -58,6 +58,7 @@ export default {
|
||||
}),
|
||||
windowTitle () {
|
||||
if (!this.selectedWorkspace) return '';
|
||||
if (this.selectedWorkspace === 'NEW') return this.$t('message.createNewConnection');
|
||||
|
||||
const connectionName = this.getConnectionName(this.selectedWorkspace);
|
||||
const workspace = this.getWorkspace(this.selectedWorkspace);
|
||||
|
@@ -1,13 +1,168 @@
|
||||
<template>
|
||||
<div v-show="isSelected" class="workspace column columns col-gapless">
|
||||
<WorkspaceExploreBar :connection="connection" :is-selected="isSelected" />
|
||||
<WorkspaceExploreBar
|
||||
v-if="workspace.connection_status === 'connected'"
|
||||
:connection="connection"
|
||||
:is-selected="isSelected"
|
||||
/>
|
||||
<div v-if="workspace.connection_status === 'connected'" class="workspace-tabs column columns col-gapless">
|
||||
<ul
|
||||
id="tabWrap"
|
||||
<Draggable
|
||||
ref="tabWrap"
|
||||
v-model="draggableTabs"
|
||||
tag="ul"
|
||||
group="tabs"
|
||||
class="tab tab-block column col-12"
|
||||
draggable=".tab-draggable"
|
||||
@mouseover.native="addWheelEvent"
|
||||
>
|
||||
<li class="tab-item dropdown tools-dropdown">
|
||||
<li
|
||||
v-for="(tab, i) of draggableTabs"
|
||||
:key="i"
|
||||
class="tab-item tab-draggable"
|
||||
draggable="true"
|
||||
:class="{'active': selectedTab === tab.uid}"
|
||||
@mousedown.left="selectTab({uid: workspace.uid, tab: tab.uid})"
|
||||
@mouseup.middle="closeTab(tab)"
|
||||
>
|
||||
<a v-if="tab.type === 'query'" class="tab-link">
|
||||
<i class="mdi mdi-18px mdi-code-tags mr-1" />
|
||||
<span>
|
||||
Query #{{ tab.index }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'temp-data'"
|
||||
class="tab-link"
|
||||
@dblclick="openAsPermanentTab(tab)"
|
||||
>
|
||||
<i class="mdi mdi-18px mr-1" :class="tab.elementType === 'view' ? 'mdi-table-eye' : 'mdi-table'" />
|
||||
<span :title="`${$t('word.data').toUpperCase()}: ${tab.elementType}`">
|
||||
<span class=" text-italic">{{ tab.elementName }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a v-else-if="tab.type === 'data'" class="tab-link">
|
||||
<i class="mdi mdi-18px mr-1" :class="tab.elementType === 'view' ? 'mdi-table-eye' : 'mdi-table'" />
|
||||
<span :title="`${$t('word.data').toUpperCase()}: ${tab.elementType}`">
|
||||
{{ tab.elementName }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'table-props'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-tune-vertical-variant mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${tab.elementType}`">
|
||||
{{ tab.elementName }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'view-props'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-tune-vertical-variant mdi-18px mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${tab.elementType}`">
|
||||
{{ tab.elementName }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type.includes('temp-')"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
@dblclick="openAsPermanentTab(tab)"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${tab.elementType}`">
|
||||
<span class=" text-italic">{{ tab.elementName }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${tab.elementType}`">
|
||||
{{ tab.elementName }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- <a
|
||||
v-else-if="tab.type === 'temp-trigger-function-props'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
@dblclick="openAsPermanentTab(tab)"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${tab.elementType}`">
|
||||
<span class=" text-italic">{{ tab.elementName }}</span>
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-else-if="tab.type === 'trigger-function-props'"
|
||||
class="tab-link"
|
||||
:class="{'badge': tab.isChanged}"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="`${$t('word.settings').toUpperCase()}: ${tab.elementType}`">
|
||||
{{ tab.elementName }}
|
||||
<span
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab)"
|
||||
/>
|
||||
</span>
|
||||
</a> -->
|
||||
</li>
|
||||
<li slot="header" class="tab-item dropdown tools-dropdown">
|
||||
<a
|
||||
class="tab-link workspace-tools-link dropdown-toggle"
|
||||
tabindex="0"
|
||||
@@ -44,151 +199,150 @@
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li
|
||||
v-if="schemaChild && isSettingSupported"
|
||||
class="tab-item"
|
||||
:class="{'active': selectedTab === 'prop'}"
|
||||
@click="selectTab({uid: workspace.uid, tab: 'prop'})"
|
||||
>
|
||||
<a class="tab-link">
|
||||
<i class="mdi mdi-18px mdi-tune-vertical-variant mr-1" />
|
||||
<span :title="schemaChild">{{ $t('word.settings').toUpperCase() }}: {{ schemaChild }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
v-if="workspace.breadcrumbs.table || workspace.breadcrumbs.view"
|
||||
class="tab-item"
|
||||
:class="{'active': selectedTab === 'data'}"
|
||||
@click="selectTab({uid: workspace.uid, tab: 'data'})"
|
||||
>
|
||||
<a class="tab-link">
|
||||
<i class="mdi mdi-18px mr-1" :class="workspace.breadcrumbs.table ? 'mdi-table' : 'mdi-table-eye'" />
|
||||
<span :title="schemaChild">{{ $t('word.data').toUpperCase() }}: {{ schemaChild }}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
v-for="tab of queryTabs"
|
||||
:key="tab.uid"
|
||||
class="tab-item"
|
||||
:class="{'active': selectedTab === tab.uid}"
|
||||
@click="selectTab({uid: workspace.uid, tab: tab.uid})"
|
||||
@mouseup.middle="closeTab(tab.uid)"
|
||||
>
|
||||
<a class="tab-link">
|
||||
<i class="mdi mdi-18px mdi-code-tags mr-1" />
|
||||
<span>
|
||||
Query #{{ tab.index }}
|
||||
<span
|
||||
v-if="queryTabs.length > 1"
|
||||
class="btn btn-clear"
|
||||
:title="$t('word.close')"
|
||||
@click.stop="closeTab(tab.uid)"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tab-item">
|
||||
<li slot="footer" class="tab-item">
|
||||
<a
|
||||
class="tab-add"
|
||||
:title="$t('message.openNewTab')"
|
||||
@click="addTab"
|
||||
@click="addQueryTab"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-plus" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<WorkspacePropsTab
|
||||
v-show="selectedTab === 'prop' && workspace.breadcrumbs.table"
|
||||
:is-selected="selectedTab === 'prop'"
|
||||
:connection="connection"
|
||||
:table="workspace.breadcrumbs.table"
|
||||
/>
|
||||
<WorkspacePropsTabView
|
||||
v-show="selectedTab === 'prop' && workspace.breadcrumbs.view"
|
||||
:is-selected="selectedTab === 'prop'"
|
||||
:connection="connection"
|
||||
:view="workspace.breadcrumbs.view"
|
||||
/>
|
||||
<WorkspacePropsTabTrigger
|
||||
v-show="selectedTab === 'prop' && workspace.breadcrumbs.trigger"
|
||||
:is-selected="selectedTab === 'prop'"
|
||||
:connection="connection"
|
||||
:trigger="workspace.breadcrumbs.trigger"
|
||||
/>
|
||||
<WorkspacePropsTabRoutine
|
||||
v-show="selectedTab === 'prop' && workspace.breadcrumbs.procedure"
|
||||
:is-selected="selectedTab === 'prop'"
|
||||
:connection="connection"
|
||||
:routine="workspace.breadcrumbs.procedure"
|
||||
/>
|
||||
<WorkspacePropsTabFunction
|
||||
v-show="selectedTab === 'prop' && workspace.breadcrumbs.function"
|
||||
:is-selected="selectedTab === 'prop'"
|
||||
:connection="connection"
|
||||
:function="workspace.breadcrumbs.function"
|
||||
/>
|
||||
<WorkspacePropsTabTriggerFunction
|
||||
v-show="selectedTab === 'prop' && workspace.breadcrumbs.triggerFunction"
|
||||
:is-selected="selectedTab === 'prop'"
|
||||
:connection="connection"
|
||||
:function="workspace.breadcrumbs.triggerFunction"
|
||||
/>
|
||||
<WorkspacePropsTabScheduler
|
||||
</Draggable>
|
||||
<!--<WorkspacePropsTabScheduler
|
||||
v-show="selectedTab === 'prop' && workspace.breadcrumbs.scheduler"
|
||||
:is-selected="selectedTab === 'prop'"
|
||||
:connection="connection"
|
||||
:scheduler="workspace.breadcrumbs.scheduler"
|
||||
/>
|
||||
<WorkspaceTableTab
|
||||
v-show="selectedTab === 'data'"
|
||||
:connection="connection"
|
||||
:table="workspace.breadcrumbs.table || workspace.breadcrumbs.view"
|
||||
/>
|
||||
<WorkspaceQueryTab
|
||||
v-for="tab of queryTabs"
|
||||
:key="tab.uid"
|
||||
:tab="tab"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:connection="connection"
|
||||
/>
|
||||
/> -->
|
||||
<WorkspaceEmptyState v-if="!workspace.tabs.length" @new-tab="addQueryTab" />
|
||||
<template v-for="tab of workspace.tabs">
|
||||
<WorkspaceQueryTab
|
||||
v-if="tab.type==='query'"
|
||||
:key="tab.uid"
|
||||
:tab="tab"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:connection="connection"
|
||||
/>
|
||||
<WorkspaceTableTab
|
||||
v-else-if="['temp-data', 'data'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:table="tab.elementName"
|
||||
:schema="tab.schema"
|
||||
:element-type="tab.elementType"
|
||||
/>
|
||||
<WorkspacePropsTab
|
||||
v-else-if="tab.type === 'table-props'"
|
||||
:key="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:table="tab.elementName"
|
||||
:schema="tab.schema"
|
||||
/>
|
||||
<WorkspacePropsTabView
|
||||
v-else-if="tab.type === 'view-props'"
|
||||
:key="tab.uid"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:connection="connection"
|
||||
:view="tab.elementName"
|
||||
:schema="tab.schema"
|
||||
/>
|
||||
<WorkspacePropsTabTrigger
|
||||
v-else-if="['temp-trigger-props', 'trigger-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:trigger="tab.elementName"
|
||||
:schema="tab.schema"
|
||||
/>
|
||||
<WorkspacePropsTabTriggerFunction
|
||||
v-else-if="['temp-trigger-function-props', 'trigger-function-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:function="tab.elementName"
|
||||
:schema="tab.schema"
|
||||
/>
|
||||
<WorkspacePropsTabRoutine
|
||||
v-else-if="['temp-routine-props', 'routine-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:routine="tab.elementName"
|
||||
:schema="tab.schema"
|
||||
/>
|
||||
<WorkspacePropsTabFunction
|
||||
v-else-if="['temp-function-props', 'function-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:function="tab.elementName"
|
||||
:schema="tab.schema"
|
||||
/>
|
||||
<WorkspacePropsTabScheduler
|
||||
v-else-if="['temp-scheduler-props', 'scheduler-props'].includes(tab.type)"
|
||||
:key="tab.uid"
|
||||
:connection="connection"
|
||||
:is-selected="selectedTab === tab.uid"
|
||||
:scheduler="tab.elementName"
|
||||
:schema="tab.schema"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<WorkspaceEditConnectionPanel v-else :connection="connection" />
|
||||
<ModalProcessesList
|
||||
v-if="isProcessesModal"
|
||||
:connection="connection"
|
||||
@close="hideProcessesModal"
|
||||
/>
|
||||
|
||||
<ModalDiscardChanges
|
||||
v-if="unsavedTab"
|
||||
@confirm="closeTab(unsavedTab, true)"
|
||||
@close="unsavedTab = null"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import Draggable from 'vuedraggable';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import WorkspaceEmptyState from '@/components/WorkspaceEmptyState';
|
||||
import WorkspaceExploreBar from '@/components/WorkspaceExploreBar';
|
||||
import WorkspaceEditConnectionPanel from '@/components/WorkspaceEditConnectionPanel';
|
||||
import WorkspaceQueryTab from '@/components/WorkspaceQueryTab';
|
||||
import WorkspaceTableTab from '@/components/WorkspaceTableTab';
|
||||
import WorkspacePropsTab from '@/components/WorkspacePropsTab';
|
||||
import WorkspacePropsTabView from '@/components/WorkspacePropsTabView';
|
||||
import WorkspacePropsTabTrigger from '@/components/WorkspacePropsTabTrigger';
|
||||
import WorkspacePropsTabTriggerFunction from '@/components/WorkspacePropsTabTriggerFunction';
|
||||
import WorkspacePropsTabRoutine from '@/components/WorkspacePropsTabRoutine';
|
||||
import WorkspacePropsTabFunction from '@/components/WorkspacePropsTabFunction';
|
||||
import WorkspacePropsTabTriggerFunction from '@/components/WorkspacePropsTabTriggerFunction';
|
||||
import WorkspacePropsTabScheduler from '@/components/WorkspacePropsTabScheduler';
|
||||
import ModalProcessesList from '@/components/ModalProcessesList';
|
||||
import ModalDiscardChanges from '@/components/ModalDiscardChanges';
|
||||
|
||||
export default {
|
||||
name: 'Workspace',
|
||||
components: {
|
||||
Draggable,
|
||||
WorkspaceEmptyState,
|
||||
WorkspaceExploreBar,
|
||||
WorkspaceEditConnectionPanel,
|
||||
WorkspaceQueryTab,
|
||||
WorkspaceTableTab,
|
||||
WorkspacePropsTab,
|
||||
WorkspacePropsTabView,
|
||||
WorkspacePropsTabTrigger,
|
||||
WorkspacePropsTabTriggerFunction,
|
||||
WorkspacePropsTabRoutine,
|
||||
WorkspacePropsTabFunction,
|
||||
WorkspacePropsTabTriggerFunction,
|
||||
WorkspacePropsTabScheduler,
|
||||
ModalProcessesList
|
||||
ModalProcessesList,
|
||||
ModalDiscardChanges
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
@@ -196,7 +350,8 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
hasWheelEvent: false,
|
||||
isProcessesModal: false
|
||||
isProcessesModal: false,
|
||||
unsavedTab: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -207,6 +362,14 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
draggableTabs: {
|
||||
get () {
|
||||
return this.workspace.tabs;
|
||||
},
|
||||
set (val) {
|
||||
this.updateTabs({ uid: this.connection.uid, tabs: val });
|
||||
}
|
||||
},
|
||||
isSelected () {
|
||||
return this.selectedWorkspace === this.connection.uid;
|
||||
},
|
||||
@@ -221,29 +384,7 @@ export default {
|
||||
return false;
|
||||
},
|
||||
selectedTab () {
|
||||
if (
|
||||
(
|
||||
this.workspace.breadcrumbs.table === null &&
|
||||
this.workspace.breadcrumbs.view === null &&
|
||||
this.workspace.breadcrumbs.trigger === null &&
|
||||
this.workspace.breadcrumbs.procedure === null &&
|
||||
this.workspace.breadcrumbs.function === null &&
|
||||
this.workspace.breadcrumbs.triggerFunction === null &&
|
||||
this.workspace.breadcrumbs.scheduler === null &&
|
||||
['data', 'prop'].includes(this.workspace.selected_tab)
|
||||
) ||
|
||||
(
|
||||
this.workspace.breadcrumbs.table === null &&
|
||||
this.workspace.breadcrumbs.view === null &&
|
||||
this.workspace.selected_tab === 'data'
|
||||
)
|
||||
)
|
||||
return this.queryTabs[0].uid;
|
||||
|
||||
return this.queryTabs.find(tab => tab.uid === this.workspace.selected_tab) ||
|
||||
['data', 'prop'].includes(this.workspace.selected_tab)
|
||||
? this.workspace.selected_tab
|
||||
: this.queryTabs[0].uid;
|
||||
return this.workspace.selected_tab;
|
||||
},
|
||||
queryTabs () {
|
||||
return this.workspace.tabs.filter(tab => tab.type === 'query');
|
||||
@@ -262,14 +403,6 @@ export default {
|
||||
if (isInitiated)
|
||||
this.connectWorkspace(this.connection);
|
||||
},
|
||||
mounted () {
|
||||
if (this.$refs.tabWrap) {
|
||||
this.$refs.tabWrap.addEventListener('wheel', e => {
|
||||
if (e.deltaY > 0) this.$refs.tabWrap.scrollLeft += 50;
|
||||
else this.$refs.tabWrap.scrollLeft -= 50;
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addWorkspace: 'workspaces/addWorkspace',
|
||||
@@ -277,28 +410,55 @@ export default {
|
||||
removeConnected: 'workspaces/removeConnected',
|
||||
selectTab: 'workspaces/selectTab',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTab: 'workspaces/removeTab'
|
||||
removeTab: 'workspaces/removeTab',
|
||||
updateTabs: 'workspaces/updateTabs'
|
||||
}),
|
||||
addTab () {
|
||||
this.newTab({ uid: this.connection.uid });
|
||||
|
||||
if (!this.hasWheelEvent) {
|
||||
this.$refs.tabWrap.addEventListener('wheel', e => {
|
||||
if (e.deltaY > 0) this.$refs.tabWrap.scrollLeft += 50;
|
||||
else this.$refs.tabWrap.scrollLeft -= 50;
|
||||
});
|
||||
this.hasWheelEvent = true;
|
||||
}
|
||||
addQueryTab () {
|
||||
this.newTab({ uid: this.connection.uid, type: 'query' });
|
||||
},
|
||||
closeTab (tUid) {
|
||||
if (this.queryTabs.length === 1) return;
|
||||
this.removeTab({ uid: this.connection.uid, tab: tUid });
|
||||
openAsPermanentTab (tab) {
|
||||
const permanentTabs = {
|
||||
table: 'data',
|
||||
view: 'data',
|
||||
trigger: 'trigger-props',
|
||||
triggerFunction: 'trigger-function-props',
|
||||
function: 'function-props',
|
||||
routine: 'routine-props',
|
||||
scheduler: 'scheduler-props'
|
||||
};
|
||||
|
||||
this.newTab({
|
||||
uid: this.connection.uid,
|
||||
schema: tab.schema,
|
||||
elementName: tab.elementName,
|
||||
type: permanentTabs[tab.elementType],
|
||||
elementType: tab.elementType
|
||||
});
|
||||
},
|
||||
closeTab (tab, force) {
|
||||
this.unsavedTab = null;
|
||||
// if (tab.type === 'query' && this.queryTabs.length === 1) return;
|
||||
if (!force && tab.isChanged) {
|
||||
this.unsavedTab = tab;
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeTab({ uid: this.connection.uid, tab: tab.uid });
|
||||
},
|
||||
showProcessesModal () {
|
||||
this.isProcessesModal = true;
|
||||
},
|
||||
hideProcessesModal () {
|
||||
this.isProcessesModal = false;
|
||||
},
|
||||
addWheelEvent () {
|
||||
if (!this.hasWheelEvent) {
|
||||
this.$refs.tabWrap.$el.addEventListener('wheel', e => {
|
||||
if (e.deltaY > 0) this.$refs.tabWrap.$el.scrollLeft += 50;
|
||||
else this.$refs.tabWrap.$el.scrollLeft -= 50;
|
||||
});
|
||||
this.hasWheelEvent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -327,20 +487,35 @@ export default {
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
max-width: 12rem;
|
||||
width: fit-content;
|
||||
flex: initial;
|
||||
|
||||
> a {
|
||||
padding: 0.2rem 0.8rem;
|
||||
padding: 0.2rem 0.6rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&.badge::after {
|
||||
position: absolute;
|
||||
right: 35px;
|
||||
top: 25px;
|
||||
}
|
||||
|
||||
.btn-clear {
|
||||
margin-left: 0.5rem;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
|
||||
.btn-clear {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.tab-add {
|
||||
@@ -359,9 +534,15 @@ export default {
|
||||
|
||||
&.active a {
|
||||
opacity: 1;
|
||||
|
||||
.btn-clear {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.tools-dropdown {
|
||||
height: 34px;
|
||||
|
||||
.tab-link:focus {
|
||||
opacity: 1;
|
||||
outline: 0;
|
||||
|
519
src/renderer/components/WorkspaceAddConnectionPanel.vue
Normal file
519
src/renderer/components/WorkspaceAddConnectionPanel.vue
Normal file
@@ -0,0 +1,519 @@
|
||||
<template>
|
||||
<div class="connection-panel">
|
||||
<div class="panel">
|
||||
<div class="panel-nav">
|
||||
<ul class="tab tab-block">
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'general'}"
|
||||
@click="selectTab('general')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.general') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssl'}"
|
||||
@click="selectTab('ssl')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.ssl') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssh'}"
|
||||
@click="selectTab('ssh')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.sshTunnel') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'general'" class="panel-body py-0">
|
||||
<div>
|
||||
<form class="form-horizontal">
|
||||
<fieldset class="m-0" :disabled="isBusy">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.connectionName') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="connection.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<select v-model="connection.client" class="form-select">
|
||||
<option value="mysql">
|
||||
MySQL
|
||||
</option>
|
||||
<option value="maria">
|
||||
MariaDB
|
||||
</option>
|
||||
<option value="pg">
|
||||
PostgreSQL
|
||||
</option>
|
||||
<!-- <option value="mssql">
|
||||
Microsoft SQL
|
||||
</option>
|
||||
<option value="oracledb">
|
||||
Oracle DB
|
||||
</option> -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.host"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.port"
|
||||
class="form-input"
|
||||
type="number"
|
||||
min="1"
|
||||
max="65535"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.database" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.database') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.database"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.user"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:disabled="connection.ask"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.password"
|
||||
class="form-input"
|
||||
type="password"
|
||||
:disabled="connection.ask"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.connectionSchema" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.schema') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.schema"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:placeholder="$t('word.all')"
|
||||
>
|
||||
</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="connection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'ssl'" class="panel-body py-0">
|
||||
<div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.enableSsl') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleSsl">
|
||||
<input type="checkbox" :checked="connection.ssl">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="m-0" :disabled="isBusy || !connection.ssl">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="connection.key"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('key')"
|
||||
@change="pathSelection($event, 'key')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.certificate') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="connection.cert"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('cert')"
|
||||
@change="pathSelection($event, 'cert')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.caCertificate') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="connection.ca"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('ca')"
|
||||
@change="pathSelection($event, 'ca')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.ciphers') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="connection.ciphers"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'ssh'" class="panel-body py-0">
|
||||
<div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.enableSsh') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleSsh">
|
||||
<input type="checkbox" :checked="connection.ssh">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="m-0" :disabled="isBusy || !connection.ssh">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.sshHost"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.sshUser"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.sshPass"
|
||||
class="form-input"
|
||||
type="password"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="connection.sshPort"
|
||||
class="form-input"
|
||||
type="number"
|
||||
min="1"
|
||||
max="65535"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="connection.sshKey"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('sshKey')"
|
||||
@change="pathSelection($event, 'sshKey')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<button
|
||||
class="btn btn-gray mr-2 d-flex"
|
||||
:class="{'loading': isTesting}"
|
||||
:disabled="isBusy"
|
||||
@click="startTest"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-lightning-bolt mr-1" />
|
||||
{{ $t('message.testConnection') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary mr-2 d-flex"
|
||||
:disabled="isBusy"
|
||||
@click="saveConnection"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
{{ $t('word.save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ModalAskCredentials
|
||||
v-if="isAsking"
|
||||
@close-asking="closeAsking"
|
||||
@credentials="continueTest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import customizations from 'common/customizations';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceAddConnectionPanel',
|
||||
components: {
|
||||
ModalAskCredentials,
|
||||
BaseUploadInput
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
connection: {
|
||||
name: '',
|
||||
client: 'mysql',
|
||||
host: '127.0.0.1',
|
||||
database: null,
|
||||
port: null,
|
||||
user: null,
|
||||
password: '',
|
||||
ask: false,
|
||||
uid: uidGen('C'),
|
||||
ssl: false,
|
||||
cert: '',
|
||||
key: '',
|
||||
ca: '',
|
||||
ciphers: '',
|
||||
ssh: false,
|
||||
sshHost: '',
|
||||
sshUser: '',
|
||||
sshPass: '',
|
||||
sshKey: '',
|
||||
sshPort: 22
|
||||
},
|
||||
isConnecting: false,
|
||||
isTesting: false,
|
||||
isAsking: false,
|
||||
selectedTab: 'general'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
customizations () {
|
||||
return customizations[this.connection.client];
|
||||
},
|
||||
isBusy () {
|
||||
return this.isConnecting || this.isTesting;
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.setDefaults();
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.$refs.firstInput) this.$refs.firstInput.focus();
|
||||
}, 20);
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addConnection: 'connections/addConnection',
|
||||
connectWorkspace: 'workspaces/connectWorkspace',
|
||||
addNotification: 'notifications/addNotification',
|
||||
selectWorkspace: 'workspaces/selectWorkspace'
|
||||
}),
|
||||
setDefaults () {
|
||||
this.connection.user = this.customizations.defaultUser;
|
||||
this.connection.port = this.customizations.defaultPort;
|
||||
this.connection.database = this.customizations.defaultDatabase;
|
||||
},
|
||||
async startConnection () {
|
||||
await this.saveConnection();
|
||||
this.isConnecting = true;
|
||||
|
||||
if (this.connection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
await this.connectWorkspace(this.connection);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
},
|
||||
async startTest () {
|
||||
this.isTesting = true;
|
||||
|
||||
if (this.connection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
try {
|
||||
const res = await Connection.makeTest(this.connection);
|
||||
if (res.status === 'error')
|
||||
this.addNotification({ status: 'error', message: res.response.message });
|
||||
else
|
||||
this.addNotification({ status: 'success', message: this.$t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
}
|
||||
},
|
||||
async continueTest (credentials) { // if "Ask for credentials" is true
|
||||
this.isAsking = false;
|
||||
const params = Object.assign({}, this.connection, credentials);
|
||||
try {
|
||||
if (this.isConnecting) {
|
||||
const params = Object.assign({}, this.connection, credentials);
|
||||
await this.connectWorkspace(params);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
else {
|
||||
const res = await Connection.makeTest(params);
|
||||
if (res.status === 'error')
|
||||
this.addNotification({ status: 'error', message: res.response.message });
|
||||
else
|
||||
this.addNotification({ status: 'success', message: this.$t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
},
|
||||
saveConnection () {
|
||||
this.selectWorkspace(this.connection.uid);
|
||||
return this.addConnection(this.connection);
|
||||
},
|
||||
closeAsking () {
|
||||
this.isTesting = false;
|
||||
this.isAsking = false;
|
||||
},
|
||||
selectTab (tab) {
|
||||
this.selectedTab = tab;
|
||||
},
|
||||
toggleSsl () {
|
||||
this.connection.ssl = !this.connection.ssl;
|
||||
},
|
||||
toggleSsh () {
|
||||
this.connection.ssh = !this.connection.ssh;
|
||||
},
|
||||
pathSelection (event, name) {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
this.connection[name] = files[0].path;
|
||||
},
|
||||
pathClear (name) {
|
||||
this.connection[name] = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.connection-panel {
|
||||
margin-top: 15vh;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
.panel {
|
||||
width: 450px;
|
||||
border-radius: $border-radius;
|
||||
|
||||
.panel-body {
|
||||
flex: initial;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<div class="columns">
|
||||
<div class="column col-12 empty">
|
||||
<div class="empty-icon">
|
||||
<i class="mdi mdi-48px mdi-power-plug-off" />
|
||||
</div>
|
||||
<p class="empty-title h5">
|
||||
{{ isConnecting ? $t('word.connecting') : $t('word.disconnected') }}
|
||||
</p>
|
||||
<div class="empty-action">
|
||||
<button
|
||||
class="btn btn-success"
|
||||
:class="{'loading': isConnecting}"
|
||||
@click="startConnection"
|
||||
>
|
||||
{{ $t('word.connect') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ModalAskCredentials
|
||||
v-if="isAsking"
|
||||
@close-asking="closeAsking"
|
||||
@credentials="continueTest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceConnectPanel',
|
||||
components: {
|
||||
ModalAskCredentials
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isConnecting: false,
|
||||
isAsking: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
connectWorkspace: 'workspaces/connectWorkspace'
|
||||
}),
|
||||
async startConnection () {
|
||||
this.isConnecting = true;
|
||||
|
||||
if (this.connection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
await this.connectWorkspace(this.connection);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
},
|
||||
async continueTest (credentials) { // if "Ask for credentials" is true
|
||||
this.isAsking = false;
|
||||
const params = Object.assign({}, this.connection, credentials);
|
||||
await this.connectWorkspace(params);
|
||||
this.isConnecting = false;
|
||||
},
|
||||
closeAsking () {
|
||||
this.isAsking = false;
|
||||
this.isConnecting = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.empty {
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
500
src/renderer/components/WorkspaceEditConnectionPanel.vue
Normal file
500
src/renderer/components/WorkspaceEditConnectionPanel.vue
Normal file
@@ -0,0 +1,500 @@
|
||||
<template>
|
||||
<div class="connection-panel">
|
||||
<div class="panel">
|
||||
<div class="panel-nav">
|
||||
<ul class="tab tab-block">
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'general'}"
|
||||
@click="selectTab('general')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.general') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssl'}"
|
||||
@click="selectTab('ssl')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.ssl') }}</a>
|
||||
</li>
|
||||
<li
|
||||
class="tab-item c-hand"
|
||||
:class="{'active': selectedTab === 'ssh'}"
|
||||
@click="selectTab('ssh')"
|
||||
>
|
||||
<a class="tab-link">{{ $t('word.sshTunnel') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'general'" class="panel-body py-0">
|
||||
<div>
|
||||
<form class="form-horizontal">
|
||||
<fieldset class="m-0" :disabled="isBusy">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.connectionName') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="localConnection.name"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.client') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<select v-model="localConnection.client" class="form-select">
|
||||
<option value="mysql">
|
||||
MySQL
|
||||
</option>
|
||||
<option value="maria">
|
||||
MariaDB
|
||||
</option>
|
||||
<option value="pg">
|
||||
PostgreSQL
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.host"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.port"
|
||||
class="form-input"
|
||||
type="number"
|
||||
min="1"
|
||||
max="65535"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.database" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.database') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.database"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.user"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:disabled="localConnection.ask"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.password"
|
||||
class="form-input"
|
||||
type="password"
|
||||
:disabled="localConnection.ask"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="customizations.connectionSchema" class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.schema') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.schema"
|
||||
class="form-input"
|
||||
type="text"
|
||||
:placeholder="$t('word.all')"
|
||||
>
|
||||
</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.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'ssl'" class="panel-body py-0">
|
||||
<div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.enableSsl') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleSsl">
|
||||
<input type="checkbox" :checked="localConnection.ssl">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="m-0" :disabled="isBusy || !localConnection.ssl">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="localConnection.key"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('key')"
|
||||
@change="pathSelection($event, 'key')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.certificate') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="localConnection.cert"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('cert')"
|
||||
@change="pathSelection($event, 'cert')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.caCertificate') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="localConnection.ca"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('ca')"
|
||||
@change="pathSelection($event, 'ca')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.ciphers') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
ref="firstInput"
|
||||
v-model="localConnection.ciphers"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedTab === 'ssh'" class="panel-body py-0">
|
||||
<div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">
|
||||
{{ $t('message.enableSsh') }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<label class="form-switch d-inline-block" @click.prevent="toggleSsh">
|
||||
<input type="checkbox" :checked="localConnection.ssh">
|
||||
<i class="form-icon" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="m-0" :disabled="isBusy || !localConnection.ssh">
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.hostName') }}/IP</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.sshHost"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.user') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.sshUser"
|
||||
class="form-input"
|
||||
type="text"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.password') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.sshPass"
|
||||
class="form-input"
|
||||
type="password"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.port') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<input
|
||||
v-model="localConnection.sshPort"
|
||||
class="form-input"
|
||||
type="number"
|
||||
min="1"
|
||||
max="65535"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group columns">
|
||||
<div class="column col-4 col-sm-12">
|
||||
<label class="form-label">{{ $t('word.privateKey') }}</label>
|
||||
</div>
|
||||
<div class="column col-8 col-sm-12">
|
||||
<BaseUploadInput
|
||||
:value="localConnection.sshKey"
|
||||
:message="$t('word.browse')"
|
||||
@clear="pathClear('sshKey')"
|
||||
@change="pathSelection($event, 'sshKey')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<button
|
||||
class="btn btn-gray mr-2 d-flex"
|
||||
:class="{'loading': isTesting}"
|
||||
:disabled="isBusy"
|
||||
@click="startTest"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-lightning-bolt mr-1" />
|
||||
{{ $t('message.testConnection') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary mr-2 d-flex"
|
||||
:disabled="isBusy || !hasChanges"
|
||||
@click="saveConnection"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
{{ $t('word.save') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-success d-flex"
|
||||
:class="{'loading': isConnecting}"
|
||||
:disabled="isBusy"
|
||||
@click="startConnection"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-connection mr-1" />
|
||||
{{ $t('word.connect') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<ModalAskCredentials
|
||||
v-if="isAsking"
|
||||
@close-asking="closeAsking"
|
||||
@credentials="continueTest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import customizations from 'common/customizations';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseUploadInput from '@/components/BaseUploadInput';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceEditConnectionPanel',
|
||||
components: {
|
||||
ModalAskCredentials,
|
||||
BaseUploadInput
|
||||
},
|
||||
props: {
|
||||
connection: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isConnecting: false,
|
||||
isTesting: false,
|
||||
isAsking: false,
|
||||
localConnection: null,
|
||||
selectedTab: 'general'
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
customizations () {
|
||||
return customizations[this.connection.client];
|
||||
},
|
||||
isBusy () {
|
||||
return this.isConnecting || this.isTesting;
|
||||
},
|
||||
hasChanges () {
|
||||
return JSON.stringify(this.connection) !== JSON.stringify(this.localConnection);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
connection () {
|
||||
this.localConnection = JSON.parse(JSON.stringify(this.connection));
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.localConnection = JSON.parse(JSON.stringify(this.connection));
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
editConnection: 'connections/editConnection',
|
||||
connectWorkspace: 'workspaces/connectWorkspace',
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
async startConnection () {
|
||||
await this.saveConnection();
|
||||
this.isConnecting = true;
|
||||
|
||||
if (this.localConnection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
await this.connectWorkspace(this.localConnection);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
},
|
||||
async startTest () {
|
||||
this.isTesting = true;
|
||||
|
||||
if (this.localConnection.ask)
|
||||
this.isAsking = true;
|
||||
else {
|
||||
try {
|
||||
const res = await Connection.makeTest(this.localConnection);
|
||||
if (res.status === 'error')
|
||||
this.addNotification({ status: 'error', message: res.response.message });
|
||||
else
|
||||
this.addNotification({ status: 'success', message: this.$t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
}
|
||||
},
|
||||
async continueTest (credentials) { // if "Ask for credentials" is true
|
||||
this.isAsking = false;
|
||||
const params = Object.assign({}, this.localConnection, credentials);
|
||||
try {
|
||||
if (this.isConnecting) {
|
||||
const params = Object.assign({}, this.connection, credentials);
|
||||
await this.connectWorkspace(params);
|
||||
this.isConnecting = false;
|
||||
}
|
||||
else {
|
||||
const res = await Connection.makeTest(params);
|
||||
if (res.status === 'error')
|
||||
this.addNotification({ status: 'error', message: res.response.message });
|
||||
else
|
||||
this.addNotification({ status: 'success', message: this.$t('message.connectionSuccessfullyMade') });
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.addNotification({ status: 'error', message: err.stack });
|
||||
}
|
||||
|
||||
this.isTesting = false;
|
||||
},
|
||||
saveConnection () {
|
||||
return this.editConnection(this.localConnection);
|
||||
},
|
||||
closeAsking () {
|
||||
this.isTesting = false;
|
||||
this.isAsking = false;
|
||||
},
|
||||
selectTab (tab) {
|
||||
this.selectedTab = tab;
|
||||
},
|
||||
toggleSsl () {
|
||||
this.localConnection.ssl = !this.localConnection.ssl;
|
||||
},
|
||||
toggleSsh () {
|
||||
this.localConnection.ssh = !this.localConnection.ssh;
|
||||
},
|
||||
pathSelection (event, name) {
|
||||
const { files } = event.target;
|
||||
if (!files.length) return;
|
||||
|
||||
this.localConnection[name] = files[0].path;
|
||||
},
|
||||
pathClear (name) {
|
||||
this.localConnection[name] = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.connection-panel {
|
||||
margin-top: 15vh;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
.panel {
|
||||
width: 450px;
|
||||
border-radius: $border-radius;
|
||||
|
||||
.panel-body {
|
||||
flex: initial;
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
55
src/renderer/components/WorkspaceEmptyState.vue
Normal file
55
src/renderer/components/WorkspaceEmptyState.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div class="column col-12 empty">
|
||||
<div class="empty-icon">
|
||||
<img :src="require(`@/images/logo-${applicationTheme}.svg`).default" width="200">
|
||||
</div>
|
||||
<p class="h6 empty-subtitle">
|
||||
{{ $t('message.noOpenTabs') }}
|
||||
</p>
|
||||
<div class="empty-action">
|
||||
<button class="btn btn-gray d-flex" @click="$emit('new-tab')">
|
||||
<i class="mdi mdi-24px mdi-tab-plus mr-2" />
|
||||
{{ $t('message.openNewTab') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
export default {
|
||||
name: 'WorkspaceEmptyState',
|
||||
computed: {
|
||||
...mapGetters({
|
||||
applicationTheme: 'settings/getApplicationTheme',
|
||||
getWorkspace: 'workspaces/getWorkspace',
|
||||
selectedWorkspace: 'workspaces/getSelected'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.changeBreadcrumbs({ schema: this.workspace.breadcrumbs.schema });
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
})
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.empty {
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
</style>
|
@@ -21,7 +21,7 @@
|
||||
@click="refresh"
|
||||
/>
|
||||
<i
|
||||
class="mdi mdi-18px mdi-power-plug-off c-hand"
|
||||
class="mdi mdi-18px mdi-power c-hand"
|
||||
:title="$t('word.disconnect')"
|
||||
@click="disconnectWorkspace(connection.uid)"
|
||||
/>
|
||||
@@ -38,12 +38,7 @@
|
||||
<i class="form-icon mdi mdi-magnify mdi-18px" />
|
||||
</div>
|
||||
</div>
|
||||
<WorkspaceConnectPanel
|
||||
v-if="workspace.connection_status !== 'connected'"
|
||||
class="workspace-explorebar-body"
|
||||
:connection="connection"
|
||||
/>
|
||||
<div v-else class="workspace-explorebar-body">
|
||||
<div class="workspace-explorebar-body">
|
||||
<WorkspaceExploreBarSchema
|
||||
v-for="db of workspace.structure"
|
||||
:key="db.name"
|
||||
@@ -52,6 +47,7 @@
|
||||
@show-schema-context="openSchemaContext"
|
||||
@show-table-context="openTableContext"
|
||||
@show-misc-context="openMiscContext"
|
||||
@show-misc-folder-context="openMiscFolderContext"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -104,7 +100,7 @@
|
||||
/>
|
||||
<DatabaseContext
|
||||
v-if="isDatabaseContext"
|
||||
:selected-database="selectedDatabase"
|
||||
:selected-schema="selectedSchema"
|
||||
:context-event="databaseContextEvent"
|
||||
@close-context="closeDatabaseContext"
|
||||
@show-create-table-modal="showCreateTableModal"
|
||||
@@ -118,6 +114,7 @@
|
||||
/>
|
||||
<TableContext
|
||||
v-if="isTableContext"
|
||||
:selected-schema="selectedSchema"
|
||||
:selected-table="selectedTable"
|
||||
:context-event="tableContextEvent"
|
||||
@close-context="closeTableContext"
|
||||
@@ -126,10 +123,24 @@
|
||||
<MiscContext
|
||||
v-if="isMiscContext"
|
||||
:selected-misc="selectedMisc"
|
||||
:selected-schema="selectedSchema"
|
||||
:context-event="miscContextEvent"
|
||||
@close-context="closeMiscContext"
|
||||
@reload="refresh"
|
||||
/>
|
||||
<MiscFolderContext
|
||||
v-if="isMiscFolderContext"
|
||||
:selected-misc="selectedMisc"
|
||||
:selected-schema="selectedSchema"
|
||||
:context-event="miscContextEvent"
|
||||
@show-create-trigger-modal="showCreateTriggerModal"
|
||||
@show-create-routine-modal="showCreateRoutineModal"
|
||||
@show-create-function-modal="showCreateFunctionModal"
|
||||
@show-create-trigger-function-modal="showCreateTriggerFunctionModal"
|
||||
@show-create-scheduler-modal="showCreateSchedulerModal"
|
||||
@close-context="closeMiscFolderContext"
|
||||
@reload="refresh"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -143,11 +154,11 @@ import Routines from '@/ipc-api/Routines';
|
||||
import Functions from '@/ipc-api/Functions';
|
||||
import Schedulers from '@/ipc-api/Schedulers';
|
||||
|
||||
import WorkspaceConnectPanel from '@/components/WorkspaceConnectPanel';
|
||||
import WorkspaceExploreBarSchema from '@/components/WorkspaceExploreBarSchema';
|
||||
import DatabaseContext from '@/components/WorkspaceExploreBarSchemaContext';
|
||||
import TableContext from '@/components/WorkspaceExploreBarTableContext';
|
||||
import MiscContext from '@/components/WorkspaceExploreBarMiscContext';
|
||||
import MiscFolderContext from '@/components/WorkspaceExploreBarMiscFolderContext';
|
||||
import ModalNewSchema from '@/components/ModalNewSchema';
|
||||
import ModalNewTable from '@/components/ModalNewTable';
|
||||
import ModalNewView from '@/components/ModalNewView';
|
||||
@@ -160,11 +171,11 @@ import ModalNewScheduler from '@/components/ModalNewScheduler';
|
||||
export default {
|
||||
name: 'WorkspaceExploreBar',
|
||||
components: {
|
||||
WorkspaceConnectPanel,
|
||||
WorkspaceExploreBarSchema,
|
||||
DatabaseContext,
|
||||
TableContext,
|
||||
MiscContext,
|
||||
MiscFolderContext,
|
||||
ModalNewSchema,
|
||||
ModalNewTable,
|
||||
ModalNewView,
|
||||
@@ -197,12 +208,13 @@ export default {
|
||||
isDatabaseContext: false,
|
||||
isTableContext: false,
|
||||
isMiscContext: false,
|
||||
isMiscFolderContext: false,
|
||||
|
||||
databaseContextEvent: null,
|
||||
tableContextEvent: null,
|
||||
miscContextEvent: null,
|
||||
|
||||
selectedDatabase: '',
|
||||
selectedSchema: '',
|
||||
selectedTable: null,
|
||||
selectedMisc: null,
|
||||
searchTerm: ''
|
||||
@@ -262,6 +274,7 @@ export default {
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
selectTab: 'workspaces/selectTab',
|
||||
newTab: 'workspaces/newTab',
|
||||
setSearchTerm: 'workspaces/setSearchTerm',
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeExplorebarSize: 'settings/changeExplorebarSize'
|
||||
@@ -299,6 +312,7 @@ export default {
|
||||
async openCreateTableEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
@@ -306,14 +320,19 @@ export default {
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedDatabase, table: payload.name });
|
||||
this.selectTab({ uid: this.workspace.uid, tab: 'prop' });
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'table',
|
||||
type: 'table-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
},
|
||||
openSchemaContext (payload) {
|
||||
this.selectedDatabase = payload.schema;
|
||||
this.selectedSchema = payload.schema;
|
||||
this.databaseContextEvent = payload.event;
|
||||
this.isDatabaseContext = true;
|
||||
},
|
||||
@@ -322,6 +341,7 @@ export default {
|
||||
},
|
||||
openTableContext (payload) {
|
||||
this.selectedTable = payload.table;
|
||||
this.selectedSchema = payload.schema;
|
||||
this.tableContextEvent = payload.event;
|
||||
this.isTableContext = true;
|
||||
},
|
||||
@@ -330,14 +350,25 @@ export default {
|
||||
},
|
||||
openMiscContext (payload) {
|
||||
this.selectedMisc = payload.misc;
|
||||
this.selectedSchema = payload.schema;
|
||||
this.miscContextEvent = payload.event;
|
||||
this.isMiscContext = true;
|
||||
},
|
||||
openMiscFolderContext (payload) {
|
||||
this.selectedMisc = payload.type;
|
||||
this.selectedSchema = payload.schema;
|
||||
this.miscContextEvent = payload.event;
|
||||
this.isMiscFolderContext = true;
|
||||
},
|
||||
closeMiscContext () {
|
||||
this.isMiscContext = false;
|
||||
},
|
||||
closeMiscFolderContext () {
|
||||
this.isMiscFolderContext = false;
|
||||
},
|
||||
showCreateViewModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewViewModal = true;
|
||||
},
|
||||
hideCreateViewModal () {
|
||||
@@ -346,6 +377,7 @@ export default {
|
||||
async openCreateViewEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
@@ -353,14 +385,22 @@ export default {
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedDatabase, view: payload.name });
|
||||
this.selectTab({ uid: this.workspace.uid, tab: 'prop' });
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, view: payload.name });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'view',
|
||||
type: 'view-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
},
|
||||
showCreateTriggerModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewTriggerModal = true;
|
||||
},
|
||||
hideCreateTriggerModal () {
|
||||
@@ -369,6 +409,7 @@ export default {
|
||||
async openCreateTriggerEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
@@ -377,14 +418,22 @@ export default {
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
const triggerName = this.customizations.triggerTableInName ? `${payload.table}.${payload.name}` : payload.name;
|
||||
this.changeBreadcrumbs({ schema: this.selectedDatabase, trigger: triggerName });
|
||||
this.selectTab({ uid: this.workspace.uid, tab: 'prop' });
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, trigger: triggerName });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: triggerName,
|
||||
elementType: 'trigger',
|
||||
type: 'trigger-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
},
|
||||
showCreateRoutineModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewRoutineModal = true;
|
||||
},
|
||||
hideCreateRoutineModal () {
|
||||
@@ -393,6 +442,7 @@ export default {
|
||||
async openCreateRoutineEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
@@ -400,14 +450,22 @@ export default {
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedDatabase, procedure: payload.name });
|
||||
this.selectTab({ uid: this.workspace.uid, tab: 'prop' });
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, routine: payload.name });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'routine',
|
||||
type: 'routine-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
},
|
||||
showCreateFunctionModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewFunctionModal = true;
|
||||
},
|
||||
hideCreateFunctionModal () {
|
||||
@@ -415,6 +473,7 @@ export default {
|
||||
},
|
||||
showCreateTriggerFunctionModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewTriggerFunctionModal = true;
|
||||
},
|
||||
hideCreateTriggerFunctionModal () {
|
||||
@@ -422,6 +481,7 @@ export default {
|
||||
},
|
||||
showCreateSchedulerModal () {
|
||||
this.closeDatabaseContext();
|
||||
this.closeMiscFolderContext();
|
||||
this.isNewSchedulerModal = true;
|
||||
},
|
||||
hideCreateSchedulerModal () {
|
||||
@@ -430,6 +490,7 @@ export default {
|
||||
async openCreateFunctionEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
@@ -437,8 +498,15 @@ export default {
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedDatabase, function: payload.name });
|
||||
this.selectTab({ uid: this.workspace.uid, tab: 'prop' });
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, function: payload.name });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'function',
|
||||
type: 'function-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
@@ -446,6 +514,7 @@ export default {
|
||||
async openCreateTriggerFunctionEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
@@ -453,8 +522,15 @@ export default {
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedDatabase, triggerFunction: payload.name });
|
||||
this.selectTab({ uid: this.workspace.uid, tab: 'prop' });
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, triggerFunction: payload.name });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'triggerFunction',
|
||||
type: 'trigger-function-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
@@ -462,6 +538,7 @@ export default {
|
||||
async openCreateSchedulerEditor (payload) {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedSchema,
|
||||
...payload
|
||||
};
|
||||
|
||||
@@ -469,8 +546,15 @@ export default {
|
||||
|
||||
if (status === 'success') {
|
||||
await this.refresh();
|
||||
this.changeBreadcrumbs({ schema: this.selectedDatabase, scheduler: payload.name });
|
||||
this.selectTab({ uid: this.workspace.uid, tab: 'prop' });
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, scheduler: payload.name });
|
||||
|
||||
this.newTab({
|
||||
uid: this.workspace.uid,
|
||||
schema: this.selectedSchema,
|
||||
elementName: payload.name,
|
||||
elementType: 'scheduler',
|
||||
type: 'scheduler-props'
|
||||
});
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
|
@@ -59,7 +59,8 @@ export default {
|
||||
},
|
||||
props: {
|
||||
contextEvent: MouseEvent,
|
||||
selectedMisc: Object
|
||||
selectedMisc: Object,
|
||||
selectedSchema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -97,6 +98,7 @@ export default {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
removeTabs: 'workspaces/removeTabs',
|
||||
newTab: 'workspaces/newTab'
|
||||
}),
|
||||
showCreateTableModal () {
|
||||
@@ -126,12 +128,14 @@ export default {
|
||||
case 'trigger':
|
||||
res = await Triggers.dropTrigger({
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.selectedSchema,
|
||||
trigger: this.selectedMisc.name
|
||||
});
|
||||
break;
|
||||
case 'procedure':
|
||||
res = await Routines.dropRoutine({
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.selectedSchema,
|
||||
routine: this.selectedMisc.name
|
||||
});
|
||||
break;
|
||||
@@ -139,12 +143,14 @@ export default {
|
||||
case 'triggerFunction':
|
||||
res = await Functions.dropFunction({
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.selectedSchema,
|
||||
func: this.selectedMisc.name
|
||||
});
|
||||
break;
|
||||
case 'scheduler':
|
||||
res = await Schedulers.dropScheduler({
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.selectedSchema,
|
||||
scheduler: this.selectedMisc.name
|
||||
});
|
||||
break;
|
||||
@@ -153,7 +159,12 @@ export default {
|
||||
const { status, response } = res;
|
||||
|
||||
if (status === 'success') {
|
||||
this.changeBreadcrumbs({ [this.selectedMisc.type]: null });
|
||||
this.removeTabs({
|
||||
uid: this.selectedWorkspace,
|
||||
elementName: this.selectedMisc.name,
|
||||
elementType: this.selectedMisc.type,
|
||||
schema: this.selectedSchema
|
||||
});
|
||||
|
||||
this.closeContext();
|
||||
this.$emit('reload');
|
||||
@@ -180,8 +191,8 @@ export default {
|
||||
async runRoutineCheck () {
|
||||
const params = {
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.workspace.breadcrumbs.schema,
|
||||
routine: this.workspace.breadcrumbs.procedure
|
||||
schema: this.selectedSchema,
|
||||
routine: this.selectedMisc.name
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -218,14 +229,14 @@ export default {
|
||||
sql = `CALL \`${this.localElement.name}\`(${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.workspace.uid, content: sql, autorun: true });
|
||||
this.newTab({ uid: this.workspace.uid, content: sql, type: 'query', autorun: true });
|
||||
this.closeContext();
|
||||
},
|
||||
async runFunctionCheck () {
|
||||
const params = {
|
||||
uid: this.selectedWorkspace,
|
||||
schema: this.workspace.breadcrumbs.schema,
|
||||
func: this.workspace.breadcrumbs.function
|
||||
schema: this.selectedSchema,
|
||||
func: this.selectedMisc.name
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -263,7 +274,7 @@ export default {
|
||||
sql = `SELECT \`${this.localElement.name}\` (${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.workspace.uid, content: sql, autorun: true });
|
||||
this.newTab({ uid: this.workspace.uid, content: sql, type: 'query', autorun: true });
|
||||
this.closeContext();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<BaseContextMenu
|
||||
:context-event="contextEvent"
|
||||
@close-context="closeContext"
|
||||
>
|
||||
<div
|
||||
v-if="selectedMisc === 'trigger'"
|
||||
class="context-element"
|
||||
@click="$emit('show-create-trigger-modal')"
|
||||
>
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-table-cog text-light pr-1" /> {{ $t('message.createNewTrigger') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedMisc === 'procedure'"
|
||||
class="context-element"
|
||||
@click="$emit('show-create-routine-modal')"
|
||||
>
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-sync-circle text-light pr-1" /> {{ $t('message.createNewRoutine') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedMisc === 'function'"
|
||||
class="context-element"
|
||||
@click="$emit('show-create-function-modal')"
|
||||
>
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-arrow-right-bold-box text-light pr-1" /> {{ $t('message.createNewFunction') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedMisc === 'triggerFunction'"
|
||||
class="context-element"
|
||||
@click="$emit('show-create-trigger-function-modal')"
|
||||
>
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-cog-clockwise text-light pr-1" /> {{ $t('message.createNewFunction') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedMisc === 'scheduler'"
|
||||
class="context-element"
|
||||
@click="$emit('show-create-scheduler-modal')"
|
||||
>
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-calendar-clock text-light pr-1" /> {{ $t('message.createNewScheduler') }}</span>
|
||||
</div>
|
||||
</BaseContextMenu>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapActions } from 'vuex';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu';
|
||||
|
||||
export default {
|
||||
name: 'WorkspaceExploreBarMiscContext',
|
||||
components: {
|
||||
BaseContextMenu
|
||||
},
|
||||
props: {
|
||||
contextEvent: MouseEvent,
|
||||
selectedMisc: String,
|
||||
selectedSchema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
localElement: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
selectedWorkspace: 'workspaces/getSelected',
|
||||
getWorkspace: 'workspaces/getWorkspace'
|
||||
}),
|
||||
workspace () {
|
||||
return this.getWorkspace(this.selectedWorkspace);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
showCreateTableModal () {
|
||||
this.$emit('show-create-table-modal');
|
||||
},
|
||||
showDeleteModal () {
|
||||
this.isDeleteModal = true;
|
||||
},
|
||||
hideDeleteModal () {
|
||||
this.isDeleteModal = false;
|
||||
},
|
||||
showAskParamsModal () {
|
||||
this.isAskingParameters = true;
|
||||
},
|
||||
hideAskParamsModal () {
|
||||
this.isAskingParameters = false;
|
||||
this.closeContext();
|
||||
},
|
||||
closeContext () {
|
||||
this.$emit('close-context');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@@ -19,7 +19,8 @@
|
||||
:key="table.name"
|
||||
class="menu-item"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && [breadcrumbs.table, breadcrumbs.view].includes(table.name)}"
|
||||
@click="setBreadcrumbs({schema: database.name, [table.type]: table.name})"
|
||||
@mousedown.left="selectTable({schema: database.name, table})"
|
||||
@dblclick="openDataTab({schema: database.name, table})"
|
||||
@contextmenu.prevent="showTableContext($event, table)"
|
||||
>
|
||||
<a class="table-name">
|
||||
@@ -39,7 +40,11 @@
|
||||
|
||||
<div v-if="filteredTriggers.length && customizations.triggers" class="database-misc">
|
||||
<details class="accordion">
|
||||
<summary class="accordion-header misc-name" :class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.trigger}">
|
||||
<summary
|
||||
class="accordion-header misc-name"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.trigger}"
|
||||
@contextmenu.prevent="showMiscFolderContext($event, 'trigger')"
|
||||
>
|
||||
<i class="misc-icon mdi mdi-18px mdi-folder-cog mr-1" />
|
||||
{{ $tc('word.trigger', 2) }}
|
||||
</summary>
|
||||
@@ -51,7 +56,8 @@
|
||||
:key="trigger.name"
|
||||
class="menu-item"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.trigger === trigger.name}"
|
||||
@click="setBreadcrumbs({schema: database.name, trigger: trigger.name})"
|
||||
@mousedown="selectMisc({schema: database.name, misc: trigger, type: 'trigger'})"
|
||||
@dblclick="openMiscPermanentTab({schema: database.name, misc: trigger, type: 'trigger'})"
|
||||
@contextmenu.prevent="showMiscContext($event, {...trigger, type: 'trigger'})"
|
||||
>
|
||||
<a class="table-name">
|
||||
@@ -67,7 +73,11 @@
|
||||
|
||||
<div v-if="filteredProcedures.length && customizations.routines" class="database-misc">
|
||||
<details class="accordion">
|
||||
<summary class="accordion-header misc-name" :class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.procedure}">
|
||||
<summary
|
||||
class="accordion-header misc-name"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.routine}"
|
||||
@contextmenu.prevent="showMiscFolderContext($event, 'procedure')"
|
||||
>
|
||||
<i class="misc-icon mdi mdi-18px mdi-folder-sync mr-1" />
|
||||
{{ $tc('word.storedRoutine', 2) }}
|
||||
</summary>
|
||||
@@ -78,8 +88,9 @@
|
||||
v-for="(procedure, i) of filteredProcedures"
|
||||
:key="`${procedure.name}-${i}`"
|
||||
class="menu-item"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.procedure === procedure.name}"
|
||||
@click="setBreadcrumbs({schema: database.name, procedure: procedure.name})"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.routine === procedure.name}"
|
||||
@mousedown="selectMisc({schema: database.name, misc: procedure, type: 'routine'})"
|
||||
@dblclick="openMiscPermanentTab({schema: database.name, misc: procedure, type: 'routine'})"
|
||||
@contextmenu.prevent="showMiscContext($event, {...procedure, type: 'procedure'})"
|
||||
>
|
||||
<a class="table-name">
|
||||
@@ -95,7 +106,11 @@
|
||||
|
||||
<div v-if="filteredTriggerFunctions.length && customizations.triggerFunctions" class="database-misc">
|
||||
<details class="accordion">
|
||||
<summary class="accordion-header misc-name" :class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.triggerFunction}">
|
||||
<summary
|
||||
class="accordion-header misc-name"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.triggerFunction}"
|
||||
@contextmenu.prevent="showMiscFolderContext($event, 'triggerFunction')"
|
||||
>
|
||||
<i class="misc-icon mdi mdi-18px mdi-folder-refresh mr-1" />
|
||||
{{ $tc('word.triggerFunction', 2) }}
|
||||
</summary>
|
||||
@@ -107,7 +122,8 @@
|
||||
:key="`${func.name}-${i}`"
|
||||
class="menu-item"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.triggerFunction === func.name}"
|
||||
@click="setBreadcrumbs({schema: database.name, triggerFunction: func.name})"
|
||||
@mousedown="selectMisc({schema: database.name, misc: func, type: 'triggerFunction'})"
|
||||
@dblclick="openMiscPermanentTab({schema: database.name, misc: func, type: 'triggerFunction'})"
|
||||
@contextmenu.prevent="showMiscContext($event, {...func, type: 'triggerFunction'})"
|
||||
>
|
||||
<a class="table-name">
|
||||
@@ -123,7 +139,11 @@
|
||||
|
||||
<div v-if="filteredFunctions.length && customizations.functions" class="database-misc">
|
||||
<details class="accordion">
|
||||
<summary class="accordion-header misc-name" :class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.function}">
|
||||
<summary
|
||||
class="accordion-header misc-name"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.function}"
|
||||
@contextmenu.prevent="showMiscFolderContext($event, 'function')"
|
||||
>
|
||||
<i class="misc-icon mdi mdi-18px mdi-folder-move mr-1" />
|
||||
{{ $tc('word.function', 2) }}
|
||||
</summary>
|
||||
@@ -135,7 +155,8 @@
|
||||
:key="`${func.name}-${i}`"
|
||||
class="menu-item"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.function === func.name}"
|
||||
@click="setBreadcrumbs({schema: database.name, function: func.name})"
|
||||
@mousedown="selectMisc({schema: database.name, misc: func, type: 'function'})"
|
||||
@dblclick="openMiscPermanentTab({schema: database.name, misc: func, type: 'function'})"
|
||||
@contextmenu.prevent="showMiscContext($event, {...func, type: 'function'})"
|
||||
>
|
||||
<a class="table-name">
|
||||
@@ -151,7 +172,11 @@
|
||||
|
||||
<div v-if="filteredSchedulers.length && customizations.schedulers" class="database-misc">
|
||||
<details class="accordion">
|
||||
<summary class="accordion-header misc-name" :class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.scheduler}">
|
||||
<summary
|
||||
class="accordion-header misc-name"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.scheduler}"
|
||||
@contextmenu.prevent="showMiscFolderContext($event, 'scheduler')"
|
||||
>
|
||||
<i class="misc-icon mdi mdi-18px mdi-folder-clock mr-1" />
|
||||
{{ $tc('word.scheduler', 2) }}
|
||||
</summary>
|
||||
@@ -163,7 +188,8 @@
|
||||
:key="scheduler.name"
|
||||
class="menu-item"
|
||||
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.scheduler === scheduler.name}"
|
||||
@click="setBreadcrumbs({schema: database.name, scheduler: scheduler.name})"
|
||||
@mousedown="selectMisc({schema: database.name, misc: scheduler, type: 'scheduler'})"
|
||||
@dblclick="openMiscPermanentTab({schema: database.name, misc: scheduler, type: 'scheduler'})"
|
||||
@contextmenu.prevent="showMiscContext($event, {...scheduler, type: 'scheduler'})"
|
||||
>
|
||||
<a class="table-name">
|
||||
@@ -247,29 +273,77 @@ export default {
|
||||
methods: {
|
||||
...mapActions({
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
addLoadedSchema: 'workspaces/addLoadedSchema',
|
||||
newTab: 'workspaces/newTab',
|
||||
refreshSchema: 'workspaces/refreshSchema'
|
||||
}),
|
||||
formatBytes,
|
||||
async selectSchema (schema) {
|
||||
if (!this.loadedSchemas.has(schema)) {
|
||||
if (!this.loadedSchemas.has(schema) && !this.isLoading) {
|
||||
this.isLoading = true;
|
||||
await this.refreshSchema({ uid: this.connection.uid, schema });
|
||||
this.addLoadedSchema(schema);
|
||||
this.isLoading = false;
|
||||
}
|
||||
|
||||
this.changeBreadcrumbs({ schema, table: null });
|
||||
},
|
||||
selectTable ({ schema, table }) {
|
||||
this.newTab({ uid: this.connection.uid, elementName: table.name, schema: this.database.name, type: 'temp-data', elementType: table.type });
|
||||
this.setBreadcrumbs({ schema, [table.type]: table.name });
|
||||
},
|
||||
selectMisc ({ schema, misc, type }) {
|
||||
const miscTempTabs = {
|
||||
trigger: 'temp-trigger-props',
|
||||
triggerFunction: 'temp-trigger-function-props',
|
||||
function: 'temp-function-props',
|
||||
routine: 'temp-routine-props',
|
||||
scheduler: 'temp-scheduler-props'
|
||||
};
|
||||
|
||||
this.newTab({
|
||||
uid: this.connection.uid,
|
||||
elementName: misc.name,
|
||||
schema: this.database.name,
|
||||
type: miscTempTabs[type],
|
||||
elementType: type
|
||||
});
|
||||
|
||||
this.setBreadcrumbs({ schema, [type]: misc.name });
|
||||
},
|
||||
openDataTab ({ schema, table }) {
|
||||
this.newTab({ uid: this.connection.uid, elementName: table.name, schema: this.database.name, type: 'data', elementType: table.type });
|
||||
this.setBreadcrumbs({ schema, [table.type]: table.name });
|
||||
},
|
||||
openMiscPermanentTab ({ schema, misc, type }) {
|
||||
const miscTabs = {
|
||||
trigger: 'trigger-props',
|
||||
triggerFunction: 'trigger-function-props',
|
||||
function: 'function-props',
|
||||
routine: 'routine-props',
|
||||
scheduler: 'scheduler-props'
|
||||
};
|
||||
|
||||
this.newTab({
|
||||
uid: this.connection.uid,
|
||||
elementName: misc.name,
|
||||
schema: this.database.name,
|
||||
type: miscTabs[type],
|
||||
elementType: type
|
||||
});
|
||||
this.setBreadcrumbs({ schema, [type]: misc.name });
|
||||
},
|
||||
showSchemaContext (event, schema) {
|
||||
this.selectSchema(schema);
|
||||
this.$emit('show-schema-context', { event, schema });
|
||||
},
|
||||
showTableContext (event, table) {
|
||||
this.setBreadcrumbs({ schema: this.database.name, [table.type]: table.name });
|
||||
this.$emit('show-table-context', { event, table });
|
||||
this.$emit('show-table-context', { event, schema: this.database.name, table });
|
||||
},
|
||||
showMiscContext (event, misc) {
|
||||
this.setBreadcrumbs({ schema: this.database.name, [misc.type]: misc.name });
|
||||
this.$emit('show-misc-context', { event, misc });
|
||||
this.$emit('show-misc-context', { event, schema: this.database.name, misc });
|
||||
},
|
||||
showMiscFolderContext (event, type) {
|
||||
this.$emit('show-misc-folder-context', { event, schema: this.database.name, type });
|
||||
},
|
||||
piePercentage (val) {
|
||||
const perc = val / this.maxSize * 100;
|
||||
@@ -283,6 +357,8 @@ export default {
|
||||
this.changeBreadcrumbs(payload);
|
||||
},
|
||||
highlightWord (string) {
|
||||
string = string.replaceAll('<', '<').replaceAll('>', '>');
|
||||
|
||||
if (this.searchTerm) {
|
||||
const regexp = new RegExp(`(${this.searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
|
||||
return string.replace(regexp, '<span class="text-primary">$1</span>');
|
||||
|
@@ -82,13 +82,13 @@
|
||||
</template>
|
||||
<div slot="body">
|
||||
<div class="mb-2">
|
||||
{{ $t('message.deleteCorfirm') }} "<b>{{ selectedDatabase }}</b>"?
|
||||
{{ $t('message.deleteCorfirm') }} "<b>{{ selectedSchema }}</b>"?
|
||||
</div>
|
||||
</div>
|
||||
</ConfirmModal>
|
||||
<ModalEditSchema
|
||||
v-if="isEditModal"
|
||||
:selected-database="selectedDatabase"
|
||||
:selected-schema="selectedSchema"
|
||||
@close="hideEditModal"
|
||||
/>
|
||||
</BaseContextMenu>
|
||||
@@ -110,7 +110,7 @@ export default {
|
||||
},
|
||||
props: {
|
||||
contextEvent: MouseEvent,
|
||||
selectedDatabase: String
|
||||
selectedSchema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -173,11 +173,11 @@ export default {
|
||||
try {
|
||||
const { status, response } = await Schema.deleteSchema({
|
||||
uid: this.selectedWorkspace,
|
||||
database: this.selectedDatabase
|
||||
database: this.selectedSchema
|
||||
});
|
||||
|
||||
if (status === 'success') {
|
||||
if (this.selectedDatabase === this.workspace.breadcrumbs.schema)
|
||||
if (this.selectedSchema === this.workspace.breadcrumbs.schema)
|
||||
this.changeBreadcrumbs({ schema: null });
|
||||
|
||||
this.closeContext();
|
||||
|
@@ -3,6 +3,20 @@
|
||||
:context-event="contextEvent"
|
||||
@close-context="closeContext"
|
||||
>
|
||||
<div
|
||||
v-if="selectedTable.type === 'table' && workspace.customizations.tableSettings"
|
||||
class="context-element"
|
||||
@click="openTableSettingTab"
|
||||
>
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-tune-vertical-variant text-light pr-1" /> {{ $t('word.settings') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedTable.type === 'view' && workspace.customizations.viewSettings"
|
||||
class="context-element"
|
||||
@click="openViewSettingTab"
|
||||
>
|
||||
<span class="d-flex"><i class="mdi mdi-18px mdi-tune-vertical-variant text-light pr-1" /> {{ $t('word.settings') }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedTable.type === 'table'"
|
||||
class="context-element"
|
||||
@@ -72,7 +86,8 @@ export default {
|
||||
},
|
||||
props: {
|
||||
contextEvent: MouseEvent,
|
||||
selectedTable: Object
|
||||
selectedTable: Object,
|
||||
selectedSchema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -92,6 +107,8 @@ export default {
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
newTab: 'workspaces/newTab',
|
||||
removeTabs: 'workspaces/removeTabs',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
showCreateTableModal () {
|
||||
@@ -112,11 +129,44 @@ export default {
|
||||
closeContext () {
|
||||
this.$emit('close-context');
|
||||
},
|
||||
openTableSettingTab () {
|
||||
this.newTab({
|
||||
uid: this.selectedWorkspace,
|
||||
elementName: this.selectedTable.name,
|
||||
schema: this.selectedSchema,
|
||||
type: 'table-props',
|
||||
elementType: 'table'
|
||||
});
|
||||
|
||||
this.changeBreadcrumbs({
|
||||
schema: this.selectedSchema,
|
||||
table: this.selectedTable.name
|
||||
});
|
||||
|
||||
this.closeContext();
|
||||
},
|
||||
openViewSettingTab () {
|
||||
this.newTab({
|
||||
uid: this.selectedWorkspace,
|
||||
elementType: 'table',
|
||||
elementName: this.selectedTable.name,
|
||||
schema: this.selectedSchema,
|
||||
type: 'view-props'
|
||||
});
|
||||
|
||||
this.changeBreadcrumbs({
|
||||
schema: this.selectedSchema,
|
||||
view: this.selectedTable.name
|
||||
});
|
||||
|
||||
this.closeContext();
|
||||
},
|
||||
async duplicateTable () {
|
||||
try {
|
||||
const { status, response } = await Tables.duplicateTable({
|
||||
uid: this.selectedWorkspace,
|
||||
table: this.selectedTable.name
|
||||
table: this.selectedTable.name,
|
||||
schema: this.selectedSchema
|
||||
});
|
||||
|
||||
if (status === 'success') {
|
||||
@@ -134,13 +184,11 @@ export default {
|
||||
try {
|
||||
const { status, response } = await Tables.truncateTable({
|
||||
uid: this.selectedWorkspace,
|
||||
table: this.selectedTable.name
|
||||
table: this.selectedTable.name,
|
||||
schema: this.selectedSchema
|
||||
});
|
||||
|
||||
if (status === 'success') {
|
||||
if (this.selectedTable.name === this.workspace.breadcrumbs.table)
|
||||
this.changeBreadcrumbs({ table: null });
|
||||
|
||||
this.closeContext();
|
||||
this.$emit('reload');
|
||||
}
|
||||
@@ -158,21 +206,27 @@ export default {
|
||||
if (this.selectedTable.type === 'table') {
|
||||
res = await Tables.dropTable({
|
||||
uid: this.selectedWorkspace,
|
||||
table: this.selectedTable.name
|
||||
table: this.selectedTable.name,
|
||||
schema: this.selectedSchema
|
||||
});
|
||||
}
|
||||
else if (this.selectedTable.type === 'view') {
|
||||
res = await Views.dropView({
|
||||
uid: this.selectedWorkspace,
|
||||
view: this.selectedTable.name
|
||||
view: this.selectedTable.name,
|
||||
schema: this.selectedSchema
|
||||
});
|
||||
}
|
||||
|
||||
const { status, response } = res;
|
||||
|
||||
if (status === 'success') {
|
||||
if (this.selectedTable.name === this.workspace.breadcrumbs.table || this.selectedTable.name === this.workspace.breadcrumbs.view)
|
||||
this.changeBreadcrumbs({ table: null, view: null });
|
||||
this.removeTabs({
|
||||
uid: this.selectedWorkspace,
|
||||
elementName: this.selectedTable.name,
|
||||
elementType: this.selectedTable.type,
|
||||
schema: this.selectedSchema
|
||||
});
|
||||
|
||||
this.closeContext();
|
||||
this.$emit('reload');
|
||||
|
@@ -19,8 +19,8 @@
|
||||
<div class="panel-header pt-0 pl-0">
|
||||
<div class="d-flex">
|
||||
<button class="btn btn-dark btn-sm d-flex" @click="addForeign">
|
||||
<i class="mdi mdi-24px mdi-link-plus mr-1" />
|
||||
<span>{{ $t('word.add') }}</span>
|
||||
<i class="mdi mdi-24px mdi-link-plus ml-1" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm d-flex ml-2 mr-0"
|
||||
@@ -28,8 +28,8 @@
|
||||
:disabled="!isChanged"
|
||||
@click.prevent="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -267,6 +267,12 @@ export default {
|
||||
addNotification: 'notifications/addNotification'
|
||||
}),
|
||||
confirmForeignsChange () {
|
||||
this.foreignProxy = this.foreignProxy.filter(foreign =>
|
||||
foreign.field &&
|
||||
foreign.refField &&
|
||||
foreign.table &&
|
||||
foreign.refTable
|
||||
);
|
||||
this.$emit('foreigns-update', this.foreignProxy);
|
||||
},
|
||||
selectForeign (event, id) {
|
||||
@@ -331,6 +337,8 @@ export default {
|
||||
this.selectedForeignID = this.foreignProxy.length ? this.foreignProxy[0]._id : '';
|
||||
},
|
||||
async getRefFields () {
|
||||
if (!this.selectedForeignObj.refTable) return;
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.selectedForeignObj.refSchema,
|
||||
|
@@ -19,8 +19,8 @@
|
||||
<div class="panel-header pt-0 pl-0">
|
||||
<div class="d-flex">
|
||||
<button class="btn btn-dark btn-sm d-flex" @click="addParameter">
|
||||
<i class="mdi mdi-24px mdi-plus mr-1" />
|
||||
<span>{{ $t('word.add') }}</span>
|
||||
<i class="mdi mdi-24px mdi-plus ml-1" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm d-flex ml-2 mr-0"
|
||||
@@ -28,8 +28,8 @@
|
||||
:disabled="!isChanged"
|
||||
@click.prevent="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -19,8 +19,8 @@
|
||||
<div class="panel-header pt-0 pl-0">
|
||||
<div class="d-flex">
|
||||
<button class="btn btn-dark btn-sm d-flex" @click="addIndex">
|
||||
<i class="mdi mdi-24px mdi-key-plus mr-1" />
|
||||
<span>{{ $t('word.add') }}</span>
|
||||
<i class="mdi mdi-24px mdi-key-plus ml-1" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm d-flex ml-2 mr-0"
|
||||
@@ -28,8 +28,8 @@
|
||||
:disabled="!isChanged"
|
||||
@click.prevent="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -186,6 +186,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
confirmIndexesChange () {
|
||||
this.indexesProxy = this.indexesProxy.filter(index => index.fields.length);
|
||||
this.$emit('indexes-update', this.indexesProxy);
|
||||
},
|
||||
selectIndex (event, id) {
|
||||
|
@@ -19,8 +19,8 @@
|
||||
<div class="panel-header pt-0 pl-0">
|
||||
<div class="d-flex">
|
||||
<button class="btn btn-dark btn-sm d-flex" @click="addParameter">
|
||||
<i class="mdi mdi-24px mdi-plus mr-1" />
|
||||
<span>{{ $t('word.add') }}</span>
|
||||
<i class="mdi mdi-24px mdi-plus ml-1" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm d-flex ml-2 mr-0"
|
||||
@@ -28,8 +28,8 @@
|
||||
:disabled="!isChanged"
|
||||
@click.prevent="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
@@ -10,46 +10,61 @@
|
||||
title="CTRL+S"
|
||||
@click="saveChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
<span>{{ $t('word.save') }}</span>
|
||||
<i class="mdi mdi-24px mdi-content-save ml-1" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="!isChanged"
|
||||
:disabled="!isChanged || isSaving"
|
||||
class="btn btn-link btn-sm mr-0"
|
||||
:title="$t('message.clearChanges')"
|
||||
@click="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
|
||||
<div class="divider-vert py-3" />
|
||||
|
||||
<button
|
||||
:disabled="isSaving"
|
||||
class="btn btn-dark btn-sm"
|
||||
:title="$t('message.addNewField')"
|
||||
@click="addField"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
|
||||
<span>{{ $t('word.add') }}</span>
|
||||
<i class="mdi mdi-24px mdi-playlist-plus ml-1" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="isSaving"
|
||||
class="btn btn-dark btn-sm"
|
||||
:title="$t('message.manageIndexes')"
|
||||
@click="showIntdexesModal"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-key mdi-rotate-45 mr-1" />
|
||||
<span>{{ $t('word.indexes') }}</span>
|
||||
<i class="mdi mdi-24px mdi-key mdi-rotate-45 ml-1" />
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm" @click="showForeignModal">
|
||||
<button
|
||||
class="btn btn-dark btn-sm"
|
||||
:disabled="isSaving"
|
||||
@click="showForeignModal"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-key-link mr-1" />
|
||||
<span>{{ $t('word.foreignKeys') }}</span>
|
||||
<i class="mdi mdi-24px mdi-key-link ml-1" />
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm" @click="showOptionsModal">
|
||||
<button
|
||||
class="btn btn-dark btn-sm"
|
||||
:disabled="isSaving"
|
||||
@click="showOptionsModal"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-cogs mr-1" />
|
||||
<span>{{ $t('word.options') }}</span>
|
||||
<i class="mdi mdi-24px mdi-cogs ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
<div class="d-flex" :title="$t('word.schema')">
|
||||
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workspace-query-results column col-12 p-relative">
|
||||
@@ -126,11 +141,12 @@ export default {
|
||||
},
|
||||
props: {
|
||||
connection: Object,
|
||||
table: String
|
||||
isSelected: Boolean,
|
||||
table: String,
|
||||
schema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'prop',
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isOptionsModal: false,
|
||||
@@ -157,6 +173,9 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
tableOptions () {
|
||||
const db = this.workspace.structure.find(db => db.name === this.schema);
|
||||
return db && this.table ? db.tables.find(table => table.name === this.table) : {};
|
||||
@@ -164,12 +183,6 @@ export default {
|
||||
defaultEngine () {
|
||||
return this.getDatabaseVariable(this.connection.uid, 'default_storage_engine').value || '';
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.table;
|
||||
},
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
},
|
||||
schemaTables () {
|
||||
const schemaTables = this.workspace.structure
|
||||
.filter(schema => schema.name === this.schema)
|
||||
@@ -185,6 +198,12 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
schema () {
|
||||
if (this.isSelected) {
|
||||
this.getFieldsData();
|
||||
this.lastTable = this.table;
|
||||
}
|
||||
},
|
||||
table () {
|
||||
if (this.isSelected) {
|
||||
this.getFieldsData();
|
||||
@@ -192,17 +211,19 @@ export default {
|
||||
}
|
||||
},
|
||||
isSelected (val) {
|
||||
if (val && this.lastTable !== this.table) {
|
||||
this.getFieldsData();
|
||||
this.lastTable = this.table;
|
||||
if (val) {
|
||||
this.changeBreadcrumbs({ schema: this.schema, table: this.table });
|
||||
|
||||
if (this.lastTable !== this.table)
|
||||
this.getFieldsData();
|
||||
}
|
||||
},
|
||||
isChanged (val) {
|
||||
if (this.isSelected && this.lastTable === this.table && this.table !== null)
|
||||
this.setUnsavedChanges(val);
|
||||
this.setUnsavedChanges({ uid: this.connection.uid, tUid: this.tabUid, isChanged: val });
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getFieldsData();
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
@@ -213,20 +234,25 @@ export default {
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
async getFieldsData () {
|
||||
if (!this.table) return;
|
||||
|
||||
this.localFields = [];
|
||||
this.lastTable = this.table;
|
||||
this.newFieldsCounter = 0;
|
||||
this.isLoading = true;
|
||||
this.localOptions = JSON.parse(JSON.stringify(this.tableOptions));
|
||||
try {
|
||||
this.localOptions = JSON.parse(JSON.stringify(this.tableOptions));
|
||||
}
|
||||
catch (err) {}
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
table: this.workspace.breadcrumbs.table
|
||||
table: this.table
|
||||
};
|
||||
|
||||
try { // Columns data
|
||||
@@ -410,7 +436,7 @@ export default {
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
table: this.workspace.breadcrumbs.table,
|
||||
table: this.table,
|
||||
additions,
|
||||
changes,
|
||||
deletions,
|
||||
@@ -428,11 +454,18 @@ export default {
|
||||
await this.refreshStructure(this.connection.uid);
|
||||
|
||||
if (oldName !== this.localOptions.name) {
|
||||
this.setUnsavedChanges(false);
|
||||
this.renameTabs({
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
elementName: oldName,
|
||||
elementNewName: this.localOptions.name,
|
||||
elementType: 'table'
|
||||
});
|
||||
|
||||
this.changeBreadcrumbs({ schema: this.schema, table: this.localOptions.name });
|
||||
}
|
||||
|
||||
this.getFieldsData();
|
||||
else
|
||||
this.getFieldsData();
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
@@ -10,8 +10,8 @@
|
||||
title="CTRL+S"
|
||||
@click="saveChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
<span>{{ $t('word.save') }}</span>
|
||||
<i class="mdi mdi-24px mdi-content-save ml-1" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="!isChanged"
|
||||
@@ -19,8 +19,8 @@
|
||||
:title="$t('message.clearChanges')"
|
||||
@click="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
|
||||
<div class="divider-vert py-3" />
|
||||
@@ -30,18 +30,23 @@
|
||||
:disabled="isChanged"
|
||||
@click="runFunctionCheck"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-play mr-1" />
|
||||
<span>{{ $t('word.run') }}</span>
|
||||
<i class="mdi mdi-24px mdi-play ml-1" />
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm" @click="showParamsModal">
|
||||
<i class="mdi mdi-24px mdi-dots-horizontal mr-1" />
|
||||
<span>{{ $t('word.parameters') }}</span>
|
||||
<i class="mdi mdi-24px mdi-dots-horizontal ml-1" />
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm" @click="showOptionsModal">
|
||||
<i class="mdi mdi-24px mdi-cogs mr-1" />
|
||||
<span>{{ $t('word.options') }}</span>
|
||||
<i class="mdi mdi-24px mdi-cogs ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
<div class="d-flex" :title="$t('word.schema')">
|
||||
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workspace-query-results column col-12 mt-2 p-relative">
|
||||
@@ -102,11 +107,12 @@ export default {
|
||||
},
|
||||
props: {
|
||||
connection: Object,
|
||||
function: String
|
||||
function: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'prop',
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isOptionsModal: false,
|
||||
@@ -127,11 +133,8 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.function;
|
||||
},
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalFunction) !== JSON.stringify(this.localFunction);
|
||||
@@ -150,6 +153,13 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async schema () {
|
||||
if (this.isSelected) {
|
||||
await this.getFunctionData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localFunction.sql);
|
||||
this.lastFunction = this.function;
|
||||
}
|
||||
},
|
||||
async function () {
|
||||
if (this.isSelected) {
|
||||
await this.getFunctionData();
|
||||
@@ -158,26 +168,32 @@ export default {
|
||||
}
|
||||
},
|
||||
async isSelected (val) {
|
||||
if (val && this.lastFunction !== this.function) {
|
||||
await this.getFunctionData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localFunction.sql);
|
||||
this.lastFunction = this.function;
|
||||
if (val) {
|
||||
this.changeBreadcrumbs({ schema: this.schema, function: this.function });
|
||||
|
||||
setTimeout(() => {
|
||||
this.resizeQueryEditor();
|
||||
}, 200);
|
||||
|
||||
if (this.lastFunction !== this.function)
|
||||
this.getRoutineData();
|
||||
}
|
||||
},
|
||||
isChanged (val) {
|
||||
if (this.isSelected && this.lastFunction === this.function && this.function !== null)
|
||||
this.setUnsavedChanges(val);
|
||||
this.setUnsavedChanges({ uid: this.connection.uid, tUid: this.tabUid, isChanged: val });
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.getFunctionData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localFunction.sql);
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
@@ -185,20 +201,22 @@ export default {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
newTab: 'workspaces/newTab'
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getFunctionData () {
|
||||
if (!this.function) return;
|
||||
|
||||
this.isLoading = true;
|
||||
this.localFunction = { sql: '' };
|
||||
this.lastFunction = this.function;
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
func: this.workspace.breadcrumbs.function
|
||||
func: this.function
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -229,9 +247,9 @@ export default {
|
||||
this.isSaving = true;
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
func: {
|
||||
...this.localFunction,
|
||||
schema: this.schema,
|
||||
oldName: this.originalFunction.name
|
||||
}
|
||||
};
|
||||
@@ -245,11 +263,18 @@ export default {
|
||||
await this.refreshStructure(this.connection.uid);
|
||||
|
||||
if (oldName !== this.localFunction.name) {
|
||||
this.setUnsavedChanges(false);
|
||||
this.renameTabs({
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
elementName: oldName,
|
||||
elementNewName: this.localFunction.name,
|
||||
elementType: 'function'
|
||||
});
|
||||
|
||||
this.changeBreadcrumbs({ schema: this.schema, function: this.localFunction.name });
|
||||
}
|
||||
|
||||
this.getFunctionData();
|
||||
else
|
||||
this.getFunctionData();
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
@@ -303,7 +328,7 @@ export default {
|
||||
sql = `SELECT \`${this.originalFunction.name}\` (${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.connection.uid, content: sql, autorun: true });
|
||||
this.newTab({ uid: this.connection.uid, content: sql, type: 'query', autorun: true });
|
||||
},
|
||||
showOptionsModal () {
|
||||
this.isOptionsModal = true;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
@@ -10,8 +10,8 @@
|
||||
title="CTRL+S"
|
||||
@click="saveChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
<span>{{ $t('word.save') }}</span>
|
||||
<i class="mdi mdi-24px mdi-content-save ml-1" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="!isChanged"
|
||||
@@ -19,8 +19,8 @@
|
||||
:title="$t('message.clearChanges')"
|
||||
@click="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
|
||||
<div class="divider-vert py-3" />
|
||||
@@ -30,18 +30,23 @@
|
||||
:disabled="isChanged"
|
||||
@click="runRoutineCheck"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-play mr-1" />
|
||||
<span>{{ $t('word.run') }}</span>
|
||||
<i class="mdi mdi-24px mdi-play ml-1" />
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm" @click="showParamsModal">
|
||||
<i class="mdi mdi-24px mdi-dots-horizontal mr-1" />
|
||||
<span>{{ $t('word.parameters') }}</span>
|
||||
<i class="mdi mdi-24px mdi-dots-horizontal ml-1" />
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm" @click="showOptionsModal">
|
||||
<i class="mdi mdi-24px mdi-cogs mr-1" />
|
||||
<span>{{ $t('word.options') }}</span>
|
||||
<i class="mdi mdi-24px mdi-cogs ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
<div class="d-flex" :title="$t('word.schema')">
|
||||
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="workspace-query-results column col-12 mt-2 p-relative">
|
||||
@@ -103,11 +108,12 @@ export default {
|
||||
},
|
||||
props: {
|
||||
connection: Object,
|
||||
routine: String
|
||||
routine: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'prop',
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isOptionsModal: false,
|
||||
@@ -128,11 +134,8 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.routine;
|
||||
},
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalRoutine) !== JSON.stringify(this.localRoutine);
|
||||
@@ -149,6 +152,13 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async schema () {
|
||||
if (this.isSelected) {
|
||||
await this.getRoutineData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localRoutine.sql);
|
||||
this.lastRoutine = this.routine;
|
||||
}
|
||||
},
|
||||
async routine () {
|
||||
if (this.isSelected) {
|
||||
await this.getRoutineData();
|
||||
@@ -157,26 +167,32 @@ export default {
|
||||
}
|
||||
},
|
||||
async isSelected (val) {
|
||||
if (val && this.lastRoutine !== this.routine) {
|
||||
await this.getRoutineData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localRoutine.sql);
|
||||
this.lastRoutine = this.routine;
|
||||
if (val) {
|
||||
this.changeBreadcrumbs({ schema: this.schema, routine: this.routine });
|
||||
|
||||
setTimeout(() => {
|
||||
this.resizeQueryEditor();
|
||||
}, 200);
|
||||
|
||||
if (this.lastRoutine !== this.routine)
|
||||
this.getRoutineData();
|
||||
}
|
||||
},
|
||||
isChanged (val) {
|
||||
if (this.isSelected && this.lastRoutine === this.routine && this.routine !== null)
|
||||
this.setUnsavedChanges(val);
|
||||
this.setUnsavedChanges({ uid: this.connection.uid, tUid: this.tabUid, isChanged: val });
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.getRoutineData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localRoutine.sql);
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
@@ -184,19 +200,22 @@ export default {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
newTab: 'workspaces/newTab'
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getRoutineData () {
|
||||
if (!this.routine) return;
|
||||
|
||||
this.localRoutine = { sql: '' };
|
||||
this.isLoading = true;
|
||||
this.lastRoutine = this.routine;
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
routine: this.workspace.breadcrumbs.procedure
|
||||
routine: this.routine
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -227,9 +246,9 @@ export default {
|
||||
this.isSaving = true;
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
routine: {
|
||||
...this.localRoutine,
|
||||
schema: this.schema,
|
||||
oldName: this.originalRoutine.name
|
||||
}
|
||||
};
|
||||
@@ -243,11 +262,18 @@ export default {
|
||||
await this.refreshStructure(this.connection.uid);
|
||||
|
||||
if (oldName !== this.localRoutine.name) {
|
||||
this.setUnsavedChanges(false);
|
||||
this.renameTabs({
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
elementName: oldName,
|
||||
elementNewName: this.localRoutine.name,
|
||||
elementType: 'procedure'
|
||||
});
|
||||
|
||||
this.changeBreadcrumbs({ schema: this.schema, procedure: this.localRoutine.name });
|
||||
}
|
||||
|
||||
this.getRoutineData();
|
||||
else
|
||||
this.getRoutineData();
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
@@ -299,7 +325,7 @@ export default {
|
||||
sql = `CALL \`${this.originalRoutine.name}\`(${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.connection.uid, content: sql, autorun: true });
|
||||
this.newTab({ uid: this.connection.uid, content: sql, type: 'query', autorun: true });
|
||||
},
|
||||
showOptionsModal () {
|
||||
this.isOptionsModal = true;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
@@ -10,8 +10,8 @@
|
||||
title="CTRL+S"
|
||||
@click="saveChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
<span>{{ $t('word.save') }}</span>
|
||||
<i class="mdi mdi-24px mdi-content-save ml-1" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="!isChanged"
|
||||
@@ -19,16 +19,21 @@
|
||||
:title="$t('message.clearChanges')"
|
||||
@click="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
|
||||
<div class="divider-vert py-3" />
|
||||
<button class="btn btn-dark btn-sm" @click="showTimingModal">
|
||||
<i class="mdi mdi-24px mdi-timer mr-1" />
|
||||
<span>{{ $t('word.timing') }}</span>
|
||||
<i class="mdi mdi-24px mdi-timer ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
<div class="d-flex" :title="$t('word.schema')">
|
||||
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
@@ -153,11 +158,12 @@ export default {
|
||||
},
|
||||
props: {
|
||||
connection: Object,
|
||||
scheduler: String
|
||||
scheduler: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'prop',
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isTimingModal: false,
|
||||
@@ -176,11 +182,8 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.scheduler;
|
||||
},
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalScheduler) !== JSON.stringify(this.localScheduler);
|
||||
@@ -197,6 +200,13 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async schema () {
|
||||
if (this.isSelected) {
|
||||
await this.getSchedulerData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localScheduler.sql);
|
||||
this.lastScheduler = this.scheduler;
|
||||
}
|
||||
},
|
||||
async scheduler () {
|
||||
if (this.isSelected) {
|
||||
await this.getSchedulerData();
|
||||
@@ -205,26 +215,32 @@ export default {
|
||||
}
|
||||
},
|
||||
async isSelected (val) {
|
||||
if (val && this.lastScheduler !== this.scheduler) {
|
||||
await this.getSchedulerData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localScheduler.sql);
|
||||
this.lastScheduler = this.scheduler;
|
||||
if (val) {
|
||||
this.changeBreadcrumbs({ schema: this.schema, scheduler: this.scheduler });
|
||||
|
||||
setTimeout(() => {
|
||||
this.resizeQueryEditor();
|
||||
}, 200);
|
||||
|
||||
if (this.lastScheduler !== this.scheduler)
|
||||
this.getSchedulerData();
|
||||
}
|
||||
},
|
||||
isChanged (val) {
|
||||
if (this.isSelected && this.lastScheduler === this.scheduler && this.scheduler !== null)
|
||||
this.setUnsavedChanges(val);
|
||||
this.setUnsavedChanges({ uid: this.connection.uid, tUid: this.tabUid, isChanged: val });
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.getSchedulerData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localScheduler.sql);
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
@@ -232,17 +248,21 @@ export default {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getSchedulerData () {
|
||||
if (!this.scheduler) return;
|
||||
|
||||
this.isLoading = true;
|
||||
this.lastScheduler = this.scheduler;
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
scheduler: this.workspace.breadcrumbs.scheduler
|
||||
scheduler: this.scheduler
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -267,9 +287,9 @@ export default {
|
||||
this.isSaving = true;
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
scheduler: {
|
||||
...this.localScheduler,
|
||||
schema: this.schema,
|
||||
oldName: this.originalScheduler.name
|
||||
}
|
||||
};
|
||||
@@ -283,11 +303,18 @@ export default {
|
||||
await this.refreshStructure(this.connection.uid);
|
||||
|
||||
if (oldName !== this.localScheduler.name) {
|
||||
this.setUnsavedChanges(false);
|
||||
this.renameTabs({
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
elementName: oldName,
|
||||
elementNewName: this.localScheduler.name,
|
||||
elementType: 'scheduler'
|
||||
});
|
||||
|
||||
this.changeBreadcrumbs({ schema: this.schema, scheduler: this.localScheduler.name });
|
||||
}
|
||||
|
||||
this.getSchedulerData();
|
||||
else
|
||||
this.getSchedulerData();
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
@@ -10,8 +10,8 @@
|
||||
title="CTRL+S"
|
||||
@click="saveChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
<span>{{ $t('word.save') }}</span>
|
||||
<i class="mdi mdi-24px mdi-content-save ml-1" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="!isChanged"
|
||||
@@ -19,10 +19,15 @@
|
||||
:title="$t('message.clearChanges')"
|
||||
@click="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
<div class="d-flex" :title="$t('word.schema')">
|
||||
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
@@ -139,11 +144,12 @@ export default {
|
||||
},
|
||||
props: {
|
||||
connection: Object,
|
||||
trigger: String
|
||||
trigger: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'prop',
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
originalTrigger: null,
|
||||
@@ -162,15 +168,12 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
customizations () {
|
||||
return this.workspace.customizations;
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.trigger;
|
||||
},
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalTrigger) !== JSON.stringify(this.localTrigger);
|
||||
},
|
||||
@@ -186,6 +189,13 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async schema () {
|
||||
if (this.isSelected) {
|
||||
await this.getTriggerData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localTrigger.sql);
|
||||
this.lastTrigger = this.trigger;
|
||||
}
|
||||
},
|
||||
async trigger () {
|
||||
if (this.isSelected) {
|
||||
await this.getTriggerData();
|
||||
@@ -194,26 +204,32 @@ export default {
|
||||
}
|
||||
},
|
||||
async isSelected (val) {
|
||||
if (val && this.lastTrigger !== this.trigger) {
|
||||
await this.getTriggerData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localTrigger.sql);
|
||||
this.lastTrigger = this.trigger;
|
||||
if (val) {
|
||||
this.changeBreadcrumbs({ schema: this.schema, trigger: this.trigger });
|
||||
|
||||
setTimeout(() => {
|
||||
this.resizeQueryEditor();
|
||||
}, 200);
|
||||
|
||||
if (this.lastTrigger !== this.trigger)
|
||||
this.getTriggerData();
|
||||
}
|
||||
},
|
||||
isChanged (val) {
|
||||
if (this.isSelected && this.lastTrigger === this.trigger && this.trigger !== null)
|
||||
this.setUnsavedChanges(val);
|
||||
this.setUnsavedChanges({ uid: this.connection.uid, tUid: this.tabUid, isChanged: val });
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.getTriggerData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localTrigger.sql);
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
@@ -221,8 +237,10 @@ export default {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getTriggerData () {
|
||||
if (!this.trigger) return;
|
||||
@@ -233,11 +251,12 @@ export default {
|
||||
|
||||
this.localTrigger = { sql: '' };
|
||||
this.isLoading = true;
|
||||
this.lastTrigger = this.trigger;
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
trigger: this.workspace.breadcrumbs.trigger
|
||||
trigger: this.trigger
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -278,9 +297,9 @@ export default {
|
||||
this.isSaving = true;
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
trigger: {
|
||||
...this.localTrigger,
|
||||
schema: this.schema,
|
||||
oldName: this.originalTrigger.name
|
||||
}
|
||||
};
|
||||
@@ -289,17 +308,24 @@ export default {
|
||||
const { status, response } = await Triggers.alterTrigger(params);
|
||||
|
||||
if (status === 'success') {
|
||||
const oldName = this.originalTrigger.name;
|
||||
|
||||
await this.refreshStructure(this.connection.uid);
|
||||
|
||||
if (oldName !== this.localTrigger.name) {
|
||||
this.setUnsavedChanges(false);
|
||||
if (this.originalTrigger.name !== this.localTrigger.name) {
|
||||
const triggerName = this.customizations.triggerTableInName ? `${this.localTrigger.table}.${this.localTrigger.name}` : this.localTrigger.name;
|
||||
const triggerOldName = this.customizations.triggerTableInName ? `${this.originalTrigger.table}.${this.originalTrigger.name}` : this.originalTrigger.name;
|
||||
|
||||
this.renameTabs({
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
elementName: triggerOldName,
|
||||
elementNewName: triggerName,
|
||||
elementType: 'trigger'
|
||||
});
|
||||
|
||||
this.changeBreadcrumbs({ schema: this.schema, trigger: triggerName });
|
||||
}
|
||||
|
||||
this.getTriggerData();
|
||||
else
|
||||
this.getTriggerData();
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
@@ -10,8 +10,8 @@
|
||||
title="CTRL+S"
|
||||
@click="saveChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
<span>{{ $t('word.save') }}</span>
|
||||
<i class="mdi mdi-24px mdi-content-save ml-1" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="!isChanged"
|
||||
@@ -19,15 +19,15 @@
|
||||
:title="$t('message.clearChanges')"
|
||||
@click="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
|
||||
<div class="divider-vert py-3" />
|
||||
|
||||
<button class="btn btn-dark btn-sm" @click="showOptionsModal">
|
||||
<i class="mdi mdi-24px mdi-cogs mr-1" />
|
||||
<span>{{ $t('word.options') }}</span>
|
||||
<i class="mdi mdi-24px mdi-cogs ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,11 +80,12 @@ export default {
|
||||
},
|
||||
props: {
|
||||
connection: Object,
|
||||
function: String
|
||||
function: String,
|
||||
isSelected: Boolean,
|
||||
schema: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'prop',
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
isOptionsModal: false,
|
||||
@@ -105,11 +106,8 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.function;
|
||||
},
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalFunction) !== JSON.stringify(this.localFunction);
|
||||
@@ -128,6 +126,13 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async schema () {
|
||||
if (this.isSelected) {
|
||||
await this.getFunctionData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localFunction.sql);
|
||||
this.lastFunction = this.function;
|
||||
}
|
||||
},
|
||||
async function () {
|
||||
if (this.isSelected) {
|
||||
await this.getFunctionData();
|
||||
@@ -136,26 +141,32 @@ export default {
|
||||
}
|
||||
},
|
||||
async isSelected (val) {
|
||||
if (val && this.lastFunction !== this.function) {
|
||||
await this.getFunctionData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localFunction.sql);
|
||||
this.lastFunction = this.function;
|
||||
if (val) {
|
||||
this.changeBreadcrumbs({ schema: this.schema, triggerFunction: this.function });
|
||||
|
||||
setTimeout(() => {
|
||||
this.resizeQueryEditor();
|
||||
}, 200);
|
||||
|
||||
if (this.lastFunction !== this.function)
|
||||
await this.getFunctionData();
|
||||
}
|
||||
},
|
||||
isChanged (val) {
|
||||
if (this.isSelected && this.lastFunction === this.function && this.function !== null)
|
||||
this.setUnsavedChanges(val);
|
||||
this.setUnsavedChanges({ uid: this.connection.uid, tUid: this.tabUid, isChanged: val });
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.getFunctionData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localFunction.sql);
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
@@ -163,20 +174,22 @@ export default {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
renameTabs: 'workspaces/renameTabs',
|
||||
newTab: 'workspaces/newTab',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
newTab: 'workspaces/newTab'
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges'
|
||||
}),
|
||||
async getFunctionData () {
|
||||
if (!this.function) return;
|
||||
|
||||
this.isLoading = true;
|
||||
this.localFunction = { sql: '' };
|
||||
this.lastFunction = this.function;
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
func: this.workspace.breadcrumbs.triggerFunction
|
||||
func: this.function
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -207,9 +220,9 @@ export default {
|
||||
this.isSaving = true;
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
func: {
|
||||
...this.localFunction,
|
||||
schema: this.schema,
|
||||
oldName: this.originalFunction.name
|
||||
}
|
||||
};
|
||||
@@ -223,11 +236,18 @@ export default {
|
||||
await this.refreshStructure(this.connection.uid);
|
||||
|
||||
if (oldName !== this.localFunction.name) {
|
||||
this.setUnsavedChanges(false);
|
||||
this.changeBreadcrumbs({ schema: this.schema, function: this.localFunction.name });
|
||||
}
|
||||
this.renameTabs({
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
elementName: oldName,
|
||||
elementNewName: this.localFunction.name,
|
||||
elementType: 'triggerFunction'
|
||||
});
|
||||
|
||||
this.getFunctionData();
|
||||
this.changeBreadcrumbs({ schema: this.schema, triggerFunction: this.localFunction.name });
|
||||
}
|
||||
else
|
||||
this.getFunctionData();
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
@@ -281,7 +301,7 @@ export default {
|
||||
sql = `SELECT \`${this.originalFunction.name}\` (${params.join(',')})`;
|
||||
}
|
||||
|
||||
this.newTab({ uid: this.connection.uid, content: sql, autorun: true });
|
||||
this.newTab({ uid: this.connection.uid, content: sql, type: 'query', autorun: true });
|
||||
},
|
||||
showOptionsModal () {
|
||||
this.isOptionsModal = true;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
@@ -10,8 +10,8 @@
|
||||
title="CTRL+S"
|
||||
@click="saveChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-content-save mr-1" />
|
||||
<span>{{ $t('word.save') }}</span>
|
||||
<i class="mdi mdi-24px mdi-content-save ml-1" />
|
||||
</button>
|
||||
<button
|
||||
:disabled="!isChanged"
|
||||
@@ -19,10 +19,15 @@
|
||||
:title="$t('message.clearChanges')"
|
||||
@click="clearChanges"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep mr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="workspace-query-info">
|
||||
<div class="d-flex" :title="$t('word.schema')">
|
||||
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
@@ -161,7 +166,7 @@
|
||||
<BaseLoader v-if="isLoading" />
|
||||
<label class="form-label ml-2">{{ $t('message.selectStatement') }}</label>
|
||||
<QueryEditor
|
||||
v-if="isSelected"
|
||||
v-show="isSelected"
|
||||
ref="queryEditor"
|
||||
:value.sync="localView.sql"
|
||||
:workspace="workspace"
|
||||
@@ -186,11 +191,12 @@ export default {
|
||||
},
|
||||
props: {
|
||||
connection: Object,
|
||||
isSelected: Boolean,
|
||||
schema: String,
|
||||
view: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'prop',
|
||||
isLoading: false,
|
||||
isSaving: false,
|
||||
originalView: null,
|
||||
@@ -208,11 +214,8 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 'prop' && this.selectedWorkspace === this.workspace.uid && this.view;
|
||||
},
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
tabUid () {
|
||||
return this.$vnode.key;
|
||||
},
|
||||
isChanged () {
|
||||
return JSON.stringify(this.originalView) !== JSON.stringify(this.localView);
|
||||
@@ -222,6 +225,13 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
async schema () {
|
||||
if (this.isSelected) {
|
||||
await this.getViewData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localView.sql);
|
||||
this.lastView = this.view;
|
||||
}
|
||||
},
|
||||
async view () {
|
||||
if (this.isSelected) {
|
||||
await this.getViewData();
|
||||
@@ -229,27 +239,33 @@ export default {
|
||||
this.lastView = this.view;
|
||||
}
|
||||
},
|
||||
async isSelected (val) {
|
||||
if (val && this.lastView !== this.view) {
|
||||
await this.getViewData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localView.sql);
|
||||
this.lastView = this.view;
|
||||
isSelected (val) {
|
||||
if (val) {
|
||||
this.changeBreadcrumbs({ schema: this.schema, view: this.view });
|
||||
|
||||
setTimeout(() => {
|
||||
this.resizeQueryEditor();
|
||||
}, 200);
|
||||
|
||||
if (this.lastView !== this.view)
|
||||
this.getViewData();
|
||||
}
|
||||
},
|
||||
isChanged (val) {
|
||||
if (this.isSelected && this.lastView === this.view && this.view !== null)
|
||||
this.setUnsavedChanges(val);
|
||||
this.setUnsavedChanges({ uid: this.connection.uid, tUid: this.tabUid, isChanged: val });
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.getViewData();
|
||||
this.$refs.queryEditor.editor.session.setValue(this.localView.sql);
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
mounted () {
|
||||
window.addEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('resize', this.resizeQueryEditor);
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.removeEventListener('keydown', this.onKey);
|
||||
},
|
||||
@@ -258,17 +274,19 @@ export default {
|
||||
addNotification: 'notifications/addNotification',
|
||||
refreshStructure: 'workspaces/refreshStructure',
|
||||
setUnsavedChanges: 'workspaces/setUnsavedChanges',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
renameTabs: 'workspaces/renameTabs'
|
||||
}),
|
||||
async getViewData () {
|
||||
if (!this.view) return;
|
||||
this.isLoading = true;
|
||||
this.localView = { sql: '' };
|
||||
this.lastView = this.view;
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
view: this.workspace.breadcrumbs.view
|
||||
view: this.view
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -293,9 +311,9 @@ export default {
|
||||
this.isSaving = true;
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
view: {
|
||||
...this.localView,
|
||||
schema: this.schema,
|
||||
oldName: this.originalView.name
|
||||
}
|
||||
};
|
||||
@@ -309,11 +327,18 @@ export default {
|
||||
await this.refreshStructure(this.connection.uid);
|
||||
|
||||
if (oldName !== this.localView.name) {
|
||||
this.setUnsavedChanges(false);
|
||||
this.renameTabs({
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
elementName: oldName,
|
||||
elementNewName: this.localView.name,
|
||||
elementType: 'view'
|
||||
});
|
||||
|
||||
this.changeBreadcrumbs({ schema: this.schema, view: this.localView.name });
|
||||
}
|
||||
|
||||
this.getViewData();
|
||||
else
|
||||
this.getViewData();
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
|
@@ -100,7 +100,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<draggable
|
||||
<Draggable
|
||||
ref="resultTable"
|
||||
:list="fields"
|
||||
class="tbody"
|
||||
@@ -117,14 +117,14 @@
|
||||
@contextmenu="contextMenu"
|
||||
@rename-field="$emit('rename-field', $event)"
|
||||
/>
|
||||
</draggable>
|
||||
</Draggable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import draggable from 'vuedraggable';
|
||||
import Draggable from 'vuedraggable';
|
||||
import TableRow from '@/components/WorkspacePropsTableRow';
|
||||
import TableContext from '@/components/WorkspacePropsTableContext';
|
||||
|
||||
@@ -133,7 +133,7 @@ export default {
|
||||
components: {
|
||||
TableRow,
|
||||
TableContext,
|
||||
draggable
|
||||
Draggable
|
||||
},
|
||||
props: {
|
||||
fields: Array,
|
||||
|
@@ -450,7 +450,7 @@ export default {
|
||||
});
|
||||
|
||||
this.defaultValue.onUpdate = this.localRow.onUpdate;
|
||||
this.defaultValue.type = this.localRow.defaultType;
|
||||
this.defaultValue.type = this.localRow.defaultType || 'noval';
|
||||
if (this.defaultValue.type === 'custom') {
|
||||
this.defaultValue.custom = this.localRow.default
|
||||
? this.localRow.default.includes('\'')
|
||||
@@ -458,8 +458,13 @@ export default {
|
||||
: this.localRow.default
|
||||
: '';
|
||||
}
|
||||
if (this.defaultValue.type === 'expression')
|
||||
this.defaultValue.expression = this.localRow.default;
|
||||
else if (this.defaultValue.type === 'expression') {
|
||||
console.log(this.localRow.default);
|
||||
if (this.localRow.default.toUpperCase().includes('ON UPDATE'))
|
||||
this.defaultValue.expression = this.localRow.default.replace(/ on update.*$/i, '');
|
||||
else
|
||||
this.defaultValue.expression = this.localRow.default;
|
||||
}
|
||||
},
|
||||
editON (event, content, field) {
|
||||
if (field === 'length') {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
v-show="isSelected"
|
||||
class="workspace-query-tab column col-12 columns col-gapless no-outline"
|
||||
class="workspace-query-tab column col-12 columns col-gapless no-outline p-0"
|
||||
tabindex="0"
|
||||
@keydown.116="runQuery(query)"
|
||||
@keydown.ctrl.87="clear"
|
||||
@@ -14,7 +14,7 @@
|
||||
:auto-focus="true"
|
||||
:value.sync="query"
|
||||
:workspace="workspace"
|
||||
:schema="schema"
|
||||
:schema="breadcrumbsSchema"
|
||||
:is-selected="isSelected"
|
||||
:height="editorHeight"
|
||||
/>
|
||||
@@ -28,8 +28,8 @@
|
||||
title="F5"
|
||||
@click="runQuery(query)"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-play pr-1" />
|
||||
<span>{{ $t('word.run') }}</span>
|
||||
<i class="mdi mdi-24px mdi-play" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-dark btn-sm"
|
||||
@@ -37,8 +37,8 @@
|
||||
title="CTRL+F8"
|
||||
@click="beautify()"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-brush pr-1" />
|
||||
<span>{{ $t('word.format') }}</span>
|
||||
<i class="mdi mdi-24px mdi-brush pl-1" />
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-link btn-sm"
|
||||
@@ -46,8 +46,8 @@
|
||||
title="CTRL+W"
|
||||
@click="clear()"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep pr-1" />
|
||||
<span>{{ $t('word.clear') }}</span>
|
||||
<i class="mdi mdi-24px mdi-delete-sweep pl-1" />
|
||||
</button>
|
||||
|
||||
<div class="divider-vert py-3" />
|
||||
@@ -58,8 +58,8 @@
|
||||
class="btn btn-dark btn-sm dropdown-toggle mr-0 pr-0"
|
||||
tabindex="0"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-file-export mr-1" />
|
||||
<span>{{ $t('word.export') }}</span>
|
||||
<i class="mdi mdi-24px mdi-file-export ml-1" />
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
</button>
|
||||
<ul class="menu text-left">
|
||||
@@ -86,12 +86,16 @@
|
||||
<div v-if="affectedCount">
|
||||
{{ $t('message.affectedRows') }}: <b>{{ affectedCount }}</b>
|
||||
</div>
|
||||
<div
|
||||
v-if="workspace.breadcrumbs.schema"
|
||||
class="d-flex"
|
||||
:title="$t('word.schema')"
|
||||
>
|
||||
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ workspace.breadcrumbs.schema }}</b>
|
||||
<div class="input-group" :title="$t('word.schema')">
|
||||
<i class="input-group-addon addon-sm mdi mdi-24px mdi-database" />
|
||||
<select v-model="selectedSchema" class="form-select select-sm text-bold">
|
||||
<option :value="null">
|
||||
{{ $t('message.noSchema') }}
|
||||
</option>
|
||||
<option v-for="schemaName in databaseSchemas" :key="schemaName">
|
||||
{{ schemaName }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -142,6 +146,7 @@ export default {
|
||||
lastQuery: '',
|
||||
isQuering: false,
|
||||
results: [],
|
||||
selectedSchema: null,
|
||||
resultsCount: 0,
|
||||
durationsCount: 0,
|
||||
affectedCount: 0,
|
||||
@@ -156,12 +161,32 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
breadcrumbsSchema () {
|
||||
return this.workspace.breadcrumbs.schema || null;
|
||||
},
|
||||
databaseSchemas () {
|
||||
return this.workspace.structure.reduce((acc, curr) => {
|
||||
acc.push(curr.name);
|
||||
return acc;
|
||||
}, []);
|
||||
},
|
||||
isWorkspaceSelected () {
|
||||
return this.workspace.uid === this.selectedWorkspace;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isSelected (val) {
|
||||
if (val)
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, query: `Query #${this.tab.index}` });
|
||||
},
|
||||
selectedSchema () {
|
||||
this.changeBreadcrumbs({ schema: this.selectedSchema, query: `Query #${this.tab.index}` });
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.query = this.tab.content;
|
||||
this.selectedSchema = this.tab.schema || this.breadcrumbsSchema;
|
||||
// this.changeBreadcrumbs({ schema: this.selectedSchema, query: `Query #${this.tab.index}` });
|
||||
|
||||
window.addEventListener('keydown', this.onKey);
|
||||
},
|
||||
@@ -183,7 +208,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs',
|
||||
updateTabContent: 'workspaces/updateTabContent'
|
||||
}),
|
||||
async runQuery (query) {
|
||||
if (!query || this.isQuering) return;
|
||||
@@ -194,7 +221,7 @@ export default {
|
||||
try { // Query Data
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
schema: this.selectedSchema,
|
||||
query
|
||||
};
|
||||
|
||||
@@ -205,6 +232,8 @@ export default {
|
||||
this.resultsCount += this.results.reduce((acc, curr) => acc + (curr.rows ? curr.rows.length : 0), 0);
|
||||
this.durationsCount += this.results.reduce((acc, curr) => acc + curr.duration, 0);
|
||||
this.affectedCount += this.results.reduce((acc, curr) => acc + (curr.report ? curr.report.affectedRows : 0), 0);
|
||||
|
||||
this.updateTabContent({ uid: this.connection.uid, tab: this.tab.uid, type: 'query', schema: this.selectedSchema, content: query });
|
||||
}
|
||||
else
|
||||
this.addNotification({ status: 'error', message: response });
|
||||
@@ -303,8 +332,10 @@ export default {
|
||||
align-items: center;
|
||||
height: 42px;
|
||||
|
||||
.workspace-query-buttons {
|
||||
.workspace-query-buttons,
|
||||
.workspace-query-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
@@ -314,7 +345,7 @@ export default {
|
||||
}
|
||||
|
||||
.workspace-query-info {
|
||||
display: flex;
|
||||
overflow: visible;
|
||||
|
||||
> div + div {
|
||||
padding-left: 0.6rem;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
v-if="isContext"
|
||||
:context-event="contextEvent"
|
||||
:selected-rows="selectedRows"
|
||||
:selected-cell="selectedCell"
|
||||
@show-delete-modal="showDeleteConfirmModal"
|
||||
@set-null="setNull"
|
||||
@copy-cell="copyCell"
|
||||
@@ -71,6 +72,7 @@
|
||||
:row="row"
|
||||
:fields="fieldsObj"
|
||||
:key-usage="keyUsage"
|
||||
:element-type="elementType"
|
||||
:class="{'selected': selectedRows.includes(row._id)}"
|
||||
@select-row="selectRow($event, row._id)"
|
||||
@update-field="updateField($event, row)"
|
||||
@@ -123,7 +125,8 @@ export default {
|
||||
results: Array,
|
||||
connUid: String,
|
||||
mode: String,
|
||||
isSelected: Boolean
|
||||
isSelected: Boolean,
|
||||
elementType: { type: String, default: 'table' }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -226,6 +229,9 @@ export default {
|
||||
},
|
||||
resultsetIndex () {
|
||||
this.setLocalResults();
|
||||
},
|
||||
isSelected (val) {
|
||||
if (val) this.refreshScroller();
|
||||
}
|
||||
},
|
||||
updated () {
|
||||
|
@@ -28,7 +28,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedRows.length === 1"
|
||||
v-if="selectedRows.length === 1 && selectedCell.isEditable"
|
||||
class="context-element"
|
||||
@click="setNull"
|
||||
>
|
||||
@@ -36,7 +36,11 @@
|
||||
<i class="mdi mdi-18px mdi-null text-light pr-1" /> {{ $t('message.setNull') }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="context-element" @click="showConfirmModal">
|
||||
<div
|
||||
v-if="selectedCell.isEditable"
|
||||
class="context-element"
|
||||
@click="showConfirmModal"
|
||||
>
|
||||
<span class="d-flex">
|
||||
<i class="mdi mdi-18px mdi-delete text-light pr-1" /> {{ $tc('message.deleteRows', selectedRows.length) }}
|
||||
</span>
|
||||
@@ -54,7 +58,8 @@ export default {
|
||||
},
|
||||
props: {
|
||||
contextEvent: MouseEvent,
|
||||
selectedRows: Array
|
||||
selectedRows: Array,
|
||||
selectedCell: Object
|
||||
},
|
||||
computed: {
|
||||
},
|
||||
|
@@ -260,7 +260,8 @@ export default {
|
||||
props: {
|
||||
row: Object,
|
||||
fields: Object,
|
||||
keyUsage: Array
|
||||
keyUsage: Array,
|
||||
elementType: { type: String, default: 'table' }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -334,6 +335,8 @@ export default {
|
||||
return this.keyUsage.map(key => key.field);
|
||||
},
|
||||
isEditable () {
|
||||
if (this.elementType === 'view') return false;
|
||||
|
||||
if (this.fields) {
|
||||
const nElements = Object.keys(this.fields).reduce((acc, curr) => {
|
||||
acc.add(this.fields[curr].table);
|
||||
@@ -503,10 +506,9 @@ export default {
|
||||
return this.keyUsage.find(key => key.field === keyName);
|
||||
},
|
||||
openContext (event, payload) {
|
||||
if (this.isEditable) {
|
||||
payload.field = this.fields[payload.field].name;// Ensures field name only
|
||||
this.$emit('contextmenu', event, payload);
|
||||
}
|
||||
payload.field = this.fields[payload.field].name;// Ensures field name only
|
||||
payload.isEditable = this.isEditable;
|
||||
this.$emit('contextmenu', event, payload);
|
||||
},
|
||||
onKey (e) {
|
||||
e.stopPropagation();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless">
|
||||
<div v-show="isSelected" class="workspace-query-tab column col-12 columns col-gapless no-outline p-0">
|
||||
<div class="workspace-query-runner column col-12">
|
||||
<div class="workspace-query-runner-footer">
|
||||
<div class="workspace-query-buttons">
|
||||
@@ -11,9 +11,9 @@
|
||||
title="F5"
|
||||
@click="reloadTable"
|
||||
>
|
||||
<i v-if="!+autorefreshTimer" class="mdi mdi-24px mdi-refresh mr-1" />
|
||||
<i v-else class="mdi mdi-24px mdi-history mdi-flip-h mr-1" />
|
||||
<span>{{ $t('word.refresh') }}</span>
|
||||
<i v-if="!+autorefreshTimer" class="mdi mdi-24px mdi-refresh ml-1" />
|
||||
<i v-else class="mdi mdi-24px mdi-history mdi-flip-h ml-1" />
|
||||
</button>
|
||||
<div class="btn btn-dark btn-sm dropdown-toggle pl-0 pr-0" tabindex="0">
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
@@ -77,8 +77,8 @@
|
||||
:disabled="isQuering"
|
||||
@click="showFakerModal"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-playlist-plus mr-1" />
|
||||
<span>{{ $t('message.tableFiller') }}</span>
|
||||
<i class="mdi mdi-24px mdi-playlist-plus ml-1" />
|
||||
</button>
|
||||
|
||||
<div class="dropdown table-dropdown pr-2">
|
||||
@@ -87,8 +87,8 @@
|
||||
class="btn btn-dark btn-sm dropdown-toggle mr-0 pr-0"
|
||||
tabindex="0"
|
||||
>
|
||||
<i class="mdi mdi-24px mdi-file-export mr-1" />
|
||||
<span>{{ $t('word.export') }}</span>
|
||||
<i class="mdi mdi-24px mdi-file-export ml-1" />
|
||||
<i class="mdi mdi-24px mdi-menu-down" />
|
||||
</button>
|
||||
<ul class="menu text-left">
|
||||
@@ -115,8 +115,8 @@
|
||||
<div v-if="hasApproximately || (page > 1 && tableInfo.rows)">
|
||||
{{ $t('word.total') }}: <b>{{ tableInfo.rows | localeString }}</b> <small>({{ $t('word.approximately') }})</small>
|
||||
</div>
|
||||
<div v-if="workspace.breadcrumbs.database">
|
||||
{{ $t('word.schema') }}: <b>{{ workspace.breadcrumbs.database }}</b>
|
||||
<div class="d-flex" :title="$t('word.schema')">
|
||||
<i class="mdi mdi-18px mdi-database mr-1" /><b>{{ schema }}</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -131,6 +131,7 @@
|
||||
:conn-uid="connection.uid"
|
||||
:is-selected="isSelected"
|
||||
mode="table"
|
||||
:element-type="elementType"
|
||||
@update-field="updateField"
|
||||
@delete-selected="deleteSelected"
|
||||
@hard-sort="hardSort"
|
||||
@@ -181,11 +182,14 @@ export default {
|
||||
mixins: [tableTabs],
|
||||
props: {
|
||||
connection: Object,
|
||||
table: String
|
||||
isSelected: Boolean,
|
||||
table: String,
|
||||
schema: String,
|
||||
elementType: String
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabUid: 'data',
|
||||
tabUid: 'data', // ???
|
||||
isQuering: false,
|
||||
isPageMenu: false,
|
||||
results: [],
|
||||
@@ -208,9 +212,6 @@ export default {
|
||||
workspace () {
|
||||
return this.getWorkspace(this.connection.uid);
|
||||
},
|
||||
isSelected () {
|
||||
return this.workspace.selected_tab === 'data' && this.workspace.uid === this.selectedWorkspace;
|
||||
},
|
||||
isTable () {
|
||||
return !!this.workspace.breadcrumbs.table;
|
||||
},
|
||||
@@ -237,6 +238,15 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
schema () {
|
||||
if (this.isSelected) {
|
||||
this.page = 1;
|
||||
this.sortParams = {};
|
||||
this.getTableData();
|
||||
this.lastTable = this.table;
|
||||
this.$refs.queryTable.resetSort();
|
||||
}
|
||||
},
|
||||
table () {
|
||||
if (this.isSelected) {
|
||||
this.page = 1;
|
||||
@@ -253,9 +263,11 @@ export default {
|
||||
}
|
||||
},
|
||||
isSelected (val) {
|
||||
if (val && this.lastTable !== this.table) {
|
||||
this.getTableData();
|
||||
this.lastTable = this.table;
|
||||
if (val) {
|
||||
this.changeBreadcrumbs({ schema: this.schema, [this.elementType]: this.table });
|
||||
|
||||
if (this.lastTable !== this.table)
|
||||
this.getTableData();
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -269,9 +281,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
addNotification: 'notifications/addNotification'
|
||||
addNotification: 'notifications/addNotification',
|
||||
changeBreadcrumbs: 'workspaces/changeBreadcrumbs'
|
||||
}),
|
||||
async getTableData (sortParams) {
|
||||
async getTableData () {
|
||||
if (!this.table) return;
|
||||
this.isQuering = true;
|
||||
|
||||
@@ -279,13 +292,15 @@ export default {
|
||||
if (this.lastTable !== this.table)
|
||||
this.results = [];
|
||||
|
||||
this.lastTable = this.table;
|
||||
|
||||
const params = {
|
||||
uid: this.connection.uid,
|
||||
schema: this.schema,
|
||||
table: this.workspace.breadcrumbs.table || this.workspace.breadcrumbs.view,
|
||||
table: this.table,
|
||||
limit: this.limit,
|
||||
page: this.page,
|
||||
sortParams
|
||||
sortParams: this.sortParams
|
||||
};
|
||||
|
||||
try { // Table data
|
||||
@@ -306,14 +321,14 @@ export default {
|
||||
return this.table;
|
||||
},
|
||||
reloadTable () {
|
||||
this.getTableData(this.sortParams);
|
||||
this.getTableData();
|
||||
},
|
||||
hardSort (sortParams) {
|
||||
this.sortParams = sortParams;
|
||||
this.getTableData(sortParams);
|
||||
this.getTableData();
|
||||
},
|
||||
openPageMenu () {
|
||||
if (this.isQuering) return;
|
||||
if (this.isQuering || (this.results.length && this.results[0].rows.length < this.limit && this.page === 1)) return;
|
||||
|
||||
this.isPageMenu = true;
|
||||
if (this.isPageMenu)
|
||||
|
@@ -104,7 +104,8 @@ module.exports = {
|
||||
database: 'Datenbank',
|
||||
scratchpad: 'Scratchpad',
|
||||
array: 'Array',
|
||||
format: 'Formatierung'
|
||||
format: 'Formatierung',
|
||||
sshTunnel: 'SSH Tunnel'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Willkommen im Antares SQL Client!',
|
||||
@@ -210,7 +211,8 @@ module.exports = {
|
||||
deleteSchema: 'Schema löschen',
|
||||
markdownSupported: 'Unterstützt Markdown',
|
||||
plantATree: 'Pflanze einen Baum',
|
||||
dataTabPageSize: 'Einträge pro Tab / Seite'
|
||||
dataTabPageSize: 'Einträge pro Tab / Seite',
|
||||
enableSsh: 'Aktiviere SSH'
|
||||
},
|
||||
faker: {
|
||||
address: 'Adresse',
|
||||
|
@@ -106,13 +106,16 @@ module.exports = {
|
||||
array: 'Array',
|
||||
changelog: 'Changelog',
|
||||
format: 'Format',
|
||||
sshTunnel: 'SSH tunnel',
|
||||
structure: 'Structure',
|
||||
small: 'Small',
|
||||
medium: 'Medium',
|
||||
large: 'Large',
|
||||
row: 'Row | Rows',
|
||||
cell: 'Cell | Cells',
|
||||
triggerFunction: 'Trigger function | Trigger functions'
|
||||
triggerFunction: 'Trigger function | Trigger functions',
|
||||
all: 'All',
|
||||
duplicate: 'Duplicate'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Welcome to Antares SQL Client!',
|
||||
@@ -166,7 +169,7 @@ module.exports = {
|
||||
deleteTable: 'Delete table',
|
||||
emptyCorfirm: 'Do you confirm to empty',
|
||||
unsavedChanges: 'Unsaved changes',
|
||||
discardUnsavedChanges: 'You have some unsaved changes. By leaving this tab these changes will be discarded.',
|
||||
discardUnsavedChanges: 'You have some unsaved changes. Closing this tab these changes will be discarded.',
|
||||
thereAreNoIndexes: 'There are no indexes',
|
||||
thereAreNoForeign: 'There are no foreign keys',
|
||||
createNewForeign: 'Create new foreign key',
|
||||
@@ -219,8 +222,12 @@ module.exports = {
|
||||
markdownSupported: 'Markdown supported',
|
||||
plantATree: 'Plant a Tree',
|
||||
dataTabPageSize: 'DATA tab page size',
|
||||
enableSsh: 'Enable SSH',
|
||||
pageNumber: 'Page number',
|
||||
duplicateTable: 'Duplicate table'
|
||||
duplicateTable: 'Duplicate table',
|
||||
noOpenTabs: 'There are no open tabs, navigate on the left bar or:',
|
||||
noSchema: 'No schema',
|
||||
restorePreviourSession: 'Restore previous session'
|
||||
},
|
||||
faker: {
|
||||
address: 'Address',
|
||||
|
@@ -93,7 +93,8 @@ module.exports = {
|
||||
ciphers: 'Chiffrement',
|
||||
upload: 'Charger',
|
||||
browse: 'Parcourir',
|
||||
faker: 'Faker'
|
||||
faker: 'Faker',
|
||||
sshTunnel: 'SSH tunnel'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Bienvenu sur le client SQL Antares!',
|
||||
@@ -183,7 +184,8 @@ module.exports = {
|
||||
preserveOnCompletion: 'Préserver à l\'achèvement',
|
||||
enableSsl: 'Activer le SSL',
|
||||
manualValue: 'Valeur manuelle',
|
||||
tableFiller: 'Remplisseur de table'
|
||||
tableFiller: 'Remplisseur de table',
|
||||
enableSsh: 'Activer le SSH'
|
||||
},
|
||||
faker: {
|
||||
address: 'Adresse',
|
||||
|
@@ -105,7 +105,8 @@ module.exports = {
|
||||
scratchpad: 'Blocco appunti',
|
||||
array: 'Array',
|
||||
changelog: 'Changelog',
|
||||
format: 'Formatta'
|
||||
format: 'Formatta',
|
||||
sshTunnel: 'SSH tunnel'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Benvenuto in Antares SQL Client!',
|
||||
@@ -210,7 +211,8 @@ module.exports = {
|
||||
editSchema: 'Modifica schema',
|
||||
deleteSchema: 'Elimina schema',
|
||||
markdownSupported: 'Markdown supportato',
|
||||
plantATree: 'Pianta un albero'
|
||||
plantATree: 'Pianta un albero',
|
||||
enableSsh: 'Abilita SSH'
|
||||
},
|
||||
faker: {
|
||||
address: 'Indirizzo',
|
||||
|
@@ -105,7 +105,8 @@ module.exports = {
|
||||
scratchpad: 'Rascunho',
|
||||
array: 'Array',
|
||||
changelog: 'Logs de alteração',
|
||||
format: 'Formato'
|
||||
format: 'Formato',
|
||||
sshTunnel: 'SSH túnel'
|
||||
},
|
||||
message: {
|
||||
appWelcome: 'Bem vindo ao Antares SQL Client!',
|
||||
@@ -210,7 +211,8 @@ module.exports = {
|
||||
editSchema: 'Editar schema',
|
||||
deleteSchema: 'Apagar schema',
|
||||
markdownSupported: 'Markdown suportado',
|
||||
plantATree: 'Plante uma árvore'
|
||||
plantATree: 'Plante uma árvore',
|
||||
enableSsh: 'Habilitar SSH'
|
||||
},
|
||||
faker: {
|
||||
address: 'Endereço',
|
||||
|
301
src/renderer/images/logo-dark.svg
Normal file
301
src/renderer/images/logo-dark.svg
Normal file
@@ -0,0 +1,301 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 1024 1024"
|
||||
style="enable-background:new 0 0 1024 1024;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="Antares-shape-2.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs80" /><sodipodi:namedview
|
||||
id="namedview78"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.66015625"
|
||||
inkscape:cx="210.55621"
|
||||
inkscape:cy="511.2426"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g75" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:url(#XMLID_15_);}
|
||||
.st2{opacity:0.5;fill:#FFBC00;}
|
||||
.st3{fill:#FFBC00;}
|
||||
.st4{fill:url(#XMLID_16_);}
|
||||
.st5{fill:url(#XMLID_17_);}
|
||||
.st6{fill:url(#XMLID_18_);}
|
||||
.st7{fill:url(#XMLID_19_);}
|
||||
.st8{fill:url(#XMLID_20_);}
|
||||
.st9{fill:url(#XMLID_21_);}
|
||||
.st10{opacity:0.46;}
|
||||
.st11{fill:url(#XMLID_23_);}
|
||||
.st12{fill:url(#XMLID_24_);}
|
||||
.st13{fill:url(#XMLID_25_);}
|
||||
.st14{fill:url(#XMLID_27_);}
|
||||
.st15{fill:url(#XMLID_28_);}
|
||||
.st16{fill:url(#XMLID_29_);}
|
||||
.st17{fill:url(#XMLID_30_);}
|
||||
.st18{opacity:0.75;}
|
||||
.st19{opacity:0.44;clip-path:url(#XMLID_31_);}
|
||||
.st20{fill:url(#XMLID_32_);}
|
||||
.st21{fill:url(#XMLID_33_);}
|
||||
.st22{fill:url(#XMLID_34_);}
|
||||
.st23{fill:url(#XMLID_35_);}
|
||||
.st24{fill:url(#XMLID_37_);}
|
||||
.st25{fill:url(#XMLID_38_);}
|
||||
.st26{opacity:0.43;fill:#FFBC00;}
|
||||
.st27{opacity:0.58;fill:#FFBC00;}
|
||||
.st28{fill:#FFBE06;}
|
||||
.st29{fill:none;}
|
||||
.st30{fill:url(#XMLID_42_);}
|
||||
.st31{fill:url(#XMLID_43_);}
|
||||
.st32{fill:url(#XMLID_44_);}
|
||||
.st33{fill:url(#XMLID_45_);}
|
||||
.st34{fill:url(#XMLID_46_);}
|
||||
.st35{fill:url(#SVGID_4_);}
|
||||
.st36{fill:url(#SVGID_5_);}
|
||||
.st37{fill:url(#SVGID_6_);}
|
||||
.st38{fill:url(#SVGID_7_);}
|
||||
.st39{fill:url(#SVGID_8_);}
|
||||
.st40{fill:url(#SVGID_11_);}
|
||||
.st41{fill:url(#SVGID_12_);}
|
||||
.st42{fill:url(#SVGID_13_);}
|
||||
.st43{fill:url(#SVGID_14_);}
|
||||
.st44{fill:#C68D00;}
|
||||
.st45{fill:#CE000F;}
|
||||
</style>
|
||||
<g
|
||||
id="g75">
|
||||
<radialGradient
|
||||
id="XMLID_15_"
|
||||
cx="358.2692"
|
||||
cy="227.2655"
|
||||
r="830.0055"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F6971E"
|
||||
id="stop4" />
|
||||
<stop
|
||||
offset="0.6338"
|
||||
style="stop-color:#F4592D"
|
||||
id="stop6" />
|
||||
<stop
|
||||
offset="0.7025"
|
||||
style="stop-color:#EF4F29"
|
||||
id="stop8" />
|
||||
<stop
|
||||
offset="0.8178"
|
||||
style="stop-color:#E1351D"
|
||||
id="stop10" />
|
||||
<stop
|
||||
offset="0.9647"
|
||||
style="stop-color:#CA0B0B"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#C40006"
|
||||
id="stop14" />
|
||||
</radialGradient>
|
||||
<path
|
||||
id="XMLID_124_"
|
||||
style="fill:#ffffff;fill-opacity:0.15000001"
|
||||
class="st1"
|
||||
d="M 510.30078 9.0996094 A 502.79999 502.79999 0 0 0 7.5 511.90039 A 502.79999 502.79999 0 0 0 510.30078 1014.6992 A 502.79999 502.79999 0 0 0 1013.0996 511.90039 A 502.79999 502.79999 0 0 0 510.30078 9.0996094 z M 326.17578 78.685547 C 349.74023 78.648438 372.16211 83.875 393.09961 95 C 420.19961 112.9 439.6 136.99922 455 172.69922 C 465.4 205.69922 469.30078 238.79961 465.80078 281.59961 C 457.70078 373.59961 411.09922 469.09961 341.19922 531.59961 C 312.29922 557.49961 284.4 573.59961 256.5 589.59961 L 256.69922 593.19922 C 279.39922 594.99922 301.39922 586.10078 326.19922 571.80078 C 415.89922 516.50078 483.49922 397.69922 504.69922 285.19922 C 495.49922 338.79922 478.19922 391.4 449.69922 445 C 423.79922 489.6 397.30039 527.1 359.40039 562 C 300.00039 612.9 238.89961 638.80078 183.09961 626.30078 C 122.39961 611.00078 90.399609 545.8 92.599609 461 C 92.399609 457.4 92.1 453.89961 89 455.59961 C 87.6 458.29961 84.700781 463.60078 83.300781 466.30078 C 69.000781 517.30078 77.1 562.79922 91 601.19922 C 116.5 666.39922 177.79922 688.69922 244.69922 676.19922 C 204.99922 685.99922 167.69922 683.3 134.19922 665.5 C 107.09922 647.6 84.599609 625.30039 70.599609 586.90039 C 55.899609 537.80039 50.700391 486.89922 70.400391 421.69922 C 95.300391 338.69922 139.50078 255.59922 207.30078 209.19922 C 227.30078 195.79922 245.99922 185.09961 267.69922 172.59961 C 270.79922 170.79961 270.60039 167.20039 268.90039 166.40039 C 159.40039 170.00039 46.500391 333.30039 20.900391 474.40039 C 36.400391 372.60039 87.500391 272.6 167.90039 198.5 C 213.50039 157.4 258.79922 136.89922 305.19922 130.69922 C 386.89922 122.69922 437.10078 194.1 434.80078 299.5 C 435.00078 303.1 436.70039 304.00039 438.40039 304.90039 C 446.50039 281.70039 451.39961 260.29922 451.59961 239.69922 C 451.50293 126.5894 381.21362 66.112098 291.87891 82.363281 C 288.79216 82.977349 285.71662 83.531343 282.59961 84.300781 C 285.71508 83.559319 288.80642 82.922208 291.87891 82.363281 C 303.5351 80.044429 314.99734 78.703151 326.17578 78.685547 z M 858.04883 508.3457 C 873.78027 508.64453 888.6875 512.44922 902.5 520.19922 C 920.3 532.49922 935.10078 547.69961 943.80078 573.59961 C 952.90078 606.59961 955.59961 640.70039 941.59961 683.90039 C 923.79961 739.00039 893.09961 793.80039 847.09961 823.90039 C 833.49961 832.60039 820.89922 839.4 806.19922 847.5 C 804.09922 848.6 804.20078 850.99922 805.30078 851.69922 C 878.70078 851.09922 956.39961 743.59922 975.59961 649.69922 C 963.79961 717.49922 928.2 783.50078 873.5 831.80078 C 842.5 858.60078 811.90078 871.59961 780.80078 875.09961 C 726.10078 879.29961 693.59922 830.9 696.69922 760.5 C 696.59922 758.1 695.50039 757.50039 694.40039 756.90039 C 688.70039 772.30039 685.09961 786.49922 684.59961 800.19922 C 683.15311 870.80636 723.40104 911.63389 777.53906 908.77344 C 757.57984 910.46578 738.70856 907.29881 721.59961 897.69922 C 703.79961 885.39922 691.10039 869.00039 681.40039 844.90039 C 674.90039 822.70039 672.79922 800.6 675.69922 772 C 682.39922 710.7 714.9 647.60078 762.5 606.80078 C 782.1 589.90078 801.00039 579.60078 819.90039 569.30078 L 819.80078 566.90039 C 804.70078 565.40039 789.89961 570.99922 773.09961 580.19922 C 712.39961 615.89922 665.50078 694.2 649.80078 769 C 656.70078 733.4 669.00078 698.39961 688.80078 663.09961 C 706.80078 633.69961 725.00078 609.00078 750.80078 586.30078 C 791.20078 553.20078 832.40039 536.80039 869.40039 545.90039 C 909.80039 556.90039 930.2 600.9 927.5 657.5 C 927.6 659.9 927.70078 662.29961 929.80078 661.09961 C 930.80078 659.29961 932.80078 655.8 933.80078 654 C 944.00078 620.2 939.3 589.70078 930.5 563.80078 C 914.4 519.90078 873.80039 504.1 828.90039 511.5 C 838.87539 509.25 848.60996 508.16641 858.04883 508.3457 z " />
|
||||
<linearGradient
|
||||
id="XMLID_16_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="505.4734"
|
||||
y1="-52.674"
|
||||
x2="505.4734"
|
||||
y2="155.1105">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0.4"
|
||||
id="stop18" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0"
|
||||
id="stop20" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_17_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="503.3253"
|
||||
y1="-583.7885"
|
||||
x2="503.3253"
|
||||
y2="-376.4571"
|
||||
gradientTransform="matrix(-1 0 0 -1 1017 456.5313)">
|
||||
<stop
|
||||
offset="5.263158e-03"
|
||||
style="stop-color:#9E3A1D;stop-opacity:0.4"
|
||||
id="stop24" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#9E3A1D;stop-opacity:0"
|
||||
id="stop26" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_18_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="506.1886"
|
||||
y1="-38.7551"
|
||||
x2="506.1886"
|
||||
y2="169.0294"
|
||||
gradientTransform="matrix(4.489700e-11 1 -1 4.489700e-11 1026.6101 -2.3899)">
|
||||
<stop
|
||||
offset="5.263158e-03"
|
||||
style="stop-color:#9E3A1D;stop-opacity:0.4"
|
||||
id="stop30" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#9E3A1D;stop-opacity:0"
|
||||
id="stop32" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_19_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="502.6101"
|
||||
y1="-660.7308"
|
||||
x2="502.6101"
|
||||
y2="-450.373"
|
||||
gradientTransform="matrix(-4.489700e-11 -1 1 -4.489700e-11 570.0789 1014.6101)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0.4"
|
||||
id="stop36" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0"
|
||||
id="stop38" />
|
||||
</linearGradient>
|
||||
|
||||
<g
|
||||
id="XMLID_39_"
|
||||
class="st10">
|
||||
<defs
|
||||
id="defs43">
|
||||
|
||||
<ellipse
|
||||
id="XMLID_36_"
|
||||
transform="matrix(0.8019 -0.5974 0.5974 0.8019 -204.724 406.2339)"
|
||||
class="st10"
|
||||
cx="510.3"
|
||||
cy="511.9"
|
||||
ry="502.8"
|
||||
rx="502.8" />
|
||||
</defs>
|
||||
<clipPath
|
||||
id="XMLID_20_">
|
||||
<use
|
||||
xlink:href="#XMLID_36_"
|
||||
style="overflow:visible;"
|
||||
id="use45" />
|
||||
</clipPath>
|
||||
</g>
|
||||
<g
|
||||
id="XMLID_41_">
|
||||
<linearGradient
|
||||
id="XMLID_21_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="64.4989"
|
||||
y1="234.8705"
|
||||
x2="401.1502"
|
||||
y2="480.7042">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F4592D"
|
||||
id="stop49" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFD900"
|
||||
id="stop51" />
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_22_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="438.1351"
|
||||
y1="490.0881"
|
||||
x2="196.6566"
|
||||
y2="356.1772">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F64626"
|
||||
id="stop55" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFD900"
|
||||
id="stop57" />
|
||||
</linearGradient>
|
||||
|
||||
</g>
|
||||
<g
|
||||
id="XMLID_11_">
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_23_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-316.9261"
|
||||
y1="9.5862"
|
||||
x2="-92.0354"
|
||||
y2="173.8087"
|
||||
gradientTransform="matrix(-0.9998 -2.148304e-02 2.148304e-02 -0.9998 625.9278 811.8477)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F4592D"
|
||||
id="stop62" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFD900"
|
||||
id="stop64" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_24_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-52.9013"
|
||||
y1="188.0779"
|
||||
x2="-214.2144"
|
||||
y2="98.6225"
|
||||
gradientTransform="matrix(-0.9998 -2.148304e-02 2.148304e-02 -0.9998 625.9278 811.8477)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F42C2D"
|
||||
id="stop68" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFD900"
|
||||
id="stop70" />
|
||||
</linearGradient>
|
||||
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 10 KiB |
301
src/renderer/images/logo-light.svg
Normal file
301
src/renderer/images/logo-light.svg
Normal file
@@ -0,0 +1,301 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 1024 1024"
|
||||
style="enable-background:new 0 0 1024 1024;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="Antares-shape-1.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs80" /><sodipodi:namedview
|
||||
id="namedview78"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.66015625"
|
||||
inkscape:cx="512"
|
||||
inkscape:cy="511.2426"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g75" />
|
||||
<style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:url(#XMLID_15_);}
|
||||
.st2{opacity:0.5;fill:#FFBC00;}
|
||||
.st3{fill:#FFBC00;}
|
||||
.st4{fill:url(#XMLID_16_);}
|
||||
.st5{fill:url(#XMLID_17_);}
|
||||
.st6{fill:url(#XMLID_18_);}
|
||||
.st7{fill:url(#XMLID_19_);}
|
||||
.st8{fill:url(#XMLID_20_);}
|
||||
.st9{fill:url(#XMLID_21_);}
|
||||
.st10{opacity:0.46;}
|
||||
.st11{fill:url(#XMLID_23_);}
|
||||
.st12{fill:url(#XMLID_24_);}
|
||||
.st13{fill:url(#XMLID_25_);}
|
||||
.st14{fill:url(#XMLID_27_);}
|
||||
.st15{fill:url(#XMLID_28_);}
|
||||
.st16{fill:url(#XMLID_29_);}
|
||||
.st17{fill:url(#XMLID_30_);}
|
||||
.st18{opacity:0.75;}
|
||||
.st19{opacity:0.44;clip-path:url(#XMLID_31_);}
|
||||
.st20{fill:url(#XMLID_32_);}
|
||||
.st21{fill:url(#XMLID_33_);}
|
||||
.st22{fill:url(#XMLID_34_);}
|
||||
.st23{fill:url(#XMLID_35_);}
|
||||
.st24{fill:url(#XMLID_37_);}
|
||||
.st25{fill:url(#XMLID_38_);}
|
||||
.st26{opacity:0.43;fill:#FFBC00;}
|
||||
.st27{opacity:0.58;fill:#FFBC00;}
|
||||
.st28{fill:#FFBE06;}
|
||||
.st29{fill:none;}
|
||||
.st30{fill:url(#XMLID_42_);}
|
||||
.st31{fill:url(#XMLID_43_);}
|
||||
.st32{fill:url(#XMLID_44_);}
|
||||
.st33{fill:url(#XMLID_45_);}
|
||||
.st34{fill:url(#XMLID_46_);}
|
||||
.st35{fill:url(#SVGID_4_);}
|
||||
.st36{fill:url(#SVGID_5_);}
|
||||
.st37{fill:url(#SVGID_6_);}
|
||||
.st38{fill:url(#SVGID_7_);}
|
||||
.st39{fill:url(#SVGID_8_);}
|
||||
.st40{fill:url(#SVGID_11_);}
|
||||
.st41{fill:url(#SVGID_12_);}
|
||||
.st42{fill:url(#SVGID_13_);}
|
||||
.st43{fill:url(#SVGID_14_);}
|
||||
.st44{fill:#C68D00;}
|
||||
.st45{fill:#CE000F;}
|
||||
</style>
|
||||
<g
|
||||
id="g75">
|
||||
<radialGradient
|
||||
id="XMLID_15_"
|
||||
cx="358.2692"
|
||||
cy="227.2655"
|
||||
r="830.0055"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F6971E"
|
||||
id="stop4" />
|
||||
<stop
|
||||
offset="0.6338"
|
||||
style="stop-color:#F4592D"
|
||||
id="stop6" />
|
||||
<stop
|
||||
offset="0.7025"
|
||||
style="stop-color:#EF4F29"
|
||||
id="stop8" />
|
||||
<stop
|
||||
offset="0.8178"
|
||||
style="stop-color:#E1351D"
|
||||
id="stop10" />
|
||||
<stop
|
||||
offset="0.9647"
|
||||
style="stop-color:#CA0B0B"
|
||||
id="stop12" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#C40006"
|
||||
id="stop14" />
|
||||
</radialGradient>
|
||||
<path
|
||||
id="XMLID_124_"
|
||||
style="fill:#000000;fill-opacity:0.5"
|
||||
class="st1"
|
||||
d="M 510.30078 9.0996094 A 502.79999 502.79999 0 0 0 7.5 511.90039 A 502.79999 502.79999 0 0 0 510.30078 1014.6992 A 502.79999 502.79999 0 0 0 1013.0996 511.90039 A 502.79999 502.79999 0 0 0 510.30078 9.0996094 z M 326.17578 78.685547 C 349.74023 78.648438 372.16211 83.875 393.09961 95 C 420.19961 112.9 439.6 136.99922 455 172.69922 C 465.4 205.69922 469.30078 238.79961 465.80078 281.59961 C 457.70078 373.59961 411.09922 469.09961 341.19922 531.59961 C 312.29922 557.49961 284.4 573.59961 256.5 589.59961 L 256.69922 593.19922 C 279.39922 594.99922 301.39922 586.10078 326.19922 571.80078 C 415.89922 516.50078 483.49922 397.69922 504.69922 285.19922 C 495.49922 338.79922 478.19922 391.4 449.69922 445 C 423.79922 489.6 397.30039 527.1 359.40039 562 C 300.00039 612.9 238.89961 638.80078 183.09961 626.30078 C 122.39961 611.00078 90.399609 545.8 92.599609 461 C 92.399609 457.4 92.1 453.89961 89 455.59961 C 87.6 458.29961 84.700781 463.60078 83.300781 466.30078 C 69.000781 517.30078 77.1 562.79922 91 601.19922 C 116.5 666.39922 177.79922 688.69922 244.69922 676.19922 C 204.99922 685.99922 167.69922 683.3 134.19922 665.5 C 107.09922 647.6 84.599609 625.30039 70.599609 586.90039 C 55.899609 537.80039 50.700391 486.89922 70.400391 421.69922 C 95.300391 338.69922 139.50078 255.59922 207.30078 209.19922 C 227.30078 195.79922 245.99922 185.09961 267.69922 172.59961 C 270.79922 170.79961 270.60039 167.20039 268.90039 166.40039 C 159.40039 170.00039 46.500391 333.30039 20.900391 474.40039 C 36.400391 372.60039 87.500391 272.6 167.90039 198.5 C 213.50039 157.4 258.79922 136.89922 305.19922 130.69922 C 386.89922 122.69922 437.10078 194.1 434.80078 299.5 C 435.00078 303.1 436.70039 304.00039 438.40039 304.90039 C 446.50039 281.70039 451.39961 260.29922 451.59961 239.69922 C 451.50293 126.5894 381.21362 66.112098 291.87891 82.363281 C 288.79216 82.977349 285.71662 83.531343 282.59961 84.300781 C 285.71508 83.559319 288.80642 82.922208 291.87891 82.363281 C 303.5351 80.044429 314.99734 78.703151 326.17578 78.685547 z M 858.04883 508.3457 C 873.78027 508.64453 888.6875 512.44922 902.5 520.19922 C 920.3 532.49922 935.10078 547.69961 943.80078 573.59961 C 952.90078 606.59961 955.59961 640.70039 941.59961 683.90039 C 923.79961 739.00039 893.09961 793.80039 847.09961 823.90039 C 833.49961 832.60039 820.89922 839.4 806.19922 847.5 C 804.09922 848.6 804.20078 850.99922 805.30078 851.69922 C 878.70078 851.09922 956.39961 743.59922 975.59961 649.69922 C 963.79961 717.49922 928.2 783.50078 873.5 831.80078 C 842.5 858.60078 811.90078 871.59961 780.80078 875.09961 C 726.10078 879.29961 693.59922 830.9 696.69922 760.5 C 696.59922 758.1 695.50039 757.50039 694.40039 756.90039 C 688.70039 772.30039 685.09961 786.49922 684.59961 800.19922 C 683.15311 870.80636 723.40104 911.63389 777.53906 908.77344 C 757.57984 910.46578 738.70856 907.29881 721.59961 897.69922 C 703.79961 885.39922 691.10039 869.00039 681.40039 844.90039 C 674.90039 822.70039 672.79922 800.6 675.69922 772 C 682.39922 710.7 714.9 647.60078 762.5 606.80078 C 782.1 589.90078 801.00039 579.60078 819.90039 569.30078 L 819.80078 566.90039 C 804.70078 565.40039 789.89961 570.99922 773.09961 580.19922 C 712.39961 615.89922 665.50078 694.2 649.80078 769 C 656.70078 733.4 669.00078 698.39961 688.80078 663.09961 C 706.80078 633.69961 725.00078 609.00078 750.80078 586.30078 C 791.20078 553.20078 832.40039 536.80039 869.40039 545.90039 C 909.80039 556.90039 930.2 600.9 927.5 657.5 C 927.6 659.9 927.70078 662.29961 929.80078 661.09961 C 930.80078 659.29961 932.80078 655.8 933.80078 654 C 944.00078 620.2 939.3 589.70078 930.5 563.80078 C 914.4 519.90078 873.80039 504.1 828.90039 511.5 C 838.87539 509.25 848.60996 508.16641 858.04883 508.3457 z " />
|
||||
<linearGradient
|
||||
id="XMLID_16_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="505.4734"
|
||||
y1="-52.674"
|
||||
x2="505.4734"
|
||||
y2="155.1105">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0.4"
|
||||
id="stop18" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0"
|
||||
id="stop20" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_17_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="503.3253"
|
||||
y1="-583.7885"
|
||||
x2="503.3253"
|
||||
y2="-376.4571"
|
||||
gradientTransform="matrix(-1 0 0 -1 1017 456.5313)">
|
||||
<stop
|
||||
offset="5.263158e-03"
|
||||
style="stop-color:#9E3A1D;stop-opacity:0.4"
|
||||
id="stop24" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#9E3A1D;stop-opacity:0"
|
||||
id="stop26" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_18_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="506.1886"
|
||||
y1="-38.7551"
|
||||
x2="506.1886"
|
||||
y2="169.0294"
|
||||
gradientTransform="matrix(4.489700e-11 1 -1 4.489700e-11 1026.6101 -2.3899)">
|
||||
<stop
|
||||
offset="5.263158e-03"
|
||||
style="stop-color:#9E3A1D;stop-opacity:0.4"
|
||||
id="stop30" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#9E3A1D;stop-opacity:0"
|
||||
id="stop32" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_19_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="502.6101"
|
||||
y1="-660.7308"
|
||||
x2="502.6101"
|
||||
y2="-450.373"
|
||||
gradientTransform="matrix(-4.489700e-11 -1 1 -4.489700e-11 570.0789 1014.6101)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0.4"
|
||||
id="stop36" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0"
|
||||
id="stop38" />
|
||||
</linearGradient>
|
||||
|
||||
<g
|
||||
id="XMLID_39_"
|
||||
class="st10">
|
||||
<defs
|
||||
id="defs43">
|
||||
|
||||
<ellipse
|
||||
id="XMLID_36_"
|
||||
transform="matrix(0.8019 -0.5974 0.5974 0.8019 -204.724 406.2339)"
|
||||
class="st10"
|
||||
cx="510.3"
|
||||
cy="511.9"
|
||||
ry="502.8"
|
||||
rx="502.8" />
|
||||
</defs>
|
||||
<clipPath
|
||||
id="XMLID_20_">
|
||||
<use
|
||||
xlink:href="#XMLID_36_"
|
||||
style="overflow:visible;"
|
||||
id="use45" />
|
||||
</clipPath>
|
||||
</g>
|
||||
<g
|
||||
id="XMLID_41_">
|
||||
<linearGradient
|
||||
id="XMLID_21_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="64.4989"
|
||||
y1="234.8705"
|
||||
x2="401.1502"
|
||||
y2="480.7042">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F4592D"
|
||||
id="stop49" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFD900"
|
||||
id="stop51" />
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_22_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="438.1351"
|
||||
y1="490.0881"
|
||||
x2="196.6566"
|
||||
y2="356.1772">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F64626"
|
||||
id="stop55" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFD900"
|
||||
id="stop57" />
|
||||
</linearGradient>
|
||||
|
||||
</g>
|
||||
<g
|
||||
id="XMLID_11_">
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_23_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-316.9261"
|
||||
y1="9.5862"
|
||||
x2="-92.0354"
|
||||
y2="173.8087"
|
||||
gradientTransform="matrix(-0.9998 -2.148304e-02 2.148304e-02 -0.9998 625.9278 811.8477)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F4592D"
|
||||
id="stop62" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFD900"
|
||||
id="stop64" />
|
||||
</linearGradient>
|
||||
|
||||
|
||||
<linearGradient
|
||||
id="XMLID_24_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-52.9013"
|
||||
y1="188.0779"
|
||||
x2="-214.2144"
|
||||
y2="98.6225"
|
||||
gradientTransform="matrix(-0.9998 -2.148304e-02 2.148304e-02 -0.9998 625.9278 811.8477)">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#F42C2D"
|
||||
id="stop68" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#FFD900"
|
||||
id="stop70" />
|
||||
</linearGradient>
|
||||
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 10 KiB |
@@ -1,11 +1,6 @@
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
schema () {
|
||||
return this.workspace.breadcrumbs.schema;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async updateField (payload) {
|
||||
this.isQuering = true;
|
||||
|
@@ -63,6 +63,12 @@
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-clear {
|
||||
&:hover {
|
||||
background: rgba($light-color, 20%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
@@ -191,19 +197,8 @@
|
||||
color: $body-font-color-dark;
|
||||
}
|
||||
|
||||
& &.tools-dropdown {
|
||||
.tab-link:focus {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.menu {
|
||||
.menu-item a {
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
background: $bg-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.tools-dropdown {
|
||||
background-color: $bg-color-light-dark;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,9 +209,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.connection-panel {
|
||||
.panel {
|
||||
background: rgba($bg-color-light-dark, 50%);
|
||||
}
|
||||
}
|
||||
|
||||
.bg-checkered {
|
||||
background-image: linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)),
|
||||
linear-gradient(to right, black 50%, white 50%), linear-gradient(to bottom, black 50%, white 50%);
|
||||
background-image:
|
||||
linear-gradient(to right, rgba(192, 192, 192, 0.75), rgba(192, 192, 192, 0.75)),
|
||||
linear-gradient(to right, black 50%, white 50%),
|
||||
linear-gradient(to bottom, black 50%, white 50%);
|
||||
background-blend-mode: normal, difference, normal;
|
||||
background-size: 2em 2em;
|
||||
}
|
||||
@@ -384,11 +387,6 @@
|
||||
background: rgba(48, 55, 66, 0.95);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:hover .ex-tooltip-content {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
#footer {
|
||||
|
@@ -168,11 +168,6 @@
|
||||
background: rgba(48, 55, 66, 0.95);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&:hover .ex-tooltip-content {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.workspace {
|
||||
@@ -191,6 +186,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-tabs {
|
||||
.tab-block {
|
||||
.tab-item {
|
||||
&.tools-dropdown {
|
||||
background-color: $body-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-query-results {
|
||||
.table {
|
||||
.th {
|
||||
@@ -205,6 +210,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.connection-panel {
|
||||
.panel {
|
||||
background: rgba($bg-color-light-gray, 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.context {
|
||||
color: $body-font-color-dark;
|
||||
|
||||
|
@@ -10,7 +10,8 @@ else
|
||||
|
||||
const persistentStore = new Store({
|
||||
name: 'connections',
|
||||
encryptionKey: key
|
||||
encryptionKey: key,
|
||||
clearInvalidConfig: true
|
||||
});
|
||||
|
||||
export default {
|
||||
@@ -23,6 +24,7 @@ export default {
|
||||
getConnections: state => state.connections,
|
||||
getConnectionName: state => uid => {
|
||||
const connection = state.connections.filter(connection => connection.uid === uid)[0];
|
||||
if (!connection) return '';
|
||||
return connection.name
|
||||
? connection.name
|
||||
: connection.ask
|
||||
|
@@ -16,7 +16,8 @@ export default {
|
||||
line_wrap: persistentStore.get('line_wrap', true),
|
||||
application_theme: persistentStore.get('application_theme', 'dark'),
|
||||
editor_theme: persistentStore.get('editor_theme', 'twilight'),
|
||||
editor_font_size: persistentStore.get('editor_font_size', 'medium')
|
||||
editor_font_size: persistentStore.get('editor_font_size', 'medium'),
|
||||
restore_tabs: persistentStore.get('restore_tabs', true)
|
||||
},
|
||||
getters: {
|
||||
getLocale: state => state.locale,
|
||||
@@ -28,7 +29,8 @@ export default {
|
||||
getLineWrap: state => state.line_wrap,
|
||||
getApplicationTheme: state => state.application_theme,
|
||||
getEditorTheme: state => state.editor_theme,
|
||||
getEditorFontSize: state => state.editor_font_size
|
||||
getEditorFontSize: state => state.editor_font_size,
|
||||
getRestoreTabs: state => state.restore_tabs
|
||||
},
|
||||
mutations: {
|
||||
SET_LOCALE (state, locale) {
|
||||
@@ -71,6 +73,10 @@ export default {
|
||||
SET_EDITOR_FONT_SIZE (state, size) {
|
||||
state.editor_font_size = size;
|
||||
persistentStore.set('editor_font_size', state.editor_font_size);
|
||||
},
|
||||
SET_RESTORE_TABS (state, val) {
|
||||
state.restore_tabs = val;
|
||||
persistentStore.set('restore_tabs', state.restore_tabs);
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
@@ -103,6 +109,9 @@ export default {
|
||||
},
|
||||
changeEditorFontSize ({ commit }, size) {
|
||||
commit('SET_EDITOR_FONT_SIZE', size);
|
||||
},
|
||||
changeRestoreTabs ({ commit }, size) {
|
||||
commit('SET_RESTORE_TABS', size);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@@ -1,26 +1,24 @@
|
||||
'use strict';
|
||||
import Store from 'electron-store';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import Schema from '@/ipc-api/Schema';
|
||||
import Users from '@/ipc-api/Users';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
const persistentStore = new Store({ name: 'tabs' });
|
||||
const tabIndex = [];
|
||||
let lastBreadcrumbs = {};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
strict: true,
|
||||
state: {
|
||||
workspaces: [],
|
||||
selected_workspace: null,
|
||||
has_unsaved_changes: false,
|
||||
is_unsaved_discard_modal: false,
|
||||
pending_breadcrumbs: {}
|
||||
selected_workspace: null
|
||||
},
|
||||
getters: {
|
||||
getSelected: state => {
|
||||
if (state.selected_workspace) return state.selected_workspace;
|
||||
if (state.workspaces.length) return state.workspaces[0].uid;
|
||||
return null;
|
||||
return 'NEW';
|
||||
},
|
||||
getWorkspace: state => uid => {
|
||||
return state.workspaces.find(workspace => workspace.uid === uid);
|
||||
@@ -45,18 +43,27 @@ export default {
|
||||
},
|
||||
getSearchTerm: state => uid => {
|
||||
return state.workspaces.find(workspace => workspace.uid === uid).search_term;
|
||||
},
|
||||
isUnsavedDiscardModal: state => {
|
||||
return state.is_unsaved_discard_modal;
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
SELECT_WORKSPACE (state, uid) {
|
||||
state.selected_workspace = uid;
|
||||
if (!uid)
|
||||
state.selected_workspace = state.workspaces.length ? state.workspaces[0].uid : 'NEW';
|
||||
else
|
||||
state.selected_workspace = uid;
|
||||
},
|
||||
SET_CONNECTED (state, payload) {
|
||||
const { uid, client, dataTypes, indexTypes, customizations, structure, version } = payload;
|
||||
|
||||
const cachedTabs = payload.restoreTabs ? persistentStore.get(uid, []) : [];
|
||||
|
||||
if (cachedTabs.length) {
|
||||
tabIndex[uid] = cachedTabs.reduce((acc, curr) => {
|
||||
if (curr.index > acc) acc = curr.index;
|
||||
return acc;
|
||||
}, null);
|
||||
}
|
||||
|
||||
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid
|
||||
? {
|
||||
...workspace,
|
||||
@@ -66,6 +73,8 @@ export default {
|
||||
customizations,
|
||||
structure,
|
||||
connection_status: 'connected',
|
||||
tabs: cachedTabs,
|
||||
selected_tab: cachedTabs.length ? cachedTabs[0].uid : null,
|
||||
version
|
||||
}
|
||||
: workspace);
|
||||
@@ -175,18 +184,24 @@ export default {
|
||||
}
|
||||
: workspace);
|
||||
},
|
||||
NEW_TAB (state, { uid, tab, content, autorun }) {
|
||||
tabIndex[uid] = tabIndex[uid] ? ++tabIndex[uid] : 1;
|
||||
NEW_TAB (state, { uid, tab, content, type, autorun, schema, elementName, elementType }) {
|
||||
if (type === 'query')
|
||||
tabIndex[uid] = tabIndex[uid] ? ++tabIndex[uid] : 1;
|
||||
|
||||
const newTab = {
|
||||
uid: tab,
|
||||
index: tabIndex[uid],
|
||||
index: type === 'query' ? tabIndex[uid] : null,
|
||||
selected: false,
|
||||
type: 'query',
|
||||
type,
|
||||
schema,
|
||||
elementName,
|
||||
elementType,
|
||||
fields: [],
|
||||
keyUsage: [],
|
||||
content: content || '',
|
||||
autorun: !!autorun
|
||||
};
|
||||
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
@@ -197,6 +212,8 @@ export default {
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, state.workspaces.find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
REMOVE_TAB (state, { uid, tab: tUid }) {
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
@@ -209,10 +226,78 @@ export default {
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, state.workspaces.find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
REMOVE_TABS (state, { uid, schema, elementName, elementType }) { // Multiple tabs based on schema and element name
|
||||
if (elementType === 'procedure') elementType = 'routine'; // TODO: pass directly "routine"
|
||||
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.filter(tab =>
|
||||
tab.schema !== schema ||
|
||||
tab.elementName !== elementName ||
|
||||
tab.elementType !== elementType
|
||||
)
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, state.workspaces.find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
REPLACE_TAB (state, { uid, tab: tUid, type, schema, content, elementName, elementType }) {
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.map(tab => {
|
||||
if (tab.uid === tUid)
|
||||
return { ...tab, type, schema, content, elementName, elementType };
|
||||
|
||||
return tab;
|
||||
})
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, state.workspaces.find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
RENAME_TABS (state, { uid, schema, elementName, elementType, elementNewName }) {
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.map(tab => {
|
||||
if (tab.elementName === elementName && tab.schema === schema) {
|
||||
return {
|
||||
...tab,
|
||||
elementName: elementNewName
|
||||
};
|
||||
}
|
||||
|
||||
return tab;
|
||||
})
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, state.workspaces.find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
SELECT_TAB (state, { uid, tab }) {
|
||||
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, selected_tab: tab } : workspace);
|
||||
},
|
||||
UPDATE_TABS (state, { uid, tabs }) {
|
||||
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid ? { ...workspace, tabs } : workspace);
|
||||
persistentStore.set(uid, state.workspaces.find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
SET_TAB_FIELDS (state, { cUid, tUid, fields }) {
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
if (workspace.uid === cUid) {
|
||||
@@ -229,6 +314,8 @@ export default {
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, state.workspaces.find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
SET_TAB_KEY_USAGE (state, { cUid, tUid, keyUsage }) {
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
@@ -246,15 +333,25 @@ export default {
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
|
||||
persistentStore.set(uid, state.workspaces.find(workspace => workspace.uid === uid).tabs);
|
||||
},
|
||||
SET_UNSAVED_CHANGES (state, val) {
|
||||
state.has_unsaved_changes = !!val;
|
||||
},
|
||||
SET_UNSAVED_DISCARD_MODAL (state, val) {
|
||||
state.is_unsaved_discard_modal = !!val;
|
||||
},
|
||||
SET_PENDING_BREADCRUMBS (state, payload) {
|
||||
state.pending_breadcrumbs = payload;
|
||||
SET_UNSAVED_CHANGES (state, { uid, tUid, isChanged }) {
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
if (workspace.uid === uid) {
|
||||
return {
|
||||
...workspace,
|
||||
tabs: workspace.tabs.map(tab => {
|
||||
if (tab.uid === tUid)
|
||||
return { ...tab, isChanged };
|
||||
|
||||
return tab;
|
||||
})
|
||||
};
|
||||
}
|
||||
else
|
||||
return workspace;
|
||||
});
|
||||
},
|
||||
ADD_LOADED_SCHEMA (state, payload) {
|
||||
state.workspaces = state.workspaces.map(workspace => {
|
||||
@@ -268,7 +365,7 @@ export default {
|
||||
selectWorkspace ({ commit }, uid) {
|
||||
commit('SELECT_WORKSPACE', uid);
|
||||
},
|
||||
async connectWorkspace ({ dispatch, commit }, connection) {
|
||||
async connectWorkspace ({ dispatch, commit, getters, rootGetters }, connection) {
|
||||
commit('SET_CONNECTING', connection.uid);
|
||||
|
||||
try {
|
||||
@@ -301,6 +398,7 @@ export default {
|
||||
if (status === 'error')
|
||||
dispatch('notifications/addNotification', { status, message: version }, { root: true });
|
||||
|
||||
// Check if Maria or MySQL
|
||||
const isMySQL = version.name.includes('MySQL');
|
||||
|
||||
if (isMySQL && connection.client !== 'mysql') {
|
||||
@@ -321,7 +419,8 @@ export default {
|
||||
indexTypes,
|
||||
customizations,
|
||||
structure: response,
|
||||
version
|
||||
version,
|
||||
restoreTabs: rootGetters['settings/getRestoreTabs']
|
||||
});
|
||||
dispatch('refreshCollations', connection.uid);
|
||||
dispatch('refreshVariables', connection.uid);
|
||||
@@ -411,7 +510,7 @@ export default {
|
||||
commit('SET_DISCONNECTED', uid);
|
||||
commit('SELECT_TAB', { uid, tab: 0 });
|
||||
},
|
||||
addWorkspace ({ commit, dispatch, getters }, uid) {
|
||||
addWorkspace ({ commit }, uid) {
|
||||
const workspace = {
|
||||
uid,
|
||||
connection_status: 'disconnected',
|
||||
@@ -427,75 +526,211 @@ export default {
|
||||
};
|
||||
|
||||
commit('ADD_WORKSPACE', workspace);
|
||||
|
||||
if (getters.getWorkspace(uid).tabs.length < 3)
|
||||
dispatch('newTab', { uid });
|
||||
|
||||
dispatch('setUnsavedChanges', false);
|
||||
},
|
||||
changeBreadcrumbs ({ state, commit, getters }, payload) {
|
||||
if (state.has_unsaved_changes) {
|
||||
commit('SET_UNSAVED_DISCARD_MODAL', true);
|
||||
commit('SET_PENDING_BREADCRUMBS', payload);
|
||||
return;
|
||||
}
|
||||
|
||||
changeBreadcrumbs ({ commit, getters }, payload) {
|
||||
const breadcrumbsObj = {
|
||||
schema: null,
|
||||
table: null,
|
||||
trigger: null,
|
||||
triggerFunction: null,
|
||||
procedure: null,
|
||||
function: null,
|
||||
scheduler: null,
|
||||
view: null
|
||||
view: null,
|
||||
query: null
|
||||
};
|
||||
|
||||
const hasLastChildren = Object.keys(lastBreadcrumbs).filter(b => b !== 'schema').some(b => lastBreadcrumbs[b]);
|
||||
const hasChildren = Object.keys(payload).filter(b => b !== 'schema').some(b => payload[b]);
|
||||
|
||||
if (lastBreadcrumbs.schema === payload.schema && hasLastChildren && !hasChildren) return;
|
||||
|
||||
if (lastBreadcrumbs.schema !== payload.schema)
|
||||
Schema.useSchema({ uid: getters.getSelected, schema: payload.schema });
|
||||
|
||||
commit('CHANGE_BREADCRUMBS', { uid: getters.getSelected, breadcrumbs: { ...breadcrumbsObj, ...payload } });
|
||||
lastBreadcrumbs = { ...breadcrumbsObj, ...payload };
|
||||
|
||||
if (payload.schema)
|
||||
commit('ADD_LOADED_SCHEMA', { uid: getters.getSelected, schema: payload.schema });
|
||||
},
|
||||
addLoadedSchema ({ commit, getters }, schema) {
|
||||
commit('ADD_LOADED_SCHEMA', { uid: getters.getSelected, schema });
|
||||
},
|
||||
setSearchTerm ({ commit, getters }, term) {
|
||||
commit('SET_SEARCH_TERM', { uid: getters.getSelected, term });
|
||||
},
|
||||
newTab ({ commit }, { uid, content, autorun }) {
|
||||
const tab = uidGen('T');
|
||||
newTab ({ state, commit }, { uid, content, type, autorun, schema, elementName, elementType }) {
|
||||
let tabUid;
|
||||
const workspaceTabs = state.workspaces.find(workspace => workspace.uid === uid);
|
||||
|
||||
commit('NEW_TAB', { uid, tab, content, autorun });
|
||||
commit('SELECT_TAB', { uid, tab });
|
||||
switch (type) {
|
||||
case 'temp-data': {
|
||||
const existentTab = workspaceTabs
|
||||
? workspaceTabs.tabs.find(tab =>
|
||||
tab.schema === schema &&
|
||||
tab.elementName === elementName &&
|
||||
tab.elementType === elementType &&
|
||||
['temp-data', 'data'].includes(tab.type))
|
||||
: false;
|
||||
|
||||
if (existentTab) { // if data tab exists
|
||||
tabUid = existentTab.uid;
|
||||
}
|
||||
else {
|
||||
const tempTabs = workspaceTabs ? workspaceTabs.tabs.filter(tab => tab.type === 'temp-data') : false;
|
||||
if (tempTabs && tempTabs.length) { // if temp table already opened
|
||||
for (const tab of tempTabs) {
|
||||
commit('REPLACE_TAB', { uid, tab: tab.uid, type, schema, elementName, elementType });
|
||||
tabUid = tab.uid;
|
||||
}
|
||||
}
|
||||
else {
|
||||
tabUid = uidGen('T');
|
||||
commit('NEW_TAB', { uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'data': {
|
||||
const existentTab = workspaceTabs
|
||||
? workspaceTabs.tabs.find(tab =>
|
||||
tab.schema === schema &&
|
||||
tab.elementName === elementName &&
|
||||
tab.elementType === elementType &&
|
||||
['temp-data', 'data'].includes(tab.type))
|
||||
: false;
|
||||
|
||||
if (existentTab) {
|
||||
commit('REPLACE_TAB', { uid, tab: existentTab.uid, type, schema, elementName, elementType });
|
||||
tabUid = existentTab.uid;
|
||||
}
|
||||
else {
|
||||
tabUid = uidGen('T');
|
||||
commit('NEW_TAB', { uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'table-props': {
|
||||
const existentTab = workspaceTabs
|
||||
? workspaceTabs.tabs.find(tab =>
|
||||
tab.elementName === elementName &&
|
||||
tab.elementType === elementType &&
|
||||
tab.type === type)
|
||||
: false;
|
||||
|
||||
if (existentTab) {
|
||||
commit('REPLACE_TAB', { uid, tab: existentTab.uid, type, schema, elementName, elementType });
|
||||
tabUid = existentTab.uid;
|
||||
}
|
||||
else {
|
||||
tabUid = uidGen('T');
|
||||
commit('NEW_TAB', { uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'temp-trigger-props':
|
||||
case 'temp-trigger-function-props':
|
||||
case 'temp-function-props':
|
||||
case 'temp-routine-props':
|
||||
case 'temp-scheduler-props': {
|
||||
const existentTab = workspaceTabs
|
||||
? workspaceTabs.tabs.find(tab =>
|
||||
tab.schema === schema &&
|
||||
tab.elementName === elementName &&
|
||||
tab.elementType === elementType &&
|
||||
[type, type.replace('temp-', '')].includes(tab.type))
|
||||
: false;
|
||||
|
||||
if (existentTab) { // if tab exists
|
||||
tabUid = existentTab.uid;
|
||||
}
|
||||
else {
|
||||
const tempTabs = workspaceTabs ? workspaceTabs.tabs.filter(tab => tab.type.includes('temp-')) : false;
|
||||
if (tempTabs && tempTabs.length) { // if temp tab already opened
|
||||
for (const tab of tempTabs) {
|
||||
if (tab.isChanged) {
|
||||
commit('REPLACE_TAB', { // make permanent a temp table with unsaved changes
|
||||
uid,
|
||||
tab: tab.uid,
|
||||
type: tab.type.replace('temp-', ''),
|
||||
schema: tab.schema,
|
||||
elementName: tab.elementName,
|
||||
elementType: tab.elementType
|
||||
});
|
||||
|
||||
tabUid = uidGen('T');
|
||||
commit('NEW_TAB', { uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
else {
|
||||
commit('REPLACE_TAB', { uid, tab: tab.uid, type, schema, elementName, elementType });
|
||||
tabUid = tab.uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
tabUid = uidGen('T');
|
||||
commit('NEW_TAB', { uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'trigger-props':
|
||||
case 'trigger-function-props':
|
||||
case 'function-props':
|
||||
case 'routine-props':
|
||||
case 'scheduler-props': {
|
||||
const existentTab = workspaceTabs
|
||||
? workspaceTabs.tabs.find(tab =>
|
||||
tab.schema === schema &&
|
||||
tab.elementName === elementName &&
|
||||
tab.elementType === elementType &&
|
||||
[`temp-${type}`, type].includes(tab.type))
|
||||
: false;
|
||||
|
||||
if (existentTab) {
|
||||
commit('REPLACE_TAB', { uid, tab: existentTab.uid, type, schema, elementName, elementType });
|
||||
tabUid = existentTab.uid;
|
||||
}
|
||||
else {
|
||||
tabUid = uidGen('T');
|
||||
commit('NEW_TAB', { uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
tabUid = uidGen('T');
|
||||
commit('NEW_TAB', { uid, tab: tabUid, content, type, autorun, schema, elementName, elementType });
|
||||
break;
|
||||
}
|
||||
|
||||
commit('SELECT_TAB', { uid, tab: tabUid });
|
||||
},
|
||||
removeTab ({ commit }, payload) {
|
||||
checkSelectedTabExists ({ state, commit }, uid) {
|
||||
const workspace = state.workspaces.find(workspace => workspace.uid === uid);
|
||||
const isSelectedExistent = workspace
|
||||
? workspace.tabs.some(tab => tab.uid === workspace.selected_tab)
|
||||
: false;
|
||||
|
||||
if (!isSelectedExistent && workspace.tabs.length)
|
||||
commit('SELECT_TAB', { uid, tab: workspace.tabs[workspace.tabs.length - 1].uid });
|
||||
},
|
||||
updateTabContent ({ commit }, { uid, tab, type, schema, content }) {
|
||||
commit('REPLACE_TAB', { uid, tab, type, schema, content });
|
||||
},
|
||||
renameTabs ({ commit }, payload) {
|
||||
commit('RENAME_TABS', payload);
|
||||
},
|
||||
removeTab ({ commit, dispatch }, payload) {
|
||||
commit('REMOVE_TAB', payload);
|
||||
dispatch('checkSelectedTabExists', payload.uid);
|
||||
},
|
||||
removeTabs ({ commit, dispatch }, payload) {
|
||||
commit('REMOVE_TABS', payload);
|
||||
dispatch('checkSelectedTabExists', payload.uid);
|
||||
},
|
||||
selectTab ({ commit }, payload) {
|
||||
commit('SELECT_TAB', payload);
|
||||
},
|
||||
updateTabs ({ commit }, payload) {
|
||||
commit('UPDATE_TABS', payload);
|
||||
},
|
||||
setTabFields ({ commit }, payload) {
|
||||
commit('SET_TAB_FIELDS', payload);
|
||||
},
|
||||
setTabKeyUsage ({ commit }, payload) {
|
||||
commit('SET_TAB_KEY_USAGE', payload);
|
||||
},
|
||||
setUnsavedChanges ({ commit }, val) {
|
||||
commit('SET_UNSAVED_CHANGES', val);
|
||||
},
|
||||
discardUnsavedChanges ({ state, commit, dispatch }) {
|
||||
dispatch('setUnsavedChanges', false);
|
||||
dispatch('changeBreadcrumbs', state.pending_breadcrumbs);
|
||||
commit('SET_UNSAVED_DISCARD_MODAL', false);
|
||||
commit('SET_PENDING_BREADCRUMBS', {});
|
||||
},
|
||||
closeUnsavedChangesModal ({ commit }) {
|
||||
commit('SET_UNSAVED_DISCARD_MODAL', false);
|
||||
setUnsavedChanges ({ commit }, payload) {
|
||||
commit('SET_UNSAVED_CHANGES', payload);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user