1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-06-05 21:59:22 +02:00

Compare commits

..

397 Commits

Author SHA1 Message Date
19d9f56f08 chore(release): 0.7.19 2023-11-01 09:43:50 +01:00
4c89578188 Merge branch 'develop' of https://github.com/antares-sql/antares into beta 2023-11-01 09:42:59 +01:00
f6fb266771 fix: table field changes not saved on text fields if pressing enter on textarea modal 2023-10-31 17:57:58 +01:00
3e739bcaa2 chore(release): 0.7.19-beta.2 2023-10-29 11:47:08 +01:00
debc1da289 fix: ssh tunnel keep-alive not working properly 2023-10-28 19:09:19 +02:00
3c2e2be40f chore: regenerate package-lock.json 2023-10-28 18:47:06 +02:00
581ec6a25d Merge branch 'develop' of https://github.com/antares-sql/antares into develop 2023-10-28 18:25:03 +02:00
d30a978cd6 refactor: replace ssh2-promise with @fabio286/ssh2-promise 2023-10-28 18:25:01 +02:00
0015f2e860 Merge branch 'master' of https://github.com/antares-sql/antares into develop 2023-10-28 11:58:06 +02:00
389e6624d8 chore: update stylelint dependencies 2023-10-28 11:55:18 +02:00
275344eb8b chore(release): 0.7.19-beta.1 2023-10-26 01:07:15 +02:00
cf24adf99e Merge branch 'develop' of https://github.com/antares-sql/antares into beta 2023-10-26 01:06:54 +02:00
2eae580e18 chore: update electron 2023-10-22 19:04:31 +02:00
e4eb27d503 feat(MySQL): RLIKE and NOT RLIKE regular expression filters, closes #688 2023-10-18 18:08:01 +02:00
580973fd04 chore(release): 0.7.19-beta.0 2023-10-14 15:04:00 +02:00
215ab783ab chore: email change 2023-10-14 15:03:09 +02:00
72148e991c Merge branch 'master' of https://github.com/antares-sql/antares into develop 2023-10-13 09:23:41 +02:00
6e4c16741a chore: Update CODE_OF_CONDUCT.md 2023-10-13 09:22:04 +02:00
9f9c63bfcc feat: "now" and "random" options added in datetime related data in insert rows tool, closes #402 2023-10-10 18:36:35 +02:00
c0dcf30e73 fix: IN and NOT IN filters not working properly, fixes #687 2023-10-09 18:13:30 +02:00
ddd290c903 fix: timeout issue on long time sql import 2023-10-03 18:19:16 +02:00
267c017921 chore(release): 0.7.18 2023-10-03 09:31:58 +02:00
b3b698b3a2 fix: hotfix for Microsoft Store unauthorized process 2023-10-03 09:31:26 +02:00
71ac3a5164 chore(release): 0.7.17 2023-09-30 16:46:49 +02:00
6fc4418c02 chore(release): 0.7.17-beta.2 2023-09-28 18:11:10 +02:00
b37781df84 fix(UI): small icons in foreign key modal 2023-09-26 18:31:58 +02:00
9c66fd51cb feat: add NOT LIKE to table filters, closes #672 2023-09-25 18:16:07 +02:00
98c1f43a4d refactor: removed icon fonts in ace editor 2023-09-25 18:14:21 +02:00
12825c69d4 Merge branch 'beta' of https://github.com/antares-sql/antares into develop 2023-09-24 23:06:01 +02:00
198ff0103b fix: nsis updater not working 2023-09-24 23:04:35 +02:00
94ce615fc8 chore(release): 0.7.17-beta.1 2023-09-23 16:00:52 +02:00
354928e302 fix(UI): small icons in sidebar elements with long name 2023-09-21 11:18:00 +02:00
6dceaf09be fix(SQLite): table content not refresh after an update, fixes #665 2023-09-20 17:54:25 +02:00
b321e64b83 fix(SQLite): field length lost when editing a table, fixes #664 2023-09-19 18:12:49 +02:00
7e36260cdb fix: table filter not working when search string on integer field, #671 2023-09-19 18:10:27 +02:00
894087e196 Merge branch 'beta' of https://github.com/antares-sql/antares into develop 2023-09-18 15:13:03 +02:00
922f56f69b fix: flip not working on BaseIcon component 2023-09-18 08:56:26 +02:00
7d84b4e81f chore(release): 0.7.17-beta.0 2023-09-17 23:56:24 +02:00
495e48625c ci: manual creation of arm64 linux artifacts 2023-09-17 23:56:05 +02:00
5934d3a990 ci: update beta build node version 2023-09-17 19:59:13 +02:00
cb92ca99f6 refactor: minor refactor 2023-09-17 19:04:24 +02:00
e7bec0aaaf perf: migration from font icons to svg icons 2023-09-17 18:49:37 +02:00
9de5f67d18 perf: improved ipc validation on Linux 2023-09-13 16:30:08 +02:00
13592425af perf(core): improved app security, fixes #666 2023-09-13 14:21:31 +02:00
0de5ef8a98 fix: empty workspace deleting connections in some conditions 2023-09-11 18:02:19 +02:00
785bc40ad0 build(deps): update some dependencies (vue, pinia, electron) 2023-09-08 15:05:28 +02:00
940f64e6ab refactor: small cleanup 2023-09-08 09:20:13 +02:00
535dd21d69 Merge pull request #662 from 64knl/feat/update-dutch-translation
feat(translation): Update Dutch
2023-09-07 15:50:04 +02:00
Rene
b43c4000d5 feat(translation): Update Dutch 2023-09-07 10:44:38 +02:00
757a2b3cbf fix(SQLite): disconnecting a sqlite connection does not truly close it, fixes #661 2023-09-05 18:08:43 +02:00
c78258219a Merge branch 'master' of https://github.com/antares-sql/antares into develop 2023-09-05 17:45:47 +02:00
fe23d86694 Merge pull request #633 from digitalgopnik/feat/ssh-keep-alive-interval
feat: customize keep-alive-interval for ssh-tunnel
2023-09-04 17:12:39 +02:00
8d605ee287 feat: keep alive interval in seconds 2023-09-04 16:27:50 +02:00
fbe271af37 refactor: adaptation for changes to i18n 2023-09-04 15:27:56 +02:00
b838916937 Merge branch 'develop' of https://github.com/antares-sql/antares into pr/digitalgopnik/633 2023-09-04 14:59:21 +02:00
77ab561058 Merge pull request #660 from antares-sql/dependabot/npm_and_yarn/develop/ace-builds-1.24.1
build(deps): bump ace-builds from 1.14.0 to 1.24.1
2023-09-04 14:05:33 +02:00
dependabot[bot]
7bb03b4922 build(deps): bump ace-builds from 1.14.0 to 1.24.1
Bumps [ace-builds](https://github.com/ajaxorg/ace-builds) from 1.14.0 to 1.24.1.
- [Release notes](https://github.com/ajaxorg/ace-builds/releases)
- [Changelog](https://github.com/ajaxorg/ace-builds/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ajaxorg/ace-builds/compare/v1.14.0...v1.24.1)

---
updated-dependencies:
- dependency-name: ace-builds
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 11:53:17 +00:00
de607a6b06 Merge pull request #659 from antares-sql/dependabot/npm_and_yarn/develop/vueuse/core-10.4.1
build(deps): bump @vueuse/core from 8.7.5 to 10.4.1
2023-09-04 13:52:29 +02:00
c5f89f9fdd Merge pull request #640 from antares-sql/dependabot/npm_and_yarn/develop/mdi/font-7.2.96
build(deps): bump @mdi/font from 7.1.96 to 7.2.96
2023-09-04 13:48:41 +02:00
bf46b89988 Merge pull request #658 from antares-sql/dependabot/npm_and_yarn/develop/sql-formatter-13.0.0
build(deps): bump sql-formatter from 12.2.2 to 13.0.0
2023-09-04 13:38:33 +02:00
e6f45d71c7 fix(UI): update notification indicator moves settings icon 2023-09-02 16:09:19 +02:00
dependabot[bot]
8608c27f20 build(deps): bump @vueuse/core from 8.7.5 to 10.4.1
Bumps [@vueuse/core](https://github.com/vueuse/vueuse/tree/HEAD/packages/core) from 8.7.5 to 10.4.1.
- [Release notes](https://github.com/vueuse/vueuse/releases)
- [Commits](https://github.com/vueuse/vueuse/commits/v10.4.1/packages/core)

---
updated-dependencies:
- dependency-name: "@vueuse/core"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 19:14:14 +00:00
dependabot[bot]
e031c75e28 build(deps): bump sql-formatter from 12.2.2 to 13.0.0
Bumps [sql-formatter](https://github.com/sql-formatter-org/sql-formatter) from 12.2.2 to 13.0.0.
- [Release notes](https://github.com/sql-formatter-org/sql-formatter/releases)
- [Changelog](https://github.com/sql-formatter-org/sql-formatter/blob/master/.release-it.json)
- [Commits](https://github.com/sql-formatter-org/sql-formatter/compare/v12.2.2...v13.0.0)

---
updated-dependencies:
- dependency-name: sql-formatter
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 19:13:36 +00:00
c1891dd5de chore(release): 0.7.16 2023-08-26 15:21:02 +02:00
53fe986bcb Merge branch 'master' of https://github.com/antares-sql/antares into beta 2023-08-26 15:19:45 +02:00
661043b181 Merge branch 'master' of https://github.com/antares-sql/antares into develop 2023-08-26 15:14:10 +02:00
b74ec71b10 chore: mastodon social link 2023-08-18 16:05:04 +02:00
54df0e4aa8 style: implement eslint simple-import-sort 2023-08-18 15:57:31 +02:00
d702ce3fa9 chore(release): 0.7.16-beta.1 2023-08-18 12:22:56 +02:00
63544e95da Merge branch 'feat/export-connections' of https://github.com/antares-sql/antares into develop 2023-08-18 12:12:05 +02:00
6df214558f feat: ability to import connections 2023-08-18 12:11:08 +02:00
f5b86e59e7 feat: ability to export connections 2023-08-17 13:48:55 +02:00
28f14c9195 Merge pull request #653 from antares-sql/all-contributors/add-Lawondyss
docs: add Lawondyss as a contributor for translation
2023-08-14 12:17:38 +02:00
allcontributors[bot]
90922e6f96 docs: update .all-contributorsrc [skip ci] 2023-08-14 10:17:13 +00:00
allcontributors[bot]
4b414df7e4 docs: update README.md [skip ci] 2023-08-14 10:17:12 +00:00
27f0068415 Merge pull request #652 from Lawondyss/develop
Add CZ translation and titles for buttons
2023-08-14 12:16:44 +02:00
Ladislav Vondráček
52e42fa1b5 fix: add some missing titles of buttons 2023-08-14 11:50:38 +02:00
Ladislav Vondráček
5b9b539bc7 chore(i18n): add czech translation 2023-08-14 11:47:41 +02:00
832aa75ebe fix(SQLite): improved view body parsing 2023-08-14 10:44:36 +02:00
aba67f3872 refactor(translation): refactor ca-ES to new format 2023-08-14 09:16:40 +02:00
5a1644f023 Merge branches 'develop' and 'master' of https://github.com/antares-sql/antares into develop 2023-08-14 09:07:55 +02:00
e372712556 Merge pull request #651 from antares-sql/all-contributors/add-markusand
docs: add markusand as a contributor for translation
2023-08-14 09:06:55 +02:00
d4727a7d20 Merge pull request #649 from markusand/master
feat: Add support for catalan language
2023-08-14 09:06:42 +02:00
allcontributors[bot]
f2c2f33afa docs: update .all-contributorsrc [skip ci] 2023-08-14 07:06:40 +00:00
allcontributors[bot]
6dc4bdd0c0 docs: update README.md [skip ci] 2023-08-14 07:06:39 +00:00
Marc Vilella
9c6f1a9ea5 feat: Add catalan language 2023-08-13 19:20:26 +02:00
dd264f802e ci: update snapcraft.yaml 2023-08-11 18:12:38 +02:00
fed0e10702 Merge branch 'master' of https://github.com/antares-sql/antares into beta 2023-08-11 17:34:50 +02:00
e7ce4ef6ed Merge branch 'master' of https://github.com/antares-sql/antares 2023-08-11 17:34:30 +02:00
e03f2eef49 ci: update snapcraft.yaml 2023-08-11 17:34:27 +02:00
3a77f0818d chore(release): 0.7.16-beta.0 2023-08-11 16:50:20 +02:00
6cd2f89bbf refactor: ts improvements 2023-08-11 16:42:34 +02:00
16ec82eb7e Merge branch 'develop' of https://github.com/antares-sql/antares into beta 2023-08-11 16:30:16 +02:00
84b2255bf4 feat: ability to export a table dump from table context menu 2023-08-11 11:49:49 +02:00
2e39d810b5 feat: ability to change sql dump file name 2023-08-11 09:52:25 +02:00
56918d89c7 Merge branch 'master' of https://github.com/antares-sql/antares into develop 2023-08-09 18:45:05 +02:00
083198af8f chore: update README.md 2023-08-09 18:44:31 +02:00
ad7e459c68 feat: support to links in changelog 2023-08-08 18:05:27 +02:00
8c4c93cb07 chore(translation): add translation helper script 2023-08-04 12:28:03 +02:00
Christian Ratz
c0c33f8237 Merge branch 'develop' into feat/ssh-keep-alive-interval 2023-08-04 11:12:48 +02:00
Christian Ratz
b4731d67a5 feat: customize keep-alive-interval for ssh-tunnel 2023-08-04 11:06:35 +02:00
eee85d24b7 ci: update snapcraft.yml 2023-08-03 18:36:27 +02:00
92fe029906 refactor: minor translation improvements 2023-08-03 18:36:09 +02:00
1dd2147b68 refactor(translation): complete refactor of translations structure 2023-08-03 18:28:50 +02:00
5a54e7ac33 Merge branch 'master' of https://github.com/antares-sql/antares into beta 2023-08-02 09:21:24 +02:00
c19bac2373 Merge branch 'master' of https://github.com/antares-sql/antares into develop 2023-08-02 09:20:29 +02:00
7b1cb4ff86 fix(MySQL): missing error details on mysql importer with some exceptione 2023-08-01 10:04:00 +02:00
f120af25f4 build(deps): update mysql2 2023-08-01 10:02:35 +02:00
83b3ca563a chore(release): 0.7.15 2023-07-31 13:04:53 +02:00
0fab3bc43c ci: arrangements for beta channel 2023-07-31 13:04:30 +02:00
dependabot[bot]
de40414a0d build(deps): bump @mdi/font from 7.1.96 to 7.2.96
Bumps [@mdi/font](https://github.com/Templarian/MaterialDesign-Webfont) from 7.1.96 to 7.2.96.
- [Commits](https://github.com/Templarian/MaterialDesign-Webfont/compare/v7.1.96...v7.2.96)

---
updated-dependencies:
- dependency-name: "@mdi/font"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-31 08:55:49 +00:00
473c4636cf ci: arrangements for beta channel 2023-07-31 10:55:05 +02:00
2e11a0c032 chore: update dependabot branch target 2023-07-26 17:57:14 +02:00
193042b92d chore: update dependabot branch target 2023-07-26 17:42:16 +02:00
51b14195a8 fix(MySQL): error insertinf new fields with some MySQL configurations, fixes #360 2023-07-24 09:09:11 +02:00
f831fcd442 fix: display content of BLOB fields if not binary, fixes #628 2023-07-21 18:17:31 +02:00
3104847b92 Merge pull request #630 from SmileYzn/master
Update pt-BR.ts 🇧🇷
2023-07-21 08:44:11 +02:00
Cleverson
bc0b029369 Update pt-BR.ts 2023-07-20 16:55:23 -03:00
efee7f3a0e Merge branch 'master' of https://github.com/antares-sql/antares 2023-07-17 18:00:43 +02:00
7c820b1827 fix(MySQL): unable to set more than one value in SET fields 2023-07-17 18:00:40 +02:00
38ec703705 Merge pull request #625 from antares-sql/all-contributors/add-zxp19821005
docs: add zxp19821005 as a contributor for platform
2023-07-17 09:34:48 +02:00
allcontributors[bot]
2afb66a2e6 docs: update .all-contributorsrc [skip ci] 2023-07-17 07:34:13 +00:00
allcontributors[bot]
5a5af3af5e docs: update README.md [skip ci] 2023-07-17 07:34:12 +00:00
8f0e5407ae Merge branch 'master' of https://github.com/antares-sql/antares 2023-07-16 11:33:30 +02:00
8bed7c2f34 chore: update README.md AUR link 2023-07-16 11:33:28 +02:00
f4a2f43ea4 Merge pull request #621 from brdtheo/i18n-french-translation
chore(i18n): update french translation
2023-07-16 11:16:41 +02:00
Théo Billardey
6063b3f697 chore(i18n): update french translation 2023-07-15 21:57:18 +02:00
2f5fa0f2e4 feat: export file name with hour, minutes and seconds, closes #610 2023-07-12 15:20:44 +02:00
703a515462 chore(release): 0.7.14 2023-07-07 15:22:53 +02:00
9d8e9a5e1f perf(PostgreSQL): minor improvement to schema selection 2023-07-07 15:22:16 +02:00
1c73503138 fix: unable to insert new rows 2023-07-07 15:21:48 +02:00
32bbc45329 feat: button to open view settings tab 2023-07-07 09:04:40 +02:00
9d90dc362e chore(release): 0.7.13 2023-07-06 22:02:55 +02:00
e808b86c52 fix(PostgreSQL): unable to connect to database, fixes #614 2023-07-06 22:01:41 +02:00
6e01f0f2e7 fix: unable to copy as sql inserts with BIT fileds, fixes #613 2023-07-06 12:06:32 +02:00
38bfea279c feat: button to open table settings tab, closes #608 2023-07-05 18:27:30 +02:00
0044522390 Merge pull request #611 from 64knl/feat/update-connection-icons
feat: update connection icons
2023-07-05 17:42:49 +02:00
Rene
462ede8dc7 feat: update connection
icons to better match other icons
2023-07-05 15:50:17 +02:00
60dd4df5ec chore(release): 0.7.12 2023-07-03 09:04:25 +02:00
fa006798cf Merge pull request #602 from antares-sql/all-contributors/add-64knl
docs: add 64knl as a contributor for translation
2023-06-30 08:07:37 +02:00
c5abc3d6b2 Merge pull request #599 from 64knl/feat/locale-dutch
feat: Add Dutch translation
2023-06-30 08:07:15 +02:00
allcontributors[bot]
a8dc30c9dd docs: update .all-contributorsrc [skip ci] 2023-06-30 06:07:02 +00:00
allcontributors[bot]
2cfed3e79b docs: update README.md [skip ci] 2023-06-30 06:07:01 +00:00
Rene
001983c5a2 fix: update source string to fix spelling 2023-06-24 17:13:12 +02:00
470f7455c0 Merge pull request #598 from antares-sql/all-contributors/add-64knl
docs: add 64knl as a contributor for code
2023-06-24 13:18:21 +02:00
allcontributors[bot]
70e00a7ee6 docs: update .all-contributorsrc [skip ci] 2023-06-24 11:18:08 +00:00
allcontributors[bot]
b76247e304 docs: update README.md [skip ci] 2023-06-24 11:18:07 +00:00
f58c30ff17 Merge pull request #597 from 64knl/feat/sort-available-languages
feat: Sort available languages
2023-06-24 13:16:46 +02:00
5bdbebfbc3 Merge pull request #596 from 64knl/fix/spelling-appearance
fix: spelling corrections
2023-06-24 13:16:27 +02:00
Rene
03c4a1c797 wip: more translations 2023-06-22 19:06:02 +02:00
Rene
e18604b3ce wip: translation 2023-06-22 18:59:23 +02:00
Rene
3ff8d2571b feat: Sort available languages alphabetically 2023-06-22 18:27:41 +02:00
Rene
f22f8d2317 wip: translation 2023-06-22 18:22:44 +02:00
Rene
8a4a099e37 fix: rename components and variables in SettingBarContext 2023-06-22 18:18:13 +02:00
Rene
702ffb81ef style: formatting 2023-06-22 17:40:23 +02:00
Rene
93e16fdda2 fix: spelling corrections
- Updated appearence -> appearance across files
- Fixed some English spelling mistakes
2023-06-22 17:36:53 +02:00
Rene
575c8ea8ca feat: more translations 2023-06-22 15:06:53 +02:00
Rene
4ff1d107b8 feat: add Dutch language support 2023-06-22 14:43:15 +02:00
3ad1e51f42 feat: format options of csv export, closes #196 2023-06-14 19:47:09 +02:00
e07e7b736e fix(PostgreSQL): unable to export as sql inserts 2023-06-14 09:38:54 +02:00
89815bf5e7 feat(PostgreSQL): ability to switch the database, closes #432 2023-06-13 18:10:52 +02:00
9d00f58998 chore: update README.md 2023-06-12 21:44:06 +02:00
f5d001846a Merge pull request #554 from antares-sql/dependabot/npm_and_yarn/sql-formatter-12.2.0
build(deps): bump sql-formatter from 12.0.3 to 12.2.0
2023-06-12 15:07:19 +02:00
0a6907b549 Merge branch 'master' into dependabot/npm_and_yarn/sql-formatter-12.2.0 2023-06-12 15:01:48 +02:00
322f92b734 Merge pull request #591 from m1khal3v/patch-3
Update ru-RU.ts
2023-06-07 03:57:34 +02:00
Anton Mikhalev
038e4494f5 Update ru-RU.ts 2023-06-06 23:41:22 +03:00
56b71ec0d1 chore(release): 0.7.11 2023-06-04 10:43:42 +02:00
787014c38d feat: context menu to close tabs, closes #392 2023-06-03 19:13:20 +02:00
e60726c741 fix: disable filter during table content loading, fixes #588 2023-06-01 18:00:16 +02:00
904670781d fix(MySQL): unable to get users list with some db settings 2023-06-01 11:47:31 +02:00
22bdaac18b fix: weird behavior in some text editors 2023-06-01 11:42:19 +02:00
446199827b fix: unique keys not recognized in table settings on some MariaDB versions 2023-05-30 18:33:37 +02:00
53a71d55c5 chore(release): 0.7.10 2023-05-28 13:32:38 +02:00
03638c0553 feat: copy rows as PHP array 2023-05-28 13:31:44 +02:00
8968179c11 feat: export table content or query results as PHP array, closes #575 2023-05-28 13:20:28 +02:00
2c0b4ffe1f fix: disable shorctut to show Ace editor settings, fixes #585 2023-05-26 18:17:23 +02:00
f454b4bb1c feat: DDL query in table settings for MySQL and PostgreSQL, closes #581 2023-05-25 18:51:56 +02:00
56698725cb Merge pull request #583 from m1khal3v/patch-2
Update ru-RU.ts
2023-05-21 00:40:16 +02:00
Anton Mikhalev
1896013267 Update ru-RU.ts 2023-05-19 14:14:35 +03:00
17eeb6d38e feat: keepalive on mysql/postgre connections, should fix #577 2023-05-14 18:48:21 +02:00
5e83b4466d Merge pull request #574 from antares-sql/all-contributors/add-m1khal3v
docs: add m1khal3v as a contributor for translation
2023-05-05 09:13:09 +02:00
allcontributors[bot]
45d1934f96 docs: update .all-contributorsrc [skip ci] 2023-05-05 07:12:57 +00:00
allcontributors[bot]
7821e25bdb docs: update README.md [skip ci] 2023-05-05 07:12:56 +00:00
ae8d558989 Merge pull request #572 from m1khal3v/patch-1
Update ru-RU.ts
2023-05-05 09:12:12 +02:00
Anton Mikhalev
b348c83501 Update ru-RU.ts 2023-05-04 16:11:10 +03:00
Anton Mikhalev
f58a12ebd5 Update ru-RU.ts 2023-05-04 16:01:17 +03:00
Anton Mikhalev
b806deeed0 Update ru-RU.ts 2023-05-04 14:36:47 +03:00
Anton Mikhalev
4e1be838bd Update ru-RU.ts 2023-05-04 14:19:38 +03:00
Anton Mikhalev
bb7ec76ced Update ru-RU.ts 2023-05-04 14:05:12 +03:00
Anton Mikhalev
e2b843cd18 Update ru-RU.ts 2023-05-04 14:01:52 +03:00
8c9713e805 ci: action to create linux arm64 artifacts 2023-05-02 08:57:14 +02:00
786de6a7ba ci: disable arm64 linux target 2023-05-01 13:41:01 +02:00
1bf54a69fd ci: disable arm deb target 2023-05-01 13:11:41 +02:00
3ddfd6bb44 chore(release): 0.7.9 2023-05-01 10:45:41 +02:00
c48266c336 feat: option to choose the target table of an SQL INSERT exportation, closes #556 2023-04-28 18:46:24 +02:00
96e1ceb1d2 perf(translation): update italian translation 2023-04-27 18:12:19 +02:00
19859f45f4 feat: no table results message 2023-04-27 18:11:36 +02:00
74c136f833 fix: unable to delete rows with null values and no primary key 2023-04-27 14:14:04 +02:00
af91d96db6 fix: sidebar height out of visible area 2023-04-26 18:52:32 +02:00
0cd55fbfe9 fix: vertical scrollbar does not reset after performing a search, fixes #567 2023-04-21 00:47:31 +02:00
55aee163b6 Merge pull request #562 from antares-sql/all-contributors/add-555cider
docs: add 555cider as a contributor for translation
2023-04-17 09:22:30 +02:00
allcontributors[bot]
eb172022fa docs: update .all-contributorsrc [skip ci] 2023-04-17 07:22:12 +00:00
allcontributors[bot]
0d5cac27ed docs: update README.md [skip ci] 2023-04-17 07:22:11 +00:00
baef4ea4d1 feat(translation): ko-KR translation, closes #561 2023-04-17 09:21:01 +02:00
6b3b22a01a chore(release): 0.7.8 2023-04-12 08:57:17 +02:00
ebf7780c3c refactor: fix ts error 2023-04-08 13:12:29 +02:00
0f24c80e5a feat(MySQL): option to export from results SQL INSERTS in chunks, closes #501 2023-04-08 13:03:46 +02:00
afa61a9bc2 fix: unable to export BLOB values from table content o query result 2023-04-08 09:39:28 +02:00
8be9f932e7 feat: filter schemas in sidebar, closes #555 2023-04-07 18:06:41 +02:00
d802b32597 fix: triggers not exported if related table not included 2023-04-04 11:55:39 +02:00
dependabot[bot]
12f3e03b45 build(deps): bump sql-formatter from 12.0.3 to 12.2.0
Bumps [sql-formatter](https://github.com/sql-formatter-org/sql-formatter) from 12.0.3 to 12.2.0.
- [Release notes](https://github.com/sql-formatter-org/sql-formatter/releases)
- [Changelog](https://github.com/sql-formatter-org/sql-formatter/blob/master/.release-it.json)
- [Commits](https://github.com/sql-formatter-org/sql-formatter/compare/v12.0.3...v12.2.0)

---
updated-dependencies:
- dependency-name: sql-formatter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-01 20:01:44 +00:00
28f0419af4 refactor: remove viewMenu on macOS 2023-03-30 18:07:24 +02:00
52108d7613 fix(MySQL): missing scale for FLOAT type 2023-03-28 17:27:47 +02:00
df6625af49 chore(release): 0.7.7 2023-03-10 18:12:26 +01:00
59846e6ff4 fix(MySQL): missing table information in table setting tab 2023-03-09 09:07:57 +01:00
63fece2a1b fix(Linux): remove app menu shown pressing ALT key 2023-03-06 18:29:53 +01:00
9ef475ec3f chore: package.json changes 2023-03-06 09:38:51 +01:00
3546c57e39 fix: unable to set string fields default values starting with 0 2023-03-02 18:09:16 +01:00
8730be02af ci: minor change 2023-03-02 09:49:59 +01:00
b925ff9c01 fix(Linux): remove app menu shown pressing ALT key 2023-03-02 09:07:10 +01:00
2c46269cf2 fix: hide table size tooltip if disabled 2023-03-02 09:06:28 +01:00
23d8467154 chore(release): 0.7.6 2023-02-27 10:44:53 +01:00
d1297a0085 fix: error with import/export tools, fixes #541 2023-02-27 10:43:51 +01:00
6bd8667f43 Merge pull request #540 from jimcat8/cn_main
Supplement the key-value pair and translate its value.
2023-02-27 10:07:46 +01:00
tianci li
c9093a36b3 Word error 2023-02-27 12:14:20 +08:00
tianci li
b6dbfe1564 Supplement the key-value pair and translate its value. 2023-02-27 11:59:29 +08:00
06b0090480 chore(release): 0.7.5 2023-02-26 17:29:31 +01:00
629ce63329 fix: single quotes not properly escaped for random generated content 2023-02-26 17:02:41 +01:00
313e7407eb feat(MySQL): option, disabled by default, to enable table size indicators on sidebar 2023-02-23 08:51:33 +01:00
4458177688 fix(MariaDB): exception with event_scheduler DISABLED with MariaDB 10, fixes #535 2023-02-21 18:07:29 +01:00
ea7865a086 Merge pull request #533 from antares-sql/all-contributors/add-jimcat8
docs: add jimcat8 as a contributor for translation
2023-02-19 10:43:34 +01:00
allcontributors[bot]
ca900f3dcf docs: update .all-contributorsrc [skip ci] 2023-02-19 09:43:23 +00:00
allcontributors[bot]
4f6f28c6e6 docs: update README.md [skip ci] 2023-02-19 09:43:22 +00:00
8caac0f21d Merge pull request #532 from jimcat8/cn_main
Updated zh-CN translation text
2023-02-19 10:43:15 +01:00
tianci li
cacfc1c2eb review 2023-02-19 14:21:42 +08:00
tianci li
2f30c0d42f Updated zh-CN translation text 2023-02-19 14:07:49 +08:00
b1fbc43ab2 fix: unable to import after a failed import, fixes #515 2023-02-13 18:06:55 +01:00
fe9817bf31 chore(release): 0.7.4 2023-02-10 09:26:50 +01:00
ddb7ead083 fix: tables sort in sidebar 2023-02-10 09:26:17 +01:00
9d8c21244b chore(release): 0.7.3 2023-02-09 11:50:16 +01:00
d934ae1e6c fix(SQLite): triggers disappear after editing related table, fixes #523 2023-02-04 13:51:02 +01:00
68f8d48064 chore: minor ts changes 2023-02-04 12:10:09 +01:00
e7e491340a feat(SQLite): added support to INTEGER UNSIGNED 2023-02-04 11:38:30 +01:00
e8447e5655 fix: select of table type stuck when editing an unknown type 2023-02-04 11:34:53 +01:00
6decba316c fix: longtext edit modal opens when it shouldn't, fixes #524 2023-02-04 09:36:29 +01:00
2b5e1e7b39 fix(SQLite): error with integer timestamp fields 2023-02-04 09:07:41 +01:00
a124f04661 Merge pull request #529 from antares-sql/dependabot/npm_and_yarn/mdi/font-7.1.96
build(deps): bump @mdi/font from 7.0.96 to 7.1.96
2023-02-02 16:45:38 +01:00
dependabot[bot]
3ee4ab4d84 build(deps): bump @mdi/font from 7.0.96 to 7.1.96
Bumps [@mdi/font](https://github.com/Templarian/MaterialDesign-Webfont) from 7.0.96 to 7.1.96.
- [Release notes](https://github.com/Templarian/MaterialDesign-Webfont/releases)
- [Commits](https://github.com/Templarian/MaterialDesign-Webfont/compare/v7.0.96...v7.1.96)

---
updated-dependencies:
- dependency-name: "@mdi/font"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 19:05:41 +00:00
174aa3c508 chore(release): 0.7.2 2023-01-22 17:16:04 +01:00
729edd40a6 build: update electron 2023-01-22 15:07:47 +01:00
c7ab3b77a2 fix: allow comments in queies, fixes #519 2023-01-19 14:32:37 +01:00
5624b3b2d7 Merge pull request #520 from dyaskur/master
add copy shortcut and default copy type setting
2023-01-16 18:16:13 +01:00
4c16d8c61f refactor: results table setting section 2023-01-16 18:15:49 +01:00
Dyas🍌 Yaskur🍎
9aca89477f feat: add copy shortcut and default copy type setting 2023-01-16 04:49:44 +07:00
0e80e823d0 fix(SQLite): exception saving tables without INT fields length 2023-01-09 10:02:28 +01:00
ff4bc6c39b feat: connection info icons in footer 2023-01-05 17:21:22 +01:00
b4e1e9ac26 Merge branch 'master' of https://github.com/antares-sql/antares 2023-01-02 09:21:03 +01:00
f177c7f1f1 style: minor refactor 2023-01-02 09:21:01 +01:00
6a67c27915 Merge pull request #406 from antares-sql/dependabot/npm_and_yarn/electron-store-8.1.0
build(deps): bump electron-store from 8.0.2 to 8.1.0
2023-01-02 09:19:15 +01:00
374cedba2b Merge pull request #510 from antares-sql/dependabot/npm_and_yarn/pinia-2.0.28
build(deps): bump pinia from 2.0.27 to 2.0.28
2023-01-02 09:18:55 +01:00
dependabot[bot]
de8097c297 build(deps): bump pinia from 2.0.27 to 2.0.28
Bumps [pinia](https://github.com/vuejs/pinia) from 2.0.27 to 2.0.28.
- [Release notes](https://github.com/vuejs/pinia/releases)
- [Commits](https://github.com/vuejs/pinia/compare/pinia@2.0.27...pinia@2.0.28)

---
updated-dependencies:
- dependency-name: pinia
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-01 19:02:46 +00:00
6fa430adf6 fix: ssh connection closed after idle time, fixes #425 2022-12-29 13:04:20 +01:00
0e7b93c2df chore(release): 0.7.1 2022-12-23 09:25:50 +01:00
843c15e428 fix(MySQL): not every connection gets read-only option 2022-12-23 09:24:05 +01:00
2982b6cb96 ci: change macos build target to macos-11 2022-12-22 22:22:17 +01:00
c08946e932 fix: context submenu outside view when near the edge, fixes #506 2022-12-22 11:27:13 +01:00
55c1604e7f refactor(UI): hide selected connection bar when folder preview 2022-12-21 13:16:56 +01:00
d64fbbad0f Merge pull request #505 from antares-sql/all-contributors/add-dyaskur
docs: add dyaskur as a contributor for code
2022-12-20 21:30:13 +01:00
allcontributors[bot]
c88d734bc0 docs: update .all-contributorsrc [skip ci] 2022-12-20 20:29:48 +00:00
allcontributors[bot]
99d94ea92c docs: update README.md [skip ci] 2022-12-20 20:29:47 +00:00
e4f620c5a1 Merge pull request #500 from dyaskur/add_copy_as_table_rows
feat: Copy rows as html table, so we can paste it to spreadsheet
2022-12-20 21:28:54 +01:00
99f9a9e188 refactor: replace string "Table" with localization 2022-12-20 21:26:33 +01:00
Dyas🍌 Yaskur🍎
2236c8fe75 set copy plain text delimiter to tab 2022-12-19 19:07:31 +07:00
b9a097e2f5 Merge pull request #502 from antares-sql/all-contributors/add-dyaskur
docs: add dyaskur as a contributor for translation
2022-12-19 09:00:17 +01:00
allcontributors[bot]
966446afd6 docs: update .all-contributorsrc [skip ci] 2022-12-19 07:59:59 +00:00
allcontributors[bot]
b681adc632 docs: update README.md [skip ci] 2022-12-19 07:59:58 +00:00
15d0158993 Merge pull request #498 from dyaskur/indonesian-language-translation
Add new language: Bahasa Indonesia
2022-12-19 08:58:25 +01:00
e76d324810 chore: minor change in e2e tests 2022-12-19 08:54:20 +01:00
Dyas🍌 Yaskur🍎
897795ddbb fix: bahasa indonesia typos 2022-12-19 07:34:50 +07:00
Dyas🍌 Yaskur🍎
c32f463ea5 feat: Copy rows as html table, so we can paste it to spreadsheet 2022-12-19 05:33:50 +07:00
Dyas🍌 Yaskur🍎
25e1ba4384 Add new language: Bahasa Indonesia 2022-12-19 04:36:10 +07:00
dependabot[bot]
a71ae05c6f build(deps): bump electron-store from 8.0.2 to 8.1.0
Bumps [electron-store](https://github.com/sindresorhus/electron-store) from 8.0.2 to 8.1.0.
- [Release notes](https://github.com/sindresorhus/electron-store/releases)
- [Commits](https://github.com/sindresorhus/electron-store/compare/v8.0.2...v8.1.0)

---
updated-dependencies:
- dependency-name: electron-store
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-18 15:01:12 +00:00
1bd26ceaa6 feat: option to disable selected query execution, closes #477 2022-12-18 15:59:58 +01:00
56a0361ed2 Merge pull request #493 from antares-sql/all-contributors/add-brdtheo
docs: add brdtheo as a contributor for translation
2022-12-12 09:14:39 +01:00
allcontributors[bot]
c0dd3e0941 docs: update .all-contributorsrc [skip ci] 2022-12-12 08:14:23 +00:00
allcontributors[bot]
33ab5d7491 docs: update README.md [skip ci] 2022-12-12 08:14:22 +00:00
72e6a23fd6 Merge pull request #491 from brdtheo/i18n-fix-french-translation
Fix french translation
2022-12-12 09:11:08 +01:00
brdtheo
fd129a2ad1 fix(i18n): add missing keys for french translation 2022-12-07 22:45:44 +01:00
2c63cbc4e8 chore: update dependencies 2022-12-06 12:56:36 +01:00
c9a33936a0 ci: test target os change 2022-12-03 17:53:16 +01:00
a6bdf69a28 fix: connection default icon not change after client change 2022-12-03 17:53:00 +01:00
dd971d70e0 fix(UI): white background dragging connections inside folder on Linux 2022-12-02 09:38:40 +01:00
669d7e8d4d fix: white background dragging connections or tabs on Linux, fixes #486 2022-12-01 15:38:19 +01:00
02f204a01d Merge pull request #485 from SmileYzn/patch-1
Update pt-BR.ts
2022-11-30 17:50:00 +01:00
Cleverson
023d7aa92d Update pt-BR.ts 2022-11-30 13:45:23 -03:00
4ca40c07d6 ci: ubuntu 20.04 as linux actions target 2022-11-30 15:57:48 +01:00
cf5247bf35 chore(release): 0.7.0 2022-11-30 13:22:26 +01:00
19db29663b refactor(UI): minor change 2022-11-30 13:09:07 +01:00
d010d5aa8f fix(UI): wrong copnnection icons color with light theme 2022-11-30 09:15:15 +01:00
0a1f50a9b9 fix: missing sidebar data after update 2022-11-29 18:18:56 +01:00
e7da5a7040 build(deps): update better-sqlite3 to 8.0.0 2022-11-29 15:19:23 +01:00
2d126d521c refactor: minor improvements 2022-11-29 14:25:30 +01:00
0fca70ebec fix(UI): folder to folder drag glitches 2022-11-29 13:19:41 +01:00
36358584fd Merge pull request #481 from antares-sql/new-sidebar
New connections sidebar
2022-11-28 15:19:24 +01:00
672896414e feat(UI): new settimgbar tooltips 2022-11-28 15:11:29 +01:00
b06bafe06c fix: deletion of connections inside folder 2022-11-28 13:06:01 +01:00
4fe9dfc4d7 feat(UI): footer color based on folder color 2022-11-28 11:56:02 +01:00
7af178a1e4 fix: wrong position moving elements outside folder 2022-11-28 09:42:18 +01:00
212b2bdba9 feat(UI): connections customization 2022-11-27 17:52:32 +01:00
72accb7b0e feat(UI): folders customization 2022-11-26 11:21:47 +01:00
321b387083 refactor(UI): various improvements on sidebar 2022-11-24 16:40:04 +01:00
ece6c6401d feat(UI): folders implementation 2022-11-23 17:52:08 +01:00
5a028a4ea2 refactor: changes to implement folders 2022-11-21 20:19:02 +01:00
83f9b12be0 chore(release): 0.6.0 2022-11-18 14:32:43 +01:00
1c1403f586 fix: incomplete list of collations, fixes #478 2022-11-18 11:30:10 +01:00
038cf68253 Merge pull request #472 from antares-sql/firebirdsql-support
Firebird SQL support
2022-11-17 16:19:59 +01:00
3580faebba chore: update README.md 2022-11-17 16:17:36 +01:00
ae312efbbc feat(Firebird SQL): procedure add/edit/delete support 2022-11-17 15:27:39 +01:00
8e422e3f07 feat(Firebird SQL): trigger add/edit/delete support 2022-11-16 15:16:12 +01:00
7d1967a609 feat(Firebird SQL): view add/edit/delete support 2022-11-16 12:00:12 +01:00
7ff8e2149e fix(Firebird SQL): connection pool issue 2022-11-16 10:12:44 +01:00
1b5cc315dd feat(Firebird SQL): table add/edit/delete support 2022-11-15 16:46:12 +01:00
27566c1dfa feat(Firebird SQL): manual commit mode 2022-11-10 15:52:31 +01:00
03777a2ea3 refactor(Firebird SQL): improve fields metadata detection 2022-11-09 17:41:31 +01:00
d91251d7cb build(deps): update better-sqlite to 7.6.2 2022-11-09 10:48:01 +01:00
0827a04d61 feat(Firebird SQL): support to blob fields 2022-11-08 15:53:21 +01:00
2c8509ff41 feat(Firebird SQL): support to indexes and foreign keys 2022-11-08 14:05:54 +01:00
76df6319c2 feat(Firebird SQL): connections pool 2022-11-07 09:49:36 +01:00
e6f6a022d1 feat: support to text blob fields 2022-11-05 10:22:12 +01:00
95bb41e9db feat(Firebird SQL): display table content and query results 2022-11-04 16:31:10 +01:00
7ab84bde57 initial firebird commit 2022-11-02 14:18:50 +01:00
d190a2dd61 fix: loss of precision updating BIGINT values, fixes #467 2022-10-26 12:26:09 +02:00
d8a298fd20 chore(release): 0.5.19 2022-10-22 14:54:15 +02:00
369622d5af Merge pull request #464 from antares-sql/context-cell-filler
Context menu option to fill table cells
2022-10-20 11:49:43 +02:00
a40d722d7c refactor: remove unnecessary console.log 2022-10-20 11:37:23 +02:00
440f74dfc1 fix: app stuck inserting a random value if field length high 2022-10-20 11:25:23 +02:00
8621ca5333 fix: unable to edit text fields if value is NULL, fixes #466 2022-10-20 10:55:30 +02:00
24edc82b1b feat: uuid fill for string cells 2022-10-19 10:40:56 +02:00
0a2124f2c2 feat: context menu option to fill cell with random values 2022-10-19 01:12:07 +02:00
a8521317a5 Merge branch 'master' of https://github.com/antares-sql/antares into context-cell-filler 2022-10-18 08:50:39 +02:00
88408da745 fix: error joining tables with different schema 2022-10-17 13:55:48 +02:00
d52b7af297 fix(SQLite): save boolean as integer to improve compativility, fixes #463 2022-10-17 12:06:22 +02:00
e4a4696dd3 chore(release): 0.5.18 2022-10-14 15:03:49 +02:00
f0255c0065 Merge pull request #455 from antares-sql/dependabot/npm_and_yarn/sql-formatter-11.0.2
build(deps): bump sql-formatter from 8.2.0 to 11.0.2
2022-10-11 10:36:00 +02:00
9991173685 Merge branch 'master' of https://github.com/antares-sql/antares into dependabot/npm_and_yarn/sql-formatter-11.0.2 2022-10-11 10:29:55 +02:00
dependabot[bot]
874dc6298b build(deps): bump sql-formatter from 8.2.0 to 11.0.2
Bumps [sql-formatter](https://github.com/sql-formatter-org/sql-formatter) from 8.2.0 to 11.0.2.
- [Release notes](https://github.com/sql-formatter-org/sql-formatter/releases)
- [Changelog](https://github.com/sql-formatter-org/sql-formatter/blob/master/.release-it.json)
- [Commits](https://github.com/sql-formatter-org/sql-formatter/compare/v8.2.0...v11.0.2)

---
updated-dependencies:
- dependency-name: sql-formatter
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-11 08:12:16 +00:00
5b1b8cf4cc build: update dependencies 2022-10-11 10:11:11 +02:00
a521274d01 feat(PostgreSQL): UUID random generation option on UUID fields, closes #424 2022-10-10 18:08:28 +02:00
86e4c1d58f Merge branch 'master' of https://github.com/antares-sql/antares 2022-10-04 10:12:19 +02:00
ba5a1b68ab fix: trackpad horizontal scroll on tabs not working properly 2022-10-04 10:12:16 +02:00
2c45bce1ee Merge pull request #448 from SmileYzn/master
Update pt-BR.ts
2022-10-01 22:22:34 +02:00
Cleverson
2e05fa4bdc Update pt-BR.ts 2022-09-30 14:43:06 -03:00
dd9c089d27 fix: auto-scroll on sidebar not working, fixes #447 2022-09-29 09:27:29 +02:00
e6955550fa refactor: minor changes in table content context 2022-09-29 09:17:47 +02:00
fe39c1d388 chore(release): 0.5.17 2022-09-22 09:34:28 +02:00
d114f8a651 feat: added more editor font sizes, closes #440 2022-09-21 10:33:44 +02:00
84168d1d75 fix: editor font size doesn't change on new tabs, fixes #442 2022-09-15 19:03:18 +02:00
498a9b48e2 fix: empty definer when editing a view, fixes #437 2022-09-15 18:58:19 +02:00
01f607cd40 fix: "run or reload" shortcut triggers on all connections open 2022-09-08 12:01:57 +02:00
efe134a059 fix: cant run procedures with parameters from leftbar 2022-09-07 18:18:15 +02:00
40cb4dd98d chore: minor changes on macos artifacts action 2022-08-27 09:27:07 +02:00
a142d3c4d7 fix(MacOS): empty options on macos menubar 2022-08-27 09:04:11 +02:00
89da957a49 ci: github action for macos artifacts 2022-08-27 09:02:09 +02:00
05c2f9836c chore(release): 0.5.16 2022-08-26 18:49:51 +02:00
ebc325ae0c fix: issue updating datetime cells with null value, closes #423 2022-08-26 18:48:26 +02:00
39326eb52e fix: unable to set null or delete rows without primary key 2022-08-26 18:31:47 +02:00
df681147aa fix: ts exceptions 2022-08-24 10:23:03 +02:00
ffc645ba5e fix: CTRL+Right/Left not working on text editor, closes #427 2022-08-24 10:04:25 +02:00
1fb1205319 chore: update README.md 2022-08-20 09:18:46 +02:00
c90ab0e880 fix(UI): wrong position of fields resizable area 2022-08-19 16:54:56 +02:00
9dc700e13e fix(UI): editor themes group not visible in select element 2022-08-18 16:10:29 +02:00
6950d0ce5a chore(release): 0.5.15 2022-08-17 16:21:37 +02:00
4df14c3693 feat: dynamic shortcut suggestions on empty query tabs 2022-08-17 16:20:36 +02:00
c05be8304f perf(translation): updated italian translation 2022-08-17 15:29:12 +02:00
31c575dad9 Merge pull request #405 from antares-sql/custom-shortcuts
Shortcuts customization
2022-08-17 11:12:49 +02:00
040657d5ca Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-17 11:05:09 +02:00
5043fafa93 feat: added more events in shortcuts setting 2022-08-17 10:00:23 +02:00
8eb127e458 feat: ability to edit shortcuts 2022-08-16 18:03:38 +02:00
d044a02cb7 feat: ability to add new shortcuts 2022-08-16 13:10:20 +02:00
8cb2c197c8 chore: suppress some stylelint warns 2022-08-15 18:14:51 +02:00
c50d17e82b fix: startup exception 2022-08-15 18:13:53 +02:00
Cleverson
7c186d2dee Update pt-BR.ts 2022-08-12 14:59:22 +02:00
0f219cf9b7 perf: improved keypress detector 2022-08-12 12:40:35 +02:00
75c5a34095 Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-11 11:22:25 +02:00
48877534d1 feat(UI): connection name on left bar, closes #382 #414 2022-08-11 11:14:43 +02:00
c22413fde9 feat: delete shortcuts and restore defaults 2022-08-10 17:59:59 +02:00
77ab8d8a03 build: minor change in ts config 2022-08-09 17:28:33 +02:00
4386c6ab95 chore(release): 0.5.14 2022-08-09 16:21:55 +02:00
19205e0736 style: general lint fix 2022-08-09 16:18:21 +02:00
4fc4ddd1d6 Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-09 16:10:26 +02:00
49b63bc6f2 feat(UI): shortcuts setting UI improved 2022-08-09 16:10:08 +02:00
44eb507a12 fix: unable to open settingbar context menu 2022-08-09 16:04:27 +02:00
1590ffaff0 build: icons for linux builds 2022-08-09 10:48:53 +02:00
44bb75bc60 feat: list of available shortcuts in settings window 2022-08-08 16:44:40 +02:00
8bb5bb93cf Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-08 11:46:08 +02:00
da25823868 Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-05 17:08:48 +02:00
e29d86b409 refactor: shortcuts registration via ShortcutRegister class 2022-08-05 12:07:19 +02:00
242 changed files with 23643 additions and 13317 deletions

View File

@@ -174,8 +174,92 @@
"contributions": [
"translation"
]
},
{
"login": "brdtheo",
"name": "Théo Billardey",
"avatar_url": "https://avatars.githubusercontent.com/u/48206778?v=4",
"profile": "https://codepen.io/theo-billardey",
"contributions": [
"translation"
]
},
{
"login": "dyaskur",
"name": "Muhammad Dyas Yaskur",
"avatar_url": "https://avatars.githubusercontent.com/u/9539970?v=4",
"profile": "http://yaskur.net",
"contributions": [
"translation",
"code"
]
},
{
"login": "jimcat8",
"name": "tianci li",
"avatar_url": "https://avatars.githubusercontent.com/u/86754294?v=4",
"profile": "https://github.com/jimcat8",
"contributions": [
"translation"
]
},
{
"login": "555cider",
"name": "555cider",
"avatar_url": "https://avatars.githubusercontent.com/u/73565447?v=4",
"profile": "https://github.com/555cider",
"contributions": [
"translation"
]
},
{
"login": "m1khal3v",
"name": "Anton Mikhalev",
"avatar_url": "https://avatars.githubusercontent.com/u/41085561?v=4",
"profile": "https://github.com/m1khal3v",
"contributions": [
"translation"
]
},
{
"login": "64knl",
"name": "René",
"avatar_url": "https://avatars.githubusercontent.com/u/3864423?v=4",
"profile": "https://64k.nl/",
"contributions": [
"code",
"translation"
]
},
{
"login": "zxp19821005",
"name": "Woodenman",
"avatar_url": "https://avatars.githubusercontent.com/u/4915850?v=4",
"profile": "https://github.com/zxp19821005",
"contributions": [
"platform"
]
},
{
"login": "markusand",
"name": "Marc Vilella",
"avatar_url": "https://avatars.githubusercontent.com/u/12972543?v=4",
"profile": "https://github.com/markusand",
"contributions": [
"translation"
]
},
{
"login": "Lawondyss",
"name": "Ladislav Vondráček",
"avatar_url": "https://avatars.githubusercontent.com/u/272130?v=4",
"profile": "https://github.com/Lawondyss",
"contributions": [
"translation"
]
}
],
"contributorsPerLine": 7,
"skipCi": true
"skipCi": true,
"commitType": "docs"
}

View File

@@ -18,7 +18,8 @@
},
"plugins": [
"vue",
"@typescript-eslint"
"@typescript-eslint",
"simple-import-sort"
],
"rules": {
"space-infix-ops": "off",
@@ -91,6 +92,8 @@
}
}
],
"@typescript-eslint/no-var-requires": "off"
"@typescript-eslint/no-var-requires": "off",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
}
}

View File

@@ -11,3 +11,4 @@ updates:
directory: "/"
schedule:
interval: "monthly"
target-branch: "develop"

42
.github/workflows/build-beta.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Build & release [BETA]
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+'
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-11, ubuntu-latest, windows-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v3
with:
ref: beta
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm i
- name: "Build"
run: npm run build
- name: Release
uses: ncipollo/release-action@v1
with:
artifacts: "build/*.AppImage,build/*.yml,build/*.deb,build/*.dmg,build/*.blockmap,build/*.zip,build/*.exe"
allowUpdates: true
draft: true
generateReleaseNotes: true

View File

@@ -1,9 +1,12 @@
name: Build & release
name: Build & release [STABLE]
on:
push:
tags:
- "v*"
- 'v[0-9]+.[0-9]+.[0-9]+'
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
jobs:
release:
@@ -11,11 +14,19 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
os: [macos-11, ubuntu-latest, windows-latest]
steps:
- name: Exit if not on master branch
if: contains(env.BRANCH_NAME, 'master') == false
run: |
echo "Wrong environment ${{env.BRANCH_NAME}}"
exit 0
- name: Check out Git repository
uses: actions/checkout@v3
with:
ref: master
- name: Install Node.js
uses: actions/setup-node@v3

View File

@@ -0,0 +1,34 @@
name: Create artifact [LINUX ARM64]
on:
workflow_dispatch: {}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v3
with:
ref: master
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm i
- name: "Build"
run: npm run build -- --arm64 --linux deb AppImage
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: linux-build
retention-days: 3
path: |
build
!build/*-unpacked
!build/.icon-ico

View File

@@ -5,7 +5,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- name: Check out Git repository
uses: actions/checkout@v3
@@ -14,11 +14,12 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 16
- name: npm install & build
run: |
npm install
npm run build
- name: Install dependencies
run: npm i
- name: "Build"
run: npm run build
- name: Upload Artifact
uses: actions/upload-artifact@v3

View File

@@ -0,0 +1,31 @@
name: Create artifact [MAC]
on:
workflow_dispatch: {}
jobs:
build:
runs-on: macos-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: npm install & build
run: |
npm install
npm run build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: macos-build
retention-days: 3
path: |
build
!build/*-unpacked
!build/.icon-ico

View File

@@ -1,6 +1,9 @@
name: Test end-to-end [LINUX]
name: Test end-to-end [WINDOWS]
on: push
on:
push:
branches:
- master
jobs:
release:
@@ -8,7 +11,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
os: [windows-latest]
steps:
- name: Check out Git repository

BIN
.nvmrc Normal file

Binary file not shown.

View File

@@ -1,6 +1,7 @@
{
"extends": [
"stylelint-config-standard"
"stylelint-config-standard",
"stylelint-config-recommended-vue"
],
"fix": true,
"formatter": "verbose",
@@ -10,6 +11,7 @@
"rules": {
"at-rule-no-unknown": null,
"no-descending-specificity": null,
"font-family-no-missing-generic-family-keyword": null,
"declaration-colon-newline-after": "always-multi-line"
},
"syntax": "scss"

2
.vscode/launch.json vendored
View File

@@ -5,7 +5,6 @@
"name": "Electron: Main",
"cwd": "${workspaceFolder}",
"port": 9222,
"protocol": "inspector",
"request": "attach",
"sourceMaps": true,
"type": "node",
@@ -23,7 +22,6 @@
"name": "Electron: Worker",
"cwd": "${workspaceFolder}",
"port": 9224,
"protocol": "inspector",
"request": "attach",
"sourceMaps": true,
"type": "node",

View File

@@ -5,9 +5,12 @@
"MySQL",
"PostgreSQL",
"SQLite",
"Firebird SQL",
"Windows",
"translation",
"Linux"
"Linux",
"MacOS",
"deps"
],
"svg.preview.background": "transparent"
}

View File

@@ -2,6 +2,477 @@
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.7.19](https://github.com/antares-sql/antares/compare/v0.7.19-beta.2...v0.7.19) (2023-11-01)
### Bug Fixes
* table field changes not saved on text fields if pressing enter on textarea modal ([f6fb266](https://github.com/antares-sql/antares/commit/f6fb266771f2d798c8ae42b997c1e33520cf21c3))
### [0.7.19-beta.2](https://github.com/antares-sql/antares/compare/v0.7.19-beta.1...v0.7.19-beta.2) (2023-10-29)
### Bug Fixes
* ssh tunnel keep-alive not working properly ([debc1da](https://github.com/antares-sql/antares/commit/debc1da289d5e35d59adf69d094b329cf93af536))
### [0.7.19-beta.1](https://github.com/antares-sql/antares/compare/v0.7.19-beta.0...v0.7.19-beta.1) (2023-10-25)
### Features
* **MySQL:** RLIKE and NOT RLIKE regular expression filters, closes [#688](https://github.com/antares-sql/antares/issues/688) ([e4eb27d](https://github.com/antares-sql/antares/commit/e4eb27d503e8f912178359c01c62a9b523d17848))
### [0.7.19-beta.0](https://github.com/antares-sql/antares/compare/v0.7.18...v0.7.19-beta.0) (2023-10-14)
### Features
* "now" and "random" options added in datetime related data in insert rows tool, closes [#402](https://github.com/antares-sql/antares/issues/402) ([9f9c63b](https://github.com/antares-sql/antares/commit/9f9c63bfcc3423bfeef143cd835f48c62900a799))
### Bug Fixes
* IN and NOT IN filters not working properly, fixes [#687](https://github.com/antares-sql/antares/issues/687) ([c0dcf30](https://github.com/antares-sql/antares/commit/c0dcf30e73a69b25b01ba31d21b27c1983ed2db6))
* timeout issue on long time sql import ([ddd290c](https://github.com/antares-sql/antares/commit/ddd290c90344241eaa70cb528552e942fd7edec0))
### [0.7.18](https://github.com/antares-sql/antares/compare/v0.7.17...v0.7.18) (2023-10-03)
### Bug Fixes
* hotfix for Microsoft Store unauthorized process ([b3b698b](https://github.com/antares-sql/antares/commit/b3b698b3a23a3c848921ab40fc0fec5d8178ef0e))
### [0.7.17](https://github.com/antares-sql/antares/compare/v0.7.17-beta.2...v0.7.17) (2023-09-30)
### [0.7.17-beta.2](https://github.com/antares-sql/antares/compare/v0.7.17-beta.1...v0.7.17-beta.2) (2023-09-28)
### Features
* add NOT LIKE to table filters, closes [#672](https://github.com/antares-sql/antares/issues/672) ([9c66fd5](https://github.com/antares-sql/antares/commit/9c66fd51cbbe6f21a1fa6a34cc962496d3db7a98))
### Bug Fixes
* nsis updater not working ([198ff01](https://github.com/antares-sql/antares/commit/198ff0103bfa95e3491296d352c944165f31b87e))
* **UI:** small icons in foreign key modal ([b37781d](https://github.com/antares-sql/antares/commit/b37781df84cf7ee99a69ecaa54480d662d79c4aa))
### [0.7.17-beta.1](https://github.com/antares-sql/antares/compare/v0.7.17-beta.0...v0.7.17-beta.1) (2023-09-23)
### Bug Fixes
* flip not working on BaseIcon component ([922f56f](https://github.com/antares-sql/antares/commit/922f56f69b168302a9d1ff86565d3f09400d6a7c))
* **SQLite:** field length lost when editing a table, fixes [#664](https://github.com/antares-sql/antares/issues/664) ([b321e64](https://github.com/antares-sql/antares/commit/b321e64b835e0b39da116c4a77bac50247f240f3))
* **SQLite:** table content not refresh after an update, fixes [#665](https://github.com/antares-sql/antares/issues/665) ([6dceaf0](https://github.com/antares-sql/antares/commit/6dceaf09be7bd46f1915721abd03253ffc517256))
* table filter not working when search string on integer field, [#671](https://github.com/antares-sql/antares/issues/671) ([7e36260](https://github.com/antares-sql/antares/commit/7e36260cdb0438197152b5c6ac61db8ae8a9791a))
* **UI:** small icons in sidebar elements with long name ([354928e](https://github.com/antares-sql/antares/commit/354928e302437d608903d1434d99d68eb79aa6e9))
### [0.7.17-beta.0](https://github.com/antares-sql/antares/compare/v0.7.16...v0.7.17-beta.0) (2023-09-17)
### Features
* customize keep-alive-interval for ssh-tunnel ([b4731d6](https://github.com/antares-sql/antares/commit/b4731d67a5b819bf87c437eb626f30a7489477f9))
* keep alive interval in seconds ([8d605ee](https://github.com/antares-sql/antares/commit/8d605ee2872c20495f0ac4de84bf17d61c6455ae))
* **translation:** Update Dutch ([b43c400](https://github.com/antares-sql/antares/commit/b43c4000d5905838348c391f25b3228dc6a6b2ac))
### Bug Fixes
* empty workspace deleting connections in some conditions ([0de5ef8](https://github.com/antares-sql/antares/commit/0de5ef8a985cc8d9f1fa4479eeaf7dbb20f5fd7c))
* **SQLite:** disconnecting a sqlite connection does not truly close it, fixes [#661](https://github.com/antares-sql/antares/issues/661) ([757a2b3](https://github.com/antares-sql/antares/commit/757a2b3cbf0d7f4df37eb5d90faa2f9821794e5f))
* **UI:** update notification indicator moves settings icon ([e6f45d7](https://github.com/antares-sql/antares/commit/e6f45d71c75206187a7ae87e5f90a22d288a53ef))
### Improvements
* **core:** improved app security, fixes [#666](https://github.com/antares-sql/antares/issues/666) ([1359242](https://github.com/antares-sql/antares/commit/13592425afc643fe7188463fe4a2d02b6e27f87c))
* improved ipc validation on Linux ([9de5f67](https://github.com/antares-sql/antares/commit/9de5f67d189c9b56fff41b29e6df69a3909bfa26))
* migration from font icons to svg icons ([e7bec0a](https://github.com/antares-sql/antares/commit/e7bec0aaaf019fe0c3040d2d9443233e46a60188))
### [0.7.16](https://github.com/antares-sql/antares/compare/v0.7.16-beta.1...v0.7.16) (2023-08-26)
### [0.7.16-beta.1](https://github.com/antares-sql/antares/compare/v0.7.16-beta.0...v0.7.16-beta.1) (2023-08-18)
### Features
* ability to export connections ([f5b86e5](https://github.com/antares-sql/antares/commit/f5b86e59e7e41bbbe1555ec8a85ec1f849e8271d))
* ability to import connections ([6df2145](https://github.com/antares-sql/antares/commit/6df214558f8186dd5fbf101505465f4c07c8ad5f))
* Add catalan language ([9c6f1a9](https://github.com/antares-sql/antares/commit/9c6f1a9ea52b4791082bdbae91b764c486684c3b))
### Bug Fixes
* add some missing titles of buttons ([52e42fa](https://github.com/antares-sql/antares/commit/52e42fa1b529512154c0680124c5e425964a5b1a))
* **SQLite:** improved view body parsing ([832aa75](https://github.com/antares-sql/antares/commit/832aa75ebe46776b9c365dde2dd13db3746adcd5))
### [0.7.16-beta.0](https://github.com/antares-sql/antares/compare/v0.7.15...v0.7.16-beta.0) (2023-08-11)
### Features
* ability to change sql dump file name ([2e39d81](https://github.com/antares-sql/antares/commit/2e39d810b519401d0410cbb76520c07c595329fc))
* ability to export a table dump from table context menu ([84b2255](https://github.com/antares-sql/antares/commit/84b2255bf405431070511890b2bca770fc4cc2bc))
* support to links in changelog ([ad7e459](https://github.com/antares-sql/antares/commit/ad7e459c689d70ca664b9a3091d3dcab3f26ce4d))
### Bug Fixes
* **MySQL:** missing error details on mysql importer with some exceptione ([7b1cb4f](https://github.com/antares-sql/antares/commit/7b1cb4ff86dddb5fb4b4d960b47ea17f38a24aa6))
### [0.7.15](https://github.com/antares-sql/antares/compare/v0.7.14...v0.7.15) (2023-07-31)
### Features
* export file name with hour, minutes and seconds, closes [#610](https://github.com/antares-sql/antares/issues/610) ([2f5fa0f](https://github.com/antares-sql/antares/commit/2f5fa0f2e416e88753c9dc2bf32edefba8c4e072))
### Bug Fixes
* display content of BLOB fields if not binary, fixes [#628](https://github.com/antares-sql/antares/issues/628) ([f831fcd](https://github.com/antares-sql/antares/commit/f831fcd442f16a03f0ea83ff5bf77a4a79906eb6))
* **MySQL:** error insertinf new fields with some MySQL configurations, fixes [#360](https://github.com/antares-sql/antares/issues/360) ([51b1419](https://github.com/antares-sql/antares/commit/51b14195a8a6c7e7f1b12bd4b86b7164a56b2aa5))
* **MySQL:** unable to set more than one value in SET fields ([7c820b1](https://github.com/antares-sql/antares/commit/7c820b18276e4ed5e381d91110acd032862a5be9))
### [0.7.14](https://github.com/antares-sql/antares/compare/v0.7.13...v0.7.14) (2023-07-07)
### Features
* button to open view settings tab ([32bbc45](https://github.com/antares-sql/antares/commit/32bbc453294736970ddbcadd3cc45597277f5bda))
### Bug Fixes
* unable to insert new rows ([1c73503](https://github.com/antares-sql/antares/commit/1c735031380c48aa8b08ed5ce3df80008dc72af8))
### Improvements
* **PostgreSQL:** minor improvement to schema selection ([9d8e9a5](https://github.com/antares-sql/antares/commit/9d8e9a5e1fda190ee7b3d4fd59e6178dd5ec1651))
### [0.7.13](https://github.com/antares-sql/antares/compare/v0.7.12...v0.7.13) (2023-07-06)
### Features
* button to open table settings tab, closes [#608](https://github.com/antares-sql/antares/issues/608) ([38bfea2](https://github.com/antares-sql/antares/commit/38bfea279ce93366dfd2021d0e91622a5a88878e))
* update connection ([462ede8](https://github.com/antares-sql/antares/commit/462ede8dc701aaf9c6089b3ec41eea0f31babdf9))
### Bug Fixes
* **PostgreSQL:** unable to connect to database, fixes [#614](https://github.com/antares-sql/antares/issues/614) ([e808b86](https://github.com/antares-sql/antares/commit/e808b86c52b8488e0c079a9f0ddce225338af4c0))
* unable to copy as sql inserts with BIT fileds, fixes [#613](https://github.com/antares-sql/antares/issues/613) ([6e01f0f](https://github.com/antares-sql/antares/commit/6e01f0f2e7194284341f89a44839d16398358f9b))
### [0.7.12](https://github.com/antares-sql/antares/compare/v0.7.11...v0.7.12) (2023-07-03)
### Features
* add Dutch language support ([4ff1d10](https://github.com/antares-sql/antares/commit/4ff1d107b8837887ceb3ffecaed46b9bdb908127))
* format options of csv export, closes [#196](https://github.com/antares-sql/antares/issues/196) ([3ad1e51](https://github.com/antares-sql/antares/commit/3ad1e51f42f3cc37ad66bdab64e9a8a0eadea74b))
* more translations ([575c8ea](https://github.com/antares-sql/antares/commit/575c8ea8cabc1fb315bad1693df6cd4ccd869838))
* **PostgreSQL:** ability to switch the database, closes [#432](https://github.com/antares-sql/antares/issues/432) ([89815bf](https://github.com/antares-sql/antares/commit/89815bf5e7c4062950b7418b31b45552ae0e1276))
* Sort available languages alphabetically ([3ff8d25](https://github.com/antares-sql/antares/commit/3ff8d2571be306a8a72e5ad2b9f963b285e8db26))
### Bug Fixes
* **PostgreSQL:** unable to export as sql inserts ([e07e7b7](https://github.com/antares-sql/antares/commit/e07e7b736ef29368262ec4b17d9e1f54ef3ec390))
* rename components and variables in SettingBarContext ([8a4a099](https://github.com/antares-sql/antares/commit/8a4a099e37c9bbc1365f322f6276f32153e24379))
* spelling corrections ([93e16fd](https://github.com/antares-sql/antares/commit/93e16fdda29601f3e898b1a9470bd8546ea95df6))
* update source string to fix spelling ([001983c](https://github.com/antares-sql/antares/commit/001983c5a2ebe17c943a9be3a58cc587f5cd09e3))
### [0.7.11](https://github.com/antares-sql/antares/compare/v0.7.10...v0.7.11) (2023-06-04)
### Features
* context menu to close tabs, closes [#392](https://github.com/antares-sql/antares/issues/392) ([787014c](https://github.com/antares-sql/antares/commit/787014c38df743315c04962871a3801805a93c55))
### Bug Fixes
* disable filter during table content loading, fixes [#588](https://github.com/antares-sql/antares/issues/588) ([e60726c](https://github.com/antares-sql/antares/commit/e60726c741276b7da0d54c0986d2a45ed9979bc9))
* **MySQL:** unable to get users list with some db settings ([9046707](https://github.com/antares-sql/antares/commit/904670781d47b1ac0dcfd982215ba1786f8c8145))
* unique keys not recognized in table settings on some MariaDB versions ([4461998](https://github.com/antares-sql/antares/commit/446199827be4b07382453739f42d46fa0201d04c))
* weird behavior in some text editors ([22bdaac](https://github.com/antares-sql/antares/commit/22bdaac18b1c46a57802cbbd3ad339ee075ec70b))
### [0.7.10](https://github.com/antares-sql/antares/compare/v0.7.9...v0.7.10) (2023-05-28)
### Features
* copy rows as PHP array ([03638c0](https://github.com/antares-sql/antares/commit/03638c05534e9ce2e594ce5945485587ed99e609))
* DDL query in table settings for MySQL and PostgreSQL, closes [#581](https://github.com/antares-sql/antares/issues/581) ([f454b4b](https://github.com/antares-sql/antares/commit/f454b4bb1ca79eec285b3b4039a2ef66802ff82a))
* export table content or query results as PHP array, closes [#575](https://github.com/antares-sql/antares/issues/575) ([8968179](https://github.com/antares-sql/antares/commit/8968179c11f4fe3e624873aac4685a5a33521024))
* keepalive on mysql/postgre connections, should fix [#577](https://github.com/antares-sql/antares/issues/577) ([17eeb6d](https://github.com/antares-sql/antares/commit/17eeb6d38e45b553e35e004b748569971743ca18))
### Bug Fixes
* disable shorctut to show Ace editor settings, fixes [#585](https://github.com/antares-sql/antares/issues/585) ([2c0b4ff](https://github.com/antares-sql/antares/commit/2c0b4ffe1f2e418f5e9120a40787788d8e7fd27e))
### [0.7.9](https://github.com/antares-sql/antares/compare/v0.7.8...v0.7.9) (2023-05-01)
### Features
* no table results message ([19859f4](https://github.com/antares-sql/antares/commit/19859f45f4457292b6ecfe79bdcfbdcc7722be06))
* option to choose the target table of an SQL INSERT exportation, closes [#556](https://github.com/antares-sql/antares/issues/556) ([c48266c](https://github.com/antares-sql/antares/commit/c48266c336d7c61abe2b56b5702e5bca83bb57b3))
* **translation:** ko-KR translation, closes [#561](https://github.com/antares-sql/antares/issues/561) ([baef4ea](https://github.com/antares-sql/antares/commit/baef4ea4d1747233a86b90fe5b60a0d6cfba1f1c))
### Bug Fixes
* sidebar height out of visible area ([af91d96](https://github.com/antares-sql/antares/commit/af91d96db6e79222e5dbc9b880a904a40332c09b))
* unable to delete rows with null values and no primary key ([74c136f](https://github.com/antares-sql/antares/commit/74c136f8334b6972ae55dd8ee0ade09ef8ae3282))
* vertical scrollbar does not reset after performing a search, fixes [#567](https://github.com/antares-sql/antares/issues/567) ([0cd55fb](https://github.com/antares-sql/antares/commit/0cd55fbfe9ff09589ae5993f16b0dd56a2ea1a5a))
### Improvements
* **translation:** update italian translation ([96e1ceb](https://github.com/antares-sql/antares/commit/96e1ceb1d2488390216553cd3fce2eec261f04eb))
### [0.7.8](https://github.com/antares-sql/antares/compare/v0.7.7...v0.7.8) (2023-04-12)
### Features
* filter schemas in sidebar, closes [#555](https://github.com/antares-sql/antares/issues/555) ([8be9f93](https://github.com/antares-sql/antares/commit/8be9f932e7a44b2067d8b57950d8faafc577123f))
* **MySQL:** option to export from results SQL INSERTS in chunks, closes [#501](https://github.com/antares-sql/antares/issues/501) ([0f24c80](https://github.com/antares-sql/antares/commit/0f24c80e5a2dc45875df6b67d3c097cf1cca458e))
### Bug Fixes
* **MySQL:** missing scale for FLOAT type ([52108d7](https://github.com/antares-sql/antares/commit/52108d76133d5fdffb56faa995d7ab7ee3e7c4bc))
* triggers not exported if related table not included ([d802b32](https://github.com/antares-sql/antares/commit/d802b32597e42ee90a2d691fe74245b3bc2517ee))
* unable to export BLOB values from table content o query result ([afa61a9](https://github.com/antares-sql/antares/commit/afa61a9bc2d698894096a6b5413c49f05b2fd5aa))
### [0.7.7](https://github.com/antares-sql/antares/compare/v0.7.6...v0.7.7) (2023-03-10)
### Bug Fixes
* hide table size tooltip if disabled ([2c46269](https://github.com/antares-sql/antares/commit/2c46269cf262248d3f5644b7c5b89d5d317a89a4))
* **Linux:** remove app menu shown pressing ALT key ([63fece2](https://github.com/antares-sql/antares/commit/63fece2a1b6b09f61ae416f7c3a7b51ee0a53d0e))
* **Linux:** remove app menu shown pressing ALT key ([b925ff9](https://github.com/antares-sql/antares/commit/b925ff9c01afcc727e5d70bafb079d468ed1eede))
* **MySQL:** missing table information in table setting tab ([59846e6](https://github.com/antares-sql/antares/commit/59846e6ff47591ec8dc22403c3be0e70e0f3ccfd))
* unable to set string fields default values starting with 0 ([3546c57](https://github.com/antares-sql/antares/commit/3546c57e398be7b2e226bb8e93e8fc0fb8bab40a))
### [0.7.6](https://github.com/antares-sql/antares/compare/v0.7.5...v0.7.6) (2023-02-27)
### Bug Fixes
* error with import/export tools, fixes [#541](https://github.com/antares-sql/antares/issues/541) ([d1297a0](https://github.com/antares-sql/antares/commit/d1297a0085fd54967817816efaeed5770a887bbf))
### [0.7.5](https://github.com/antares-sql/antares/compare/v0.7.4...v0.7.5) (2023-02-26)
### Features
* **MySQL:** option, disabled by default, to enable table size indicators on sidebar ([313e740](https://github.com/antares-sql/antares/commit/313e7407eb1afe5d19ac49ee4b308950b48cafa8))
### Bug Fixes
* **MariaDB:** exception with event_scheduler DISABLED with MariaDB 10, fixes [#535](https://github.com/antares-sql/antares/issues/535) ([4458177](https://github.com/antares-sql/antares/commit/445817768863616ea7340c8bf62472197b73bd6e))
* single quotes not properly escaped for random generated content ([629ce63](https://github.com/antares-sql/antares/commit/629ce633294c862266db9e27ffa5c154e8fc416c))
* unable to import after a failed import, fixes [#515](https://github.com/antares-sql/antares/issues/515) ([b1fbc43](https://github.com/antares-sql/antares/commit/b1fbc43ab2f39827cb85ac7d21ac889ffc2f4c64))
### [0.7.4](https://github.com/antares-sql/antares/compare/v0.7.3...v0.7.4) (2023-02-10)
### Bug Fixes
* tables sort in sidebar ([ddb7ead](https://github.com/antares-sql/antares/commit/ddb7ead0832708713ba4bb2717661b8b93a47e3f))
### [0.7.3](https://github.com/antares-sql/antares/compare/v0.7.2...v0.7.3) (2023-02-09)
### Features
* **SQLite:** added support to INTEGER UNSIGNED ([e7e4913](https://github.com/antares-sql/antares/commit/e7e491340a037b64d6d8e538376415779d54332e))
### Bug Fixes
* longtext edit modal opens when it shouldn't, fixes [#524](https://github.com/antares-sql/antares/issues/524) ([6decba3](https://github.com/antares-sql/antares/commit/6decba316ca46106520cb4dba44409ceb4a4af75))
* select of table type stuck when editing an unknown type ([e8447e5](https://github.com/antares-sql/antares/commit/e8447e56551871a200517bdaa747ae215ad83cf4))
* **SQLite:** error with integer timestamp fields ([2b5e1e7](https://github.com/antares-sql/antares/commit/2b5e1e7b39c25f536b6139a4d01b9f7f17069ea8))
* **SQLite:** triggers disappear after editing related table, fixes [#523](https://github.com/antares-sql/antares/issues/523) ([d934ae1](https://github.com/antares-sql/antares/commit/d934ae1e6c0747698b4973d9cad217379076a6cf))
### [0.7.2](https://github.com/antares-sql/antares/compare/v0.7.1...v0.7.2) (2023-01-22)
### Features
* add copy shortcut and default copy type setting ([9aca894](https://github.com/antares-sql/antares/commit/9aca89477f1fd7b7f55f1e5c290d495c46f61d8e))
* connection info icons in footer ([ff4bc6c](https://github.com/antares-sql/antares/commit/ff4bc6c39b05a827cebde84466814cf246908208))
### Bug Fixes
* allow comments in queies, fixes [#519](https://github.com/antares-sql/antares/issues/519) ([c7ab3b7](https://github.com/antares-sql/antares/commit/c7ab3b77a22e85cee6fb93064eaad5a8e8ad9fd2))
* **SQLite:** exception saving tables without INT fields length ([0e80e82](https://github.com/antares-sql/antares/commit/0e80e823d059dfe24995b5848d88cc84235e6275))
* ssh connection closed after idle time, fixes [#425](https://github.com/antares-sql/antares/issues/425) ([6fa430a](https://github.com/antares-sql/antares/commit/6fa430adf68013a9d0a093031f56dd741bdc0299))
### [0.7.1](https://github.com/antares-sql/antares/compare/v0.7.0...v0.7.1) (2022-12-23)
### Features
* Copy rows as html table, so we can paste it to spreadsheet ([c32f463](https://github.com/antares-sql/antares/commit/c32f463ea5ac3f54cba32929f77442f1e0ba934a))
* option to disable selected query execution, closes [#477](https://github.com/antares-sql/antares/issues/477) ([1bd26ce](https://github.com/antares-sql/antares/commit/1bd26ceaa68fe66f26c76b3b60fa6eeccea91729))
### Bug Fixes
* bahasa indonesia typos ([897795d](https://github.com/antares-sql/antares/commit/897795ddbb4ade2652b0471f18288b8b3aaf0eb9))
* connection default icon not change after client change ([a6bdf69](https://github.com/antares-sql/antares/commit/a6bdf69a281c8614c41274b6dc2f3563aa89c57e))
* context submenu outside view when near the edge, fixes [#506](https://github.com/antares-sql/antares/issues/506) ([c08946e](https://github.com/antares-sql/antares/commit/c08946e932884e5f0253df2545f98315ab7e5219))
* **i18n:** add missing keys for french translation ([fd129a2](https://github.com/antares-sql/antares/commit/fd129a2ad1c3401372c9172b38f4406254d134df))
* **MySQL:** not every connection gets read-only option ([843c15e](https://github.com/antares-sql/antares/commit/843c15e428c4a0412f19a93ab05d2fcbb60da09b))
* **UI:** white background dragging connections inside folder on Linux ([dd971d7](https://github.com/antares-sql/antares/commit/dd971d70e04faf0d5b239586b12e4a9a42407433))
* white background dragging connections or tabs on Linux, fixes [#486](https://github.com/antares-sql/antares/issues/486) ([669d7e8](https://github.com/antares-sql/antares/commit/669d7e8d4d062ed5bdafe1d5cde8ec51a2f68b26))
## [0.7.0](https://github.com/antares-sql/antares/compare/v0.6.0...v0.7.0) (2022-11-30)
### Features
* **UI:** connections customization ([212b2bd](https://github.com/antares-sql/antares/commit/212b2bdba933db1af22967a057d64f41c96b9930))
* **UI:** folders customization ([72accb7](https://github.com/antares-sql/antares/commit/72accb7b0e62977dde2c82312aee5b9d025e5182))
* **UI:** folders implementation ([ece6c64](https://github.com/antares-sql/antares/commit/ece6c6401def4a9b42280f23efaa038b9ad98de8))
* **UI:** footer color based on folder color ([4fe9dfc](https://github.com/antares-sql/antares/commit/4fe9dfc4d7ca19a798b8a8a74d979ab88aebeaac))
* **UI:** new settimgbar tooltips ([6728964](https://github.com/antares-sql/antares/commit/672896414e901635c83ca037663e355a31ce013b))
### Bug Fixes
* deletion of connections inside folder ([b06bafe](https://github.com/antares-sql/antares/commit/b06bafe06c060233ebe901979b9fc4455a25cb89))
* missing sidebar data after update ([0a1f50a](https://github.com/antares-sql/antares/commit/0a1f50a9b92c9705784b93f14be40a01a78cb0da))
* **UI:** folder to folder drag glitches ([0fca70e](https://github.com/antares-sql/antares/commit/0fca70ebec1af3d594db4e1ce159e52e12224850))
* **UI:** wrong copnnection icons color with light theme ([d010d5a](https://github.com/antares-sql/antares/commit/d010d5aa8f07a5def1183567ee767fd144696ed3))
* wrong position moving elements outside folder ([7af178a](https://github.com/antares-sql/antares/commit/7af178a1e400876e6c45dbe31a198a12d29227a8))
## [0.6.0](https://github.com/antares-sql/antares/compare/v0.5.19...v0.6.0) (2022-11-18)
### Features
* **Firebird SQL:** connections pool ([76df631](https://github.com/antares-sql/antares/commit/76df6319c242ea42f93d4e5d811d96ec2c282aa8))
* **Firebird SQL:** display table content and query results ([95bb41e](https://github.com/antares-sql/antares/commit/95bb41e9db255a780aae1ae32ce4a53ee3bab20e))
* **Firebird SQL:** manual commit mode ([27566c1](https://github.com/antares-sql/antares/commit/27566c1dfae55f72d3f870c50410e5ecda256037))
* **Firebird SQL:** procedure add/edit/delete support ([ae312ef](https://github.com/antares-sql/antares/commit/ae312efbbc3a9941380477b9849bdd8edc5b9fbf))
* **Firebird SQL:** support to blob fields ([0827a04](https://github.com/antares-sql/antares/commit/0827a04d61af75b4366394e5f0289df461d02c98))
* **Firebird SQL:** support to indexes and foreign keys ([2c8509f](https://github.com/antares-sql/antares/commit/2c8509ff4173fbebeff92ab472a37edd3d80a2ac))
* **Firebird SQL:** table add/edit/delete support ([1b5cc31](https://github.com/antares-sql/antares/commit/1b5cc315dddca6b753fb6fe6e196e29441ffed79))
* **Firebird SQL:** trigger add/edit/delete support ([8e422e3](https://github.com/antares-sql/antares/commit/8e422e3f07323f388523621a05f0403a87f19e47))
* **Firebird SQL:** view add/edit/delete support ([7d1967a](https://github.com/antares-sql/antares/commit/7d1967a60977b2ce1095a37b7135f429a83f163d))
* support to text blob fields ([e6f6a02](https://github.com/antares-sql/antares/commit/e6f6a022d1a5bbc3f5303f635a2115813601c61a))
### Bug Fixes
* **Firebird SQL:** connection pool issue ([7ff8e21](https://github.com/antares-sql/antares/commit/7ff8e2149ef911a235b4a1dcc329775af1d2a72b))
* incomplete list of collations, fixes [#478](https://github.com/antares-sql/antares/issues/478) ([1c1403f](https://github.com/antares-sql/antares/commit/1c1403f58641f7b5f8a7c29fc430673ffa88f969))
* loss of precision updating BIGINT values, fixes [#467](https://github.com/antares-sql/antares/issues/467) ([d190a2d](https://github.com/antares-sql/antares/commit/d190a2dd61040d1748dfb97403f9d56015d938fe))
### [0.5.19](https://github.com/antares-sql/antares/compare/v0.5.18...v0.5.19) (2022-10-22)
### Features
* context menu option to fill cell with random values ([0a2124f](https://github.com/antares-sql/antares/commit/0a2124f2c2bdadc7c753db11d1e29f8acb9ddcac))
* uuid fill for string cells ([24edc82](https://github.com/antares-sql/antares/commit/24edc82b1be7299a09df18611b2a0ba361a6b46f))
### Bug Fixes
* app stuck inserting a random value if field length high ([440f74d](https://github.com/antares-sql/antares/commit/440f74dfc1f4942ba585b9bdae7517fe6ab04a81))
* error joining tables with different schema ([88408da](https://github.com/antares-sql/antares/commit/88408da745e45c70de977bc4270e5f61825be65f))
* **SQLite:** save boolean as integer to improve compativility, fixes [#463](https://github.com/antares-sql/antares/issues/463) ([d52b7af](https://github.com/antares-sql/antares/commit/d52b7af2978bc8beafd2d22078c72abb62e9e532))
* unable to edit text fields if value is NULL, fixes [#466](https://github.com/antares-sql/antares/issues/466) ([8621ca5](https://github.com/antares-sql/antares/commit/8621ca5333b5c51dc7a2ea1fcc0c5ec7f752a00a))
### [0.5.18](https://github.com/antares-sql/antares/compare/v0.5.17...v0.5.18) (2022-10-14)
### Features
* **PostgreSQL:** UUID random generation option on UUID fields, closes [#424](https://github.com/antares-sql/antares/issues/424) ([a521274](https://github.com/antares-sql/antares/commit/a521274d01031c1411bbbb136369802d43368089))
### Bug Fixes
* auto-scroll on sidebar not working, fixes [#447](https://github.com/antares-sql/antares/issues/447) ([dd9c089](https://github.com/antares-sql/antares/commit/dd9c089d27c61ab76d49887c7de2849cbb6e88a6))
* trackpad horizontal scroll on tabs not working properly ([ba5a1b6](https://github.com/antares-sql/antares/commit/ba5a1b68ab2d56777a5c94eede26e9bded5819e6))
### [0.5.17](https://github.com/antares-sql/antares/compare/v0.5.16...v0.5.17) (2022-09-22)
### Features
* added more editor font sizes, closes [#440](https://github.com/antares-sql/antares/issues/440) ([d114f8a](https://github.com/antares-sql/antares/commit/d114f8a65164f702b23175095e6fc2b021e0e038))
### Bug Fixes
* "run or reload" shortcut triggers on all connections open ([01f607c](https://github.com/antares-sql/antares/commit/01f607cd40c18ab0f9761b2a05705a966aaae43a))
* cant run procedures with parameters from leftbar ([efe134a](https://github.com/antares-sql/antares/commit/efe134a059700ca87333dc6e66166d6ec8d289e8))
* editor font size doesn't change on new tabs, fixes [#442](https://github.com/antares-sql/antares/issues/442) ([84168d1](https://github.com/antares-sql/antares/commit/84168d1d75460acc2c844bfece7d85f0c977e74c))
* empty definer when editing a view, fixes [#437](https://github.com/antares-sql/antares/issues/437) ([498a9b4](https://github.com/antares-sql/antares/commit/498a9b48e25ee061960f5f649c953cdaf6ff1a58))
* **MacOS:** empty options on macos menubar ([a142d3c](https://github.com/antares-sql/antares/commit/a142d3c4d77e31375dfbea148eec54ce1f635192))
### [0.5.16](https://github.com/antares-sql/antares/compare/v0.5.15...v0.5.16) (2022-08-26)
### Bug Fixes
* CTRL+Right/Left not working on text editor, closes [#427](https://github.com/antares-sql/antares/issues/427) ([ffc645b](https://github.com/antares-sql/antares/commit/ffc645ba5efb1c52670096e4f8c7f992b7335dae))
* issue updating datetime cells with null value, closes [#423](https://github.com/antares-sql/antares/issues/423) ([ebc325a](https://github.com/antares-sql/antares/commit/ebc325ae0c656dca2eb8f7544ab271beaee9b47e))
* ts exceptions ([df68114](https://github.com/antares-sql/antares/commit/df681147aaf0bfca69f3ffdc474cc1846541b1d8))
* **UI:** editor themes group not visible in select element ([9dc700e](https://github.com/antares-sql/antares/commit/9dc700e13ea65bb8c6feac4ff4ffeadd32053614))
* **UI:** wrong position of fields resizable area ([c90ab0e](https://github.com/antares-sql/antares/commit/c90ab0e8807ff30a9ab58e9aa3515cf427dd6e86))
* unable to set null or delete rows without primary key ([39326eb](https://github.com/antares-sql/antares/commit/39326eb52e038728b5419d4a8de8024c7ead3002))
### [0.5.15](https://github.com/antares-sql/antares/compare/v0.5.14...v0.5.15) (2022-08-17)
### Features
* ability to add new shortcuts ([d044a02](https://github.com/antares-sql/antares/commit/d044a02cb79a9d06aadc34cdbf6e81da84360559))
* ability to edit shortcuts ([8eb127e](https://github.com/antares-sql/antares/commit/8eb127e45838bc01ba12f0740fec077fcd975532))
* added more events in shortcuts setting ([5043faf](https://github.com/antares-sql/antares/commit/5043fafa934844ebc2f59cabcec830c6a4d5ca8e))
* delete shortcuts and restore defaults ([c22413f](https://github.com/antares-sql/antares/commit/c22413fde9dfe5501a5f220070cfe552a318c70b))
* dynamic shortcut suggestions on empty query tabs ([4df14c3](https://github.com/antares-sql/antares/commit/4df14c3693955bd7801b4b99103fca85f00f3e8c))
* list of available shortcuts in settings window ([44bb75b](https://github.com/antares-sql/antares/commit/44bb75bc60d7d31bbd99a9ba57f30fd354f7581c))
* **UI:** connection name on left bar, closes [#382](https://github.com/antares-sql/antares/issues/382) [#414](https://github.com/antares-sql/antares/issues/414) ([4887753](https://github.com/antares-sql/antares/commit/48877534d1a41d351b267c0dab925046ca984179))
* **UI:** shortcuts setting UI improved ([49b63bc](https://github.com/antares-sql/antares/commit/49b63bc6f28fc6031e6a892d0a48cd35ae2f26cd))
### Bug Fixes
* startup exception ([c50d17e](https://github.com/antares-sql/antares/commit/c50d17e82b7fd337d4037ddf646cd1a8fc765bae))
### Improvements
* improved keypress detector ([0f219cf](https://github.com/antares-sql/antares/commit/0f219cf9b796b4369c609fb0e8e3b84346a30b07))
* **translation:** updated italian translation ([c05be83](https://github.com/antares-sql/antares/commit/c05be8304f3cf299cf338f67c00184305e022919))
### [0.5.14](https://github.com/antares-sql/antares/compare/v0.5.13...v0.5.14) (2022-08-09)
### Bug Fixes
* unable to open settingbar context menu ([44eb507](https://github.com/antares-sql/antares/commit/44eb507a12bad028a4fa8a8bb0f6442a3e8dde91))
### [0.5.13](https://github.com/antares-sql/antares/compare/v0.5.12...v0.5.13) (2022-08-09)

View File

@@ -61,7 +61,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
fabio286@gmail.com.
info@fabiodistasio.it.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the

View File

@@ -7,19 +7,23 @@
# Antares SQL Client
![GitHub package.json version](https://img.shields.io/github/package-json/v/fabio286/antares) ![GitHub](https://img.shields.io/github/license/fabio286/antares) [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Ffabio286%2Fantares%2Fbadge&style=flat)](https://actions-badge.atrox.dev/fabio286/antares/goto) [![antares](https://snapcraft.io/antares/badge.svg)](https://snapcraft.io/antares) [![antares](https://snapcraft.io/antares/trending.svg?name=0)](https://snapcraft.io/antares) [![Twitter Follow](https://img.shields.io/twitter/follow/AntaresSQL?style=social)](https://twitter.com/AntaresSQL) [![Plant a Tree](https://raw.githubusercontent.com/Fabio286/treedom-badge/master/svg/plant-a-tree.svg)](https://www.treedom.net/en/user/fabio-di-stasio/event/antares-for-the-planet)
![GitHub package.json version](https://img.shields.io/github/package-json/v/fabio286/antares) ![GitHub](https://img.shields.io/github/license/fabio286/antares) [![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Ffabio286%2Fantares%2Fbadge&style=flat)](https://actions-badge.atrox.dev/fabio286/antares/goto) [![antares](https://snapcraft.io/antares/badge.svg)](https://snapcraft.io/antares) [![antares](https://snapcraft.io/antares/trending.svg?name=0)](https://snapcraft.io/antares)
![Mastodon Follow](https://img.shields.io/mastodon/follow/%20110860460902482117?domain=https%3A%2F%2Ffosstodon.org&style=social) [![Twitter Follow](https://img.shields.io/twitter/follow/AntaresSQL?style=social)](https://twitter.com/AntaresSQL) [![Plant a Tree](https://raw.githubusercontent.com/Fabio286/treedom-badge/master/svg/plant-a-tree.svg)](https://www.treedom.net/en/user/fabio-di-stasio/event/antares-for-the-planet)
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.
Our 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, PostgreSQL and SQLite.
**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB, PostgreSQL, SQLite and Firebird SQL.
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.
👁 To stay tuned for new releases follow Antares SQL on [Mastodon](https://fosstodon.org/@AntaresSQL) or [Twitter](https://twitter.com/AntaresSQL).
🌟 Don't forget to **leave a star** if you appreciate this project.
🗳️ Poll: **[Which is the main OS you use Antares on?](https://github.com/antares-sql/antares/discussions/379)**
🗳️ Polls:
- **[Which is the main OS you use Antares on?](https://github.com/antares-sql/antares/discussions/379)**
- **[Which database do you use the most?](https://github.com/antares-sql/antares/discussions/594)**
## Current key features
@@ -34,6 +38,7 @@ We are actively working on it, hoping to provide new cool features, improvements
- SSH tunnel support.
- Manual commit mode.
- Import and export database dumps.
- Customizable keyboard shortcuts.
- Dark and light theme.
- Editor themes.
@@ -62,7 +67,7 @@ On macOS you can run `.dmg` distribution following [this guide](https://support.
## Download
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/antares) [![Get it from AUR](https://raw.githubusercontent.com/Fabio286/antares/3e00c4bae6e036300c752c1a40c5a038fea9c169/docs/aur-badge.svg)](https://aur.archlinux.org/packages/antares-sql/) [<img src="https://developer.microsoft.com/store/badges/images/English_get-it-from-MS.png" style="height: 56px">](https://www.microsoft.com/p/antares-sql-client/9nhtb9sq51r1?cid=storebadge&ocid=badge&rtc=1&activetab=pivot:overviewtab)
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/antares) [![Get it from AUR](https://raw.githubusercontent.com/Fabio286/antares/3e00c4bae6e036300c752c1a40c5a038fea9c169/docs/aur-badge.svg)](https://aur.archlinux.org/packages/antares-sql-bin) [<img src="https://developer.microsoft.com/store/badges/images/English_get-it-from-MS.png" style="height: 56px">](https://www.microsoft.com/p/antares-sql-client/9nhtb9sq51r1?cid=storebadge&ocid=badge&rtc=1&activetab=pivot:overviewtab)
🚀 **[Other Downloads](https://github.com/Fabio286/antares/releases/latest)**
## Coming soon
@@ -83,8 +88,8 @@ This is a roadmap with major features will come in near future.
- [x] MySQL/MariaDB
- [x] PostgreSQL
- [x] SQLite
- [ ] MSSQL
- [ ] OracleDB
- [x] Firebird SQL
- [ ] SQL Server
- [ ] More...
### Operating Systems
@@ -115,30 +120,43 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://fabiodistasio.it/"><img src="https://avatars.githubusercontent.com/u/31471771?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fabio Di Stasio</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=Fabio286" title="Code">💻</a> <a href="#translation-Fabio286" title="Translation">🌍</a> <a href="https://github.com/antares-sql/antares/commits?author=Fabio286" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.linkedin.com/in/giulioganci/"><img src="https://avatars.githubusercontent.com/u/4192159?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Giulio Ganci</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=toriphes" title="Code">💻</a></td>
<td align="center"><a href="https://christianratz.de/"><img src="https://avatars.githubusercontent.com/u/2630316?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Ratz</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=digitalgopnik" title="Code">💻</a> <a href="#translation-digitalgopnik" title="Translation">🌍</a></td>
<td align="center"><a href="https://reverb6821.github.io/"><img src="https://avatars.githubusercontent.com/u/55198803?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Giuseppe Gigliotti</b></sub></a><br /><a href="#translation-reverb6821" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/Mohd-PH"><img src="https://avatars.githubusercontent.com/u/9362157?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mohd-PH</b></sub></a><br /><a href="#translation-Mohd-PH" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/hongkfui"><img src="https://avatars.githubusercontent.com/u/37477191?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hongkfui</b></sub></a><br /><a href="#translation-hongkfui" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/MrAnyx"><img src="https://avatars.githubusercontent.com/u/44176707?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robin</b></sub></a><br /><a href="#translation-MrAnyx" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/daeleduardo"><img src="https://avatars.githubusercontent.com/u/8599078?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Eduardo</b></sub></a><br /><a href="#translation-daeleduardo" title="Translation">🌍</a></td>
<td align="center"><a href="https://ngoquocdat.com/"><img src="https://avatars.githubusercontent.com/u/56961917?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ngô Quốc Đạt</b></sub></a><br /><a href="#translation-datlechin" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/IsamuSugi"><img src="https://avatars.githubusercontent.com/u/7746658?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Isamu Sugiura</b></sub></a><br /><a href="#translation-IsamuSugi" title="Translation">🌍</a></td>
<td align="center"><a href="http://rsacchetto.nexxontech.it/"><img src="https://avatars.githubusercontent.com/u/18429412?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Riccardo Sacchetto</b></sub></a><br /><a href="#platform-Occhioverde" title="Packaging/porting to new platform">📦</a></td>
<td align="center"><a href="https://kilianstallinger.com"><img src="https://avatars.githubusercontent.com/u/5290318?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kilian Stallinger</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=kilianstallz" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/wenj91"><img src="https://avatars.githubusercontent.com/u/12549338?v=4?s=100" width="100px;" alt=""/><br /><sub><b>文杰</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=wenj91" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/goYou"><img src="https://avatars.githubusercontent.com/u/62732795?v=4?s=100" width="100px;" alt=""/><br /><sub><b>goYou</b></sub></a><br /><a href="#translation-goYou" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/raliqala"><img src="https://avatars.githubusercontent.com/u/30502407?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Topollo</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=raliqala" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/SmileYzn"><img src="https://avatars.githubusercontent.com/u/5851851?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cleverson</b></sub></a><br /><a href="#translation-SmileYzn" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/fredatgithub"><img src="https://avatars.githubusercontent.com/u/6720055?v=4?s=100" width="100px;" alt=""/><br /><sub><b>fred</b></sub></a><br /><a href="#translation-fredatgithub" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/xak666"><img src="https://avatars.githubusercontent.com/u/38811437?v=4?s=100" width="100px;" alt=""/><br /><sub><b>xaka_xak</b></sub></a><br /><a href="#translation-xak666" title="Translation">🌍</a></td>
</tr>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://fabiodistasio.it/"><img src="https://avatars.githubusercontent.com/u/31471771?v=4?s=100" width="100px;" alt="Fabio Di Stasio"/><br /><sub><b>Fabio Di Stasio</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=Fabio286" title="Code">💻</a> <a href="#translation-Fabio286" title="Translation">🌍</a> <a href="https://github.com/antares-sql/antares/commits?author=Fabio286" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/giulioganci/"><img src="https://avatars.githubusercontent.com/u/4192159?v=4?s=100" width="100px;" alt="Giulio Ganci"/><br /><sub><b>Giulio Ganci</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=toriphes" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://christianratz.de/"><img src="https://avatars.githubusercontent.com/u/2630316?v=4?s=100" width="100px;" alt="Christian Ratz"/><br /><sub><b>Christian Ratz</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=digitalgopnik" title="Code">💻</a> <a href="#translation-digitalgopnik" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://reverb6821.github.io/"><img src="https://avatars.githubusercontent.com/u/55198803?v=4?s=100" width="100px;" alt="Giuseppe Gigliotti"/><br /><sub><b>Giuseppe Gigliotti</b></sub></a><br /><a href="#translation-reverb6821" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Mohd-PH"><img src="https://avatars.githubusercontent.com/u/9362157?v=4?s=100" width="100px;" alt="Mohd-PH"/><br /><sub><b>Mohd-PH</b></sub></a><br /><a href="#translation-Mohd-PH" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hongkfui"><img src="https://avatars.githubusercontent.com/u/37477191?v=4?s=100" width="100px;" alt="hongkfui"/><br /><sub><b>hongkfui</b></sub></a><br /><a href="#translation-hongkfui" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MrAnyx"><img src="https://avatars.githubusercontent.com/u/44176707?v=4?s=100" width="100px;" alt="Robin"/><br /><sub><b>Robin</b></sub></a><br /><a href="#translation-MrAnyx" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daeleduardo"><img src="https://avatars.githubusercontent.com/u/8599078?v=4?s=100" width="100px;" alt="Daniel Eduardo"/><br /><sub><b>Daniel Eduardo</b></sub></a><br /><a href="#translation-daeleduardo" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://ngoquocdat.com/"><img src="https://avatars.githubusercontent.com/u/56961917?v=4?s=100" width="100px;" alt="Ngô Quốc Đạt"/><br /><sub><b>Ngô Quốc Đạt</b></sub></a><br /><a href="#translation-datlechin" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/IsamuSugi"><img src="https://avatars.githubusercontent.com/u/7746658?v=4?s=100" width="100px;" alt="Isamu Sugiura"/><br /><sub><b>Isamu Sugiura</b></sub></a><br /><a href="#translation-IsamuSugi" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://rsacchetto.nexxontech.it/"><img src="https://avatars.githubusercontent.com/u/18429412?v=4?s=100" width="100px;" alt="Riccardo Sacchetto"/><br /><sub><b>Riccardo Sacchetto</b></sub></a><br /><a href="#platform-Occhioverde" title="Packaging/porting to new platform">📦</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://kilianstallinger.com"><img src="https://avatars.githubusercontent.com/u/5290318?v=4?s=100" width="100px;" alt="Kilian Stallinger"/><br /><sub><b>Kilian Stallinger</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=kilianstallz" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wenj91"><img src="https://avatars.githubusercontent.com/u/12549338?v=4?s=100" width="100px;" alt="文杰"/><br /><sub><b>文杰</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=wenj91" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/goYou"><img src="https://avatars.githubusercontent.com/u/62732795?v=4?s=100" width="100px;" alt="goYou"/><br /><sub><b>goYou</b></sub></a><br /><a href="#translation-goYou" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/raliqala"><img src="https://avatars.githubusercontent.com/u/30502407?v=4?s=100" width="100px;" alt="Topollo"/><br /><sub><b>Topollo</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=raliqala" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SmileYzn"><img src="https://avatars.githubusercontent.com/u/5851851?v=4?s=100" width="100px;" alt="Cleverson"/><br /><sub><b>Cleverson</b></sub></a><br /><a href="#translation-SmileYzn" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fredatgithub"><img src="https://avatars.githubusercontent.com/u/6720055?v=4?s=100" width="100px;" alt="fred"/><br /><sub><b>fred</b></sub></a><br /><a href="#translation-fredatgithub" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xak666"><img src="https://avatars.githubusercontent.com/u/38811437?v=4?s=100" width="100px;" alt="xaka_xak"/><br /><sub><b>xaka_xak</b></sub></a><br /><a href="#translation-xak666" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://codepen.io/theo-billardey"><img src="https://avatars.githubusercontent.com/u/48206778?v=4?s=100" width="100px;" alt="Théo Billardey"/><br /><sub><b>Théo Billardey</b></sub></a><br /><a href="#translation-brdtheo" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://yaskur.net"><img src="https://avatars.githubusercontent.com/u/9539970?v=4?s=100" width="100px;" alt="Muhammad Dyas Yaskur"/><br /><sub><b>Muhammad Dyas Yaskur</b></sub></a><br /><a href="#translation-dyaskur" title="Translation">🌍</a> <a href="https://github.com/antares-sql/antares/commits?author=dyaskur" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jimcat8"><img src="https://avatars.githubusercontent.com/u/86754294?v=4?s=100" width="100px;" alt="tianci li"/><br /><sub><b>tianci li</b></sub></a><br /><a href="#translation-jimcat8" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/555cider"><img src="https://avatars.githubusercontent.com/u/73565447?v=4?s=100" width="100px;" alt="555cider"/><br /><sub><b>555cider</b></sub></a><br /><a href="#translation-555cider" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/m1khal3v"><img src="https://avatars.githubusercontent.com/u/41085561?v=4?s=100" width="100px;" alt="Anton Mikhalev"/><br /><sub><b>Anton Mikhalev</b></sub></a><br /><a href="#translation-m1khal3v" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://64k.nl/"><img src="https://avatars.githubusercontent.com/u/3864423?v=4?s=100" width="100px;" alt="René"/><br /><sub><b>René</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=64knl" title="Code">💻</a> <a href="#translation-64knl" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zxp19821005"><img src="https://avatars.githubusercontent.com/u/4915850?v=4?s=100" width="100px;" alt="Woodenman"/><br /><sub><b>Woodenman</b></sub></a><br /><a href="#platform-zxp19821005" title="Packaging/porting to new platform">📦</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/markusand"><img src="https://avatars.githubusercontent.com/u/12972543?v=4?s=100" width="100px;" alt="Marc Vilella"/><br /><sub><b>Marc Vilella</b></sub></a><br /><a href="#translation-markusand" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Lawondyss"><img src="https://avatars.githubusercontent.com/u/272130?v=4?s=100" width="100px;" alt="Ladislav Vondráček"/><br /><sub><b>Ladislav Vondráček</b></sub></a><br /><a href="#translation-Lawondyss" title="Translation">🌍</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->

BIN
assets/linux/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/linux/16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

BIN
assets/linux/256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
assets/linux/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
assets/linux/64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

16361
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "antares",
"productName": "Antares",
"version": "0.5.13",
"version": "0.7.19",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT",
"repository": "https://github.com/antares-sql/antares.git",
@@ -16,9 +16,10 @@
"build:appx": "npm run build -- --win appx",
"rebuild:electron": "rimraf ./dist && npm run postinstall && npm run devtools:install",
"release": "standard-version",
"release:pre": "npm run release -- --prerelease alpha",
"release:beta": "npm run release -- --prerelease beta",
"devtools:install": "node scripts/devtoolsInstaller",
"postinstall": "electron-builder install-app-deps",
"translation:check": "ts-node ./scripts/translationCheck.ts",
"test:e2e": "npm run compile && npm run test:e2e-dry",
"test:e2e-dry": "xvfb-maybe -- playwright test",
"lint": "eslint . --ext .js,.ts,.vue && stylelint \"./src/**/*.{css,scss,sass,vue}\"",
@@ -26,7 +27,7 @@
"contributors:add": "all-contributors add",
"contributors:generate": "all-contributors generate"
},
"author": "Fabio Di Stasio <fabio286@gmail.com>",
"author": "Fabio Di Stasio <info@fabiodistasio.it>",
"main": "./dist/main.js",
"antares": {
"devtoolsId": "nhdogjmejiglipccpnnnanhbledajbpd"
@@ -66,19 +67,18 @@
"target": "deb",
"arch": [
"x64",
"armv7l",
"arm64"
"armv7l"
]
},
{
"target": "AppImage",
"arch": [
"x64",
"armv7l",
"arm64"
"armv7l"
]
}
],
"icon": "assets/linux",
"category": "Development"
},
"appImage": {
@@ -120,44 +120,49 @@
"dependencies": {
"@electron/remote": "~2.0.1",
"@faker-js/faker": "~6.1.2",
"@mdi/font": "~7.0.96",
"@jamescoyle/vue-icon": "~0.1.2",
"@mdi/js": "~7.2.96",
"@turf/helpers": "~6.5.0",
"@vueuse/core": "~8.7.5",
"ace-builds": "~1.8.1",
"better-sqlite3": "~7.5.1",
"@vueuse/core": "~10.4.1",
"ace-builds": "~1.24.1",
"better-sqlite3": "~8.0.0",
"electron-log": "~4.4.1",
"electron-store": "~8.0.1",
"electron-store": "~8.1.0",
"electron-updater": "~4.6.5",
"electron-window-state": "~5.0.3",
"encoding": "~0.1.13",
"floating-vue": "~2.0.0-beta.20",
"json2php": "~0.0.7",
"leaflet": "~1.7.1",
"marked": "~4.0.0",
"marked": "~4.0.19",
"moment": "~2.29.4",
"mysql2": "~2.3.2",
"pg": "~8.7.1",
"mysql2": "~3.5.2",
"node-firebird": "~1.1.4",
"pg": "~8.11.1",
"pg-connection-string": "~2.5.0",
"pg-query-stream": "~4.2.3",
"pgsql-ast-parser": "~7.2.1",
"pinia": "~2.0.13",
"pinia": "~2.1.6",
"source-map-support": "~0.5.20",
"spectre.css": "~0.5.9",
"sql-formatter": "~8.2.0",
"ssh2-promise": "~1.0.2",
"sql-formatter": "~13.0.0",
"@fabio286/ssh2-promise": "~1.0.4-b",
"v-mask": "~2.3.0",
"vue": "~3.2.37",
"vue-i18n": "~9.2.0",
"vue": "~3.3.4",
"vue-i18n": "~9.2.2",
"vuedraggable": "~4.1.0"
},
"devDependencies": {
"@babel/eslint-parser": "~7.15.7",
"@babel/preset-env": "~7.15.8",
"@babel/preset-typescript": "~7.16.7",
"@playwright/test": "~1.21.1",
"@playwright/test": "~1.28.1",
"@types/better-sqlite3": "~7.5.0",
"@types/leaflet": "~1.7.9",
"@types/marked": "~4.0.3",
"@types/marked": "~4.0.7",
"@types/node": "~17.0.23",
"@types/pg": "~8.6.5",
"@types/ssh2": "~1.11.6",
"@typescript-eslint/eslint-plugin": "~5.18.0",
"@typescript-eslint/parser": "~5.18.0",
"@vue/compiler-sfc": "~3.2.33",
@@ -166,38 +171,42 @@
"chalk": "~4.1.2",
"cross-env": "~7.0.2",
"css-loader": "~6.5.0",
"electron": "~19.0.5",
"electron-builder": "~23.0.3",
"electron": "~22.3.27",
"electron-builder": "~22.10.3",
"eslint": "~7.32.0",
"eslint-config-standard": "~16.0.3",
"eslint-plugin-import": "~2.24.2",
"eslint-plugin-node": "~11.1.0",
"eslint-plugin-promise": "~5.2.0",
"eslint-plugin-simple-import-sort": "~10.0.0",
"eslint-plugin-vue": "~8.0.3",
"file-loader": "~6.2.0",
"html-webpack-plugin": "~5.5.0",
"mini-css-extract-plugin": "~2.4.5",
"node-loader": "~2.0.0",
"playwright": "~1.21.1",
"playwright-core": "~1.21.1",
"playwright": "~1.28.1",
"playwright-core": "~1.28.1",
"postcss-html": "~1.5.0",
"progress-webpack-plugin": "~1.0.12",
"rimraf": "~3.0.2",
"sass": "~1.42.1",
"sass-loader": "~12.3.0",
"standard-version": "~9.3.1",
"style-loader": "~3.3.1",
"stylelint": "~13.13.1",
"stylelint-config-standard": "~22.0.0",
"stylelint-scss": "~3.21.0",
"stylelint": "^15.11.0",
"stylelint-config-recommended-vue": "~1.5.0",
"stylelint-config-standard": "~34.0.0",
"stylelint-scss": "~5.3.0",
"tree-kill": "~1.2.2",
"ts-loader": "~9.2.8",
"ts-node": "~10.9.1",
"typescript": "~4.6.3",
"unzip-crx-3": "~0.2.0",
"vue-eslint-parser": "~8.3.0",
"vue-loader": "~16.8.3",
"webpack": "~5.72.0",
"webpack-cli": "~4.9.1",
"webpack-dev-server": "~4.4.0",
"webpack-dev-server": "~4.11.1",
"xvfb-maybe": "~0.2.1"
}
}

View File

@@ -114,7 +114,6 @@ function startRenderer (callback) {
});
const server = new WebpackDevServer(compiler, {
hot: true,
port: 9080,
client: {
overlay: true,

View File

@@ -1,4 +1,5 @@
// @ts-check
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
const fs = require('fs');
const path = require('path');
const https = require('https');

View File

@@ -0,0 +1,45 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { enUS } from '../src/renderer/i18n/en-US';
import { localesNames } from '../src/renderer/i18n/supported-locales';
const locale = process.argv[2];
let fullCount = 0;
let checkCount = 0;
if (!locale) {
console.log('Please specify locale code as first argument.');
process.exit();
}
if (!Object.keys(localesNames).includes(locale)) {
console.log(`Translation ${locale} not fount in supported locales.`);
process.exit();
}
console.log('Checking missing translations for:', locale);
const i18nFile = require(`../src/renderer/i18n/${locale}`)[locale.replace('-', '')];
for (const group in enUS) {
// @ts-ignore
fullCount += Object.keys(enUS[group]).length;
if (!Object.keys(i18nFile).includes(group)) {
console.log(`Group "\u001b[31m${group}\u001b[0m" missing!`);
continue;
}
// @ts-ignore
for (const term in enUS[group]) {
if (!Object.keys(i18nFile[group]).includes(term))
console.log(`Translation "\u001b[33m${group}.${term}\u001b[0m" missing!`);
// @ts-ignore
else if (i18nFile[group][term] === enUS[group][term]) {
console.log(`Term "\u001b[36m${group}.${term}\u001b[0m" not translated!`);
checkCount++;
}
else
checkCount++;
}
}
console.log(checkCount, 'of', fullCount, 'strings are present in', locale, `(\u001b[32m${(checkCount*100/fullCount).toFixed(1)}%\u001b[0m)`);

View File

@@ -4,7 +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.
base: core20
base: core22
grade: stable
confinement: strict
@@ -31,10 +31,10 @@ parts:
fi
# Get the latest releases json
echo "Get GitHub releases..."
wget --quiet https://api.github.com/repos/fabio286/antares/releases/latest -O releases.json
wget --quiet https://api.github.com/repos/fabio286/antares/releases -O releases.json
# Get the version from the tag_name and the download URL.
VERSION=$(jq . releases.json | grep tag_name | cut -d'"' -f4 | sed s'/release-//')
DEB_URL=$(cat releases.json | jq -r ".assets[] | select(.name | test(\"${FILTER}\")) | .browser_download_url")
VERSION=$(jq . releases.json | grep tag_name | head -1 | cut -d'"' -f4 | sed s'/release-//')
DEB_URL=$(cat releases.json | jq -r ".[0].assets[] | select(.name | test(\"${FILTER}\")) | .browser_download_url")
DEB=$(basename "${DEB_URL}")
echo "Downloading ${DEB_URL}..."
wget --quiet "${DEB_URL}" -O "${SNAPCRAFT_PART_INSTALL}/${DEB}"
@@ -79,7 +79,7 @@ parts:
- libdb5.3
- libdbus-1-3
- libexpat1
- libffi7
- libffi8
- libgcc-s1
- libgcrypt20
- libglib2.0-0
@@ -87,9 +87,9 @@ parts:
- libgnutls30
- libgpg-error0
- libgssapi-krb5-2
- libhogweed5
- libhogweed6
- libidn2-0
- libjson-c4
- libjson-c5
- libk5crypto3
- libkeyutils1
- libkrb5-3
@@ -97,12 +97,12 @@ parts:
- liblz4-1
- liblzma5
- libmount1
- libnettle7
- libnettle8
- libp11-kit0
- libpcre2-8-0
- libselinux1
- libsqlite3-0
- libssl1.1
- libssl3
- libstdc++6
- libsystemd0
- libtasn1-6
@@ -119,10 +119,10 @@ parts:
cleanup:
after: [antares]
plugin: nil
build-snaps: [gnome-3-38-2004]
build-snaps: [gnome-42-2204]
override-prime: |
set -eux
cd /snap/gnome-3-38-2004/current
cd /snap/gnome-42-2204/current
find . -type f,l -exec rm -f $SNAPCRAFT_PRIME/{} \;
mdns-lookup:
@@ -136,7 +136,7 @@ parts:
- libnss-mdns
override-prime: |
set -eux
sed -Ee 's/^\s*hosts:(\s+)files/hosts:\1files mdns4_minimal \[NOTFOUND=return\]/' /snap/core20/current/etc/nsswitch.conf > $SNAPCRAFT_STAGE/etc/nsswitch.conf
sed -Ee 's/^\s*hosts:(\s+)files/hosts:\1files mdns4_minimal \[NOTFOUND=return\]/' /snap/core22/current/etc/nsswitch.conf > $SNAPCRAFT_STAGE/etc/nsswitch.conf
snapcraftctl prime
prime:
- lib/$SNAPCRAFT_ARCH_TRIPLET/libnss_mdns4_minimal*
@@ -146,10 +146,7 @@ apps:
antares:
command: opt/Antares/antares --no-sandbox
desktop: usr/share/applications/antares.desktop
extensions: [gnome-3-38]
environment:
# Fallback to XWayland if running in a Wayland session.
DISABLE_WAYLAND: 1
extensions: [gnome]
plugs:
- browser-support
- cups-control

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export default class {
static get _methods () {
return [
@@ -50,6 +51,7 @@ export default class {
{ name: 'collation', group: 'database', types: ['string'] },
{ name: 'engine', group: 'database', types: ['string'] },
{ name: 'now', group: 'date', types: ['string', 'datetime'] },
{ name: 'past', group: 'date', types: ['string', 'datetime'] },
{ name: 'future', group: 'date', types: ['string', 'datetime'] },
// { name: 'between', group: 'date', types: ['string'] },
@@ -139,7 +141,7 @@ export default class {
{ name: 'arrayElement', group: 'random', types: ['string'] },
{ name: 'arrayElements', group: 'random', types: ['string'] },
{ name: 'objectElement', group: 'random', types: ['string'] },
{ name: 'uuid', group: 'random', types: ['string'] },
{ name: 'uuid', group: 'random', types: ['string', 'uuid'] },
{ name: 'boolean', group: 'random', types: ['string'] },
{ name: 'word', group: 'random', types: ['string'] },
{ name: 'words', group: 'random', types: ['string'] },
@@ -160,7 +162,9 @@ export default class {
{ name: 'filePath', group: 'system', types: ['string'] },
{ name: 'semver', group: 'system', types: ['string'] },
{ name: 'now', group: 'time', types: ['string', 'time'] },
{ name: 'recent', group: 'time', types: ['string', 'time'] },
{ name: 'random', group: 'time', types: ['string', 'time'] },
{ name: 'vehicle', group: 'vehicle', types: ['string'] },
{ name: 'manufacturer', group: 'vehicle', types: ['string'] },
@@ -180,7 +184,7 @@ export default class {
acc[curr.group] = new Set(curr.types);
return acc;
}, {});
}, {} as any);
const groupsArr = [];
@@ -198,12 +202,12 @@ export default class {
});
}
static getGroupsByType (type) {
static getGroupsByType (type: string) {
if (!type) return [];
return this.getGroups().filter(group => group.types.includes(type));
}
static getMethods ({ type, group }) {
static getMethods ({ type, group }: {type: string; group: string}) {
return this._methods.filter(method => method.group === group && method.types.includes(type)).sort((a, b) => {
if (a.name < b.name)
return -1;

View File

@@ -1,10 +1,15 @@
import { Customizations } from '../interfaces/customizations';
// Everything OFF
export const defaults: Customizations = {
// Defaults
defaultPort: null,
defaultUser: null,
defaultDatabase: null,
dataTypes: [],
indexTypes: [],
foreignActions: [],
operators: ['=', '!=', '>', '<', '>=', '<=', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE', 'BETWEEN', 'IS NULL', 'IS NOT NULL'],
// Core
database: false,
collations: false,
@@ -27,11 +32,12 @@ export const defaults: Customizations = {
routines: false,
functions: false,
schedulers: false,
// Settings
// Misc
elementsWrapper: '',
stringsWrapper: '"',
tableAdd: false,
tableTruncateDisableFKCheck: false,
tableDdl: false,
viewAdd: false,
triggerAdd: false,
triggerFunctionAdd: false,
@@ -45,9 +51,9 @@ export const defaults: Customizations = {
exportByChunks: false,
schemaImport: false,
tableSettings: false,
tableOptions: false,
tableArray: false,
tableRealCount: false,
tableDuplicate: false,
viewSettings: false,
triggerSettings: false,
triggerFunctionSettings: false,
@@ -73,6 +79,7 @@ export const defaults: Customizations = {
procedureDataAccess: false,
procedureSql: null,
procedureContext: false,
procedureContextValues: [],
procedureLanguage: false,
functionDeterministic: false,
functionDataAccess: false,

View File

@@ -0,0 +1,63 @@
import firebirdTypes from '../data-types/firebird';
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
export const customizations: Customizations = {
...defaults,
// Defaults
defaultPort: 3050,
defaultUser: 'SYSDBA',
defaultDatabase: null,
dataTypes: firebirdTypes,
indexTypes: [
'PRIMARY',
// 'CHECK',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'NO ACTION',
'CASCADE',
'SET NULL',
'SET DEFAULT'
],
// Core
database: true,
collations: false,
engines: false,
connectionSchema: false,
sslConnection: false,
sshConnection: false,
fileConnection: false,
cancelQueries: false,
// Tools
processesList: false,
usersManagement: false,
variables: false,
// Structure
schemas: false,
tables: true,
views: true,
triggers: true,
routines: true,
functions: false,
// Settings
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableSettings: true,
tableRealCount: true,
viewAdd: true,
viewSettings: true,
triggerAdd: true,
triggerMultipleEvents: true,
triggerSql: 'BEGIN\r\n\r\nEND',
routineAdd: true,
procedureContext: true,
procedureContextValues: ['IN', 'OUT'],
procedureSql: 'BEGIN\r\n\r\nEND',
parametersLength: true,
indexes: true,
foreigns: true,
nullable: true
};

View File

@@ -1,3 +1,4 @@
import * as firebird from 'common/customizations/firebird';
import * as mysql from 'common/customizations/mysql';
import * as postgresql from 'common/customizations/postgresql';
import * as sqlite from 'common/customizations/sqlite';
@@ -7,10 +8,12 @@ export default {
maria: mysql.customizations,
mysql: mysql.customizations,
pg: postgresql.customizations,
sqlite: sqlite.customizations
sqlite: sqlite.customizations,
firebird: firebird.customizations
} as {
maria: Customizations;
mysql: Customizations;
pg: Customizations;
sqlite: Customizations;
firebird: Customizations;
};

View File

@@ -1,3 +1,4 @@
import mysqlTypes from '../data-types/mysql';
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
@@ -7,6 +8,20 @@ export const customizations: Customizations = {
defaultPort: 3306,
defaultUser: 'root',
defaultDatabase: null,
dataTypes: mysqlTypes,
operators: ['=', '!=', '>', '<', '>=', '<=', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE', 'RLIKE', 'NOT RLIKE', 'BETWEEN', 'IS NULL', 'IS NOT NULL'],
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE',
'FULLTEXT'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
connectionSchema: true,
collations: true,
@@ -29,6 +44,8 @@ export const customizations: Customizations = {
stringsWrapper: '"',
tableAdd: true,
tableTruncateDisableFKCheck: true,
tableDuplicate: true,
tableDdl: true,
viewAdd: true,
triggerAdd: true,
routineAdd: true,
@@ -51,7 +68,6 @@ export const customizations: Customizations = {
unsigned: true,
nullable: true,
zerofill: true,
tableOptions: true,
autoIncrement: true,
comment: true,
collation: true,
@@ -64,6 +80,7 @@ export const customizations: Customizations = {
procedureDataAccess: true,
procedureSql: 'BEGIN\r\n\r\nEND',
procedureContext: true,
procedureContextValues: ['IN', 'OUT', 'INOUT'],
triggerSql: 'BEGIN\r\n\r\nEND',
functionDeterministic: true,
functionDataAccess: true,

View File

@@ -1,3 +1,4 @@
import postgresqlTypes from '../data-types/postgresql';
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
@@ -7,6 +8,18 @@ export const customizations: Customizations = {
defaultPort: 5432,
defaultUser: 'postgres',
defaultDatabase: 'postgres',
dataTypes: postgresqlTypes,
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
database: true,
sslConnection: true,
@@ -22,10 +35,12 @@ export const customizations: Customizations = {
triggerFunctions: true,
routines: true,
functions: true,
// Settings
// Misc
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableDuplicate: true,
tableDdl: true,
viewAdd: true,
triggerAdd: true,
triggerFunctionAdd: true,
@@ -47,6 +62,7 @@ export const customizations: Customizations = {
tableArray: true,
procedureSql: '$procedure$\r\n\r\n$procedure$',
procedureContext: true,
procedureContextValues: ['IN', 'OUT', 'INOUT'],
procedureLanguage: true,
functionSql: '$function$\r\n\r\n$function$',
triggerFunctionSql: '$function$\r\nBEGIN\r\n\r\nEND\r\n$function$',

View File

@@ -1,8 +1,21 @@
import sqliteTypes from '../data-types/sqlite';
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
export const customizations: Customizations = {
...defaults,
dataTypes: sqliteTypes,
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
fileConnection: true,
// Structure
@@ -14,6 +27,7 @@ export const customizations: Customizations = {
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableDuplicate: true,
viewAdd: true,
triggerAdd: true,
schemaEdit: false,

View File

@@ -0,0 +1,136 @@
import { TypesGroup } from 'common/interfaces/antares';
export default [
{
group: 'integer',
types: [
{
name: 'SMALLINT',
length: false,
collation: false,
unsigned: true,
zerofill: true
},
{
name: 'INTEGER',
length: false,
collation: false,
unsigned: true,
zerofill: true
},
{
name: 'BIGINT',
length: false,
collation: false,
unsigned: true,
zerofill: true
}
]
},
{
group: 'float',
types: [
{
name: 'DECIMAL',
length: true,
scale: true,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'NUMERIC',
length: true,
scale: true,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'FLOAT',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'DOUBLE PRECISION',
length: false,
collation: false,
unsigned: false,
zerofill: false
}
]
},
{
group: 'string',
types: [
{
name: 'CHAR',
length: true,
collation: true,
unsigned: false,
zerofill: false
},
{
name: 'VARCHAR',
length: true,
collation: true,
unsigned: false,
zerofill: false
},
{
name: 'BLOB-TEXT',
length: false,
collation: true,
unsigned: false,
zerofill: false
}
]
},
{
group: 'binary',
types: [
{
name: 'BLOB',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'CHAR-BINARY',
length: false,
collation: false,
unsigned: false,
zerofill: false
}
]
},
{
group: 'time',
types: [
{
name: 'DATE',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'TIME',
length: true,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'TIMESTAMP',
length: false,
collation: false,
unsigned: false,
zerofill: false
}
]
}
] as TypesGroup[];

View File

@@ -54,6 +54,7 @@ export default [
{
name: 'FLOAT',
length: true,
scale: true,
collation: false,
unsigned: false,
zerofill: false

View File

@@ -6,7 +6,7 @@ export default [
types: [
{
name: 'INT',
length: true,
length: 10,
collation: false,
unsigned: true,
zerofill: true
@@ -18,6 +18,13 @@ export default [
unsigned: true,
zerofill: true
},
{
name: 'INTEGER UNSIGNED',
length: true,
collation: false,
unsigned: true,
zerofill: true
},
{
name: 'BIGINT',
length: true,

View File

@@ -10,7 +10,8 @@ export const LONG_TEXT = [
'MEDIUMTEXT',
'LONGTEXT',
'JSON',
'VARBINARY'
'VARBINARY',
'BLOB-TEXT'
];
export const ARRAY = [
@@ -29,14 +30,14 @@ export const NUMBER = [
'SMALLINT',
'MEDIUMINT',
'BIGINT',
'DECIMAL',
'NUMERIC',
'INTEGER',
'SMALLSERIAL',
'SERIAL',
'BIGSERIAL',
'OID',
'XID'
'XID',
'INT64'
];
export const FLOAT = [
@@ -48,6 +49,12 @@ export const FLOAT = [
'MONEY'
];
export const IS_BIGINT = [
'BIGINT',
'BIGSERIAL',
'DOUBLE PRECISION'
];
export const BOOLEAN = [
'BOOL',
'BOOLEAN'
@@ -78,7 +85,9 @@ export const BLOB = [
'TINYBLOB',
'MEDIUMBLOB',
'LONGBLOB',
'BYTEA'
'LONG_BLOB',
'BYTEA',
'CHAR-BINARY'
];
export const BIT = [
@@ -86,6 +95,14 @@ export const BIT = [
'BIT VARYING'
];
export const BINARY = [
'BINARY'
];
export const UUID = [
'UUID'
];
export const SPATIAL = [
'POINT',
'LINESTRING',

View File

@@ -1,6 +0,0 @@
export default [
'PRIMARY',
'INDEX',
'UNIQUE',
'FULLTEXT'
];

View File

@@ -1,5 +0,0 @@
export default [
'PRIMARY',
'INDEX',
'UNIQUE'
];

View File

@@ -1,5 +0,0 @@
export default [
'PRIMARY',
'INDEX',
'UNIQUE'
];

View File

@@ -1,16 +1,18 @@
import SSHConfig from '@fabio286/ssh2-promise/lib/sshConfig';
import * as mysql from 'mysql2/promise';
import * as pg from 'pg';
import { FirebirdSQLClient } from 'src/main/libs/clients/FirebirdSQLClient';
import MysqlExporter from 'src/main/libs/exporters/sql/MysqlExporter';
import PostgreSQLExporter from 'src/main/libs/exporters/sql/PostgreSQLExporter';
import MySQLImporter from 'src/main/libs/importers/sql/MySQLlImporter';
import PostgreSQLImporter from 'src/main/libs/importers/sql/PostgreSQLImporter';
import SSHConfig from 'ssh2-promise/lib/sshConfig';
import { MySQLClient } from '../../main/libs/clients/MySQLClient';
import { PostgreSQLClient } from '../../main/libs/clients/PostgreSQLClient';
import { SQLiteClient } from '../../main/libs/clients/SQLiteClient';
export type Client = MySQLClient | PostgreSQLClient | SQLiteClient
export type ClientCode = 'mysql' | 'maria' | 'pg' | 'sqlite'
export type Client = MySQLClient | PostgreSQLClient | SQLiteClient | FirebirdSQLClient
export type ClientCode = 'mysql' | 'maria' | 'pg' | 'sqlite' | 'firebird'
export type Exporter = MysqlExporter | PostgreSQLExporter
export type Importer = MySQLImporter | PostgreSQLImporter
@@ -63,6 +65,7 @@ export interface ConnectionParams {
sshKey?: string;
sshPort?: number;
sshPassphrase?: string;
sshKeepAliveInterval?: number;
}
export interface TypeInformations {
@@ -84,13 +87,11 @@ export interface TableInfos {
name: string;
type: string;
rows: number;
created: Date;
updated: Date;
engine: string;
comment: string;
size: number | false;
autoIncrement: number;
collation: string;
autoIncrement?: boolean;
}
export type TableOptions = Partial<TableInfos>;
@@ -362,8 +363,7 @@ export interface QueryBuilderObject {
offset: number;
join: string[];
update: string[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
insert: {[key: string]: any}[];
insert: {[key: string]: string | boolean | number }[];
delete: boolean;
}

View File

@@ -1,8 +1,15 @@
import { TypesGroup } from './antares';
import { TableFilterOperator } from './tableApis';
export interface Customizations {
// Defaults
defaultPort?: number;
defaultUser?: string;
defaultDatabase?: string;
dataTypes?: TypesGroup[];
indexTypes?: string[];
foreignActions?: string[];
operators?: TableFilterOperator[];
// Core
database?: boolean;
collations?: boolean;
@@ -25,15 +32,16 @@ export interface Customizations {
routines?: boolean;
functions?: boolean;
schedulers?: boolean;
// Settings
// Misc
elementsWrapper: string;
stringsWrapper: string;
tableAdd?: boolean;
tableSettings?: boolean;
tableOptions?: boolean;
tableDuplicate?: boolean;
tableArray?: boolean;
tableRealCount?: boolean;
tableTruncateDisableFKCheck?: boolean;
tableDdl?: boolean;
viewAdd?: boolean;
viewSettings?: boolean;
triggerAdd?: boolean;
@@ -71,6 +79,7 @@ export interface Customizations {
procedureDataAccess?: boolean;
procedureSql?: string;
procedureContext?: boolean;
procedureContextValues?: string[];
procedureLanguage?: boolean;
functionDeterministic?: boolean;
functionDataAccess?: boolean;

View File

@@ -21,10 +21,12 @@ export interface TableDeleteParams {
rows: {[key: string]: any};
}
export type TableFilterOperator = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'RLIKE' | 'NOT RLIKE' | 'BETWEEN' | 'IS NULL' | 'IS NOT NULL'
export interface TableFilterClausole {
active: boolean;
field: string;
op: '=' | '!=' | '>' | '<' | '>=' | '<=' | 'IN' | 'NOT IN' | 'LIKE' | 'BETWEEN' | 'IS NULL' | 'IS NOT NULL';
op:TableFilterOperator;
value: '';
value2: '';
}

View File

@@ -1,5 +1,5 @@
export function bufferToBase64 (buf: Buffer) {
const binstr = Array.prototype.map.call(buf, ch => {
const binstr = Array.prototype.map.call(buf, (ch: number) => {
return String.fromCharCode(ch);
}).join('');
return Buffer.from(binstr, 'binary').toString('base64');

View File

@@ -0,0 +1,28 @@
import * as crypto from 'crypto';
const algorithm = 'aes-256-gcm';
function encrypt (text: string, password: string) {
const iv = crypto.randomBytes(16);
const key = crypto.scryptSync(password, 'antares', 32);
const cipher = crypto.createCipheriv(algorithm, key, iv);
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
const authTag = cipher.getAuthTag();
return {
iv: iv.toString('hex'),
authTag: authTag.toString('hex'),
content: encrypted.toString('hex')
};
}
function decrypt (hash: { iv: string; content: string; authTag: string }, password: string) {
const key = crypto.scryptSync(password, 'antares', 32);
const decipher = crypto.createDecipheriv(algorithm, key, Buffer.from(hash.iv, 'hex'));
decipher.setAuthTag(Buffer.from(hash.authTag, 'hex'));
const decrpyted = decipher.update(hash.content, 'hex', 'utf8') + decipher.final('utf8');
return decrpyted;
}
export { decrypt, encrypt };

View File

@@ -0,0 +1,17 @@
import { faker } from '@faker-js/faker';
import * as moment from 'moment';
export const fakerCustom = {
seed: faker.seed,
setLocale: faker.setLocale,
...faker,
date: {
now: () => moment().format('YYYY-MM-DD HH:mm:ss'),
...faker.date
},
time: {
now: () => moment().format('HH:mm:ss'),
random: () => moment(faker.date.recent()).format('HH:mm:ss'),
...faker.time
}
};

View File

@@ -176,7 +176,7 @@ function isMD (str: string) {
}
export function langDetector (str: string) {
if (!str.trim().length)
if (!str || !str.trim().length)
return 'text';
if (isJSON(str))
return 'json';

View File

@@ -1,12 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-useless-escape */
import * as moment from 'moment';
import { lineString, point, polygon } from '@turf/helpers';
import { BIT, BLOB, DATE, DATETIME, FLOAT, IS_MULTI_SPATIAL, NUMBER, SPATIAL, TEXT_SEARCH } from 'common/fieldTypes';
import * as moment from 'moment';
import customizations from '../customizations';
import { ClientCode } from '../interfaces/antares';
import { BLOB, BIT, DATE, DATETIME, FLOAT, SPATIAL, IS_MULTI_SPATIAL, NUMBER, TEXT_SEARCH } from 'common/fieldTypes';
import hexToBinary, { HexChar } from './hexToBinary';
import { getArrayDepth } from './getArrayDepth';
import hexToBinary, { HexChar } from './hexToBinary';
/**
* Escapes a string fo SQL use
@@ -72,7 +73,7 @@ export const escapeAndQuote = (val: string, client: ClientCode) => {
export const valueToSqlString = (args: {
val: any;
client: ClientCode;
field: {type: string; datePrecision: number};
field: {type: string; datePrecision?: number; precision?: number | false; isArray?: boolean};
}): string => {
let parsedValue;
const { val, client, field } = args;
@@ -94,7 +95,7 @@ export const valueToSqlString = (args: {
? escapeAndQuote(moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`), client)
: escapeAndQuote(val, client);
}
else if ('isArray' in field) {
else if ('isArray' in field && field.isArray) {
let localVal;
if (Array.isArray(val))
localVal = JSON.stringify(val).replaceAll('[', '{').replaceAll(']', '}');
@@ -105,12 +106,18 @@ export const valueToSqlString = (args: {
else if (TEXT_SEARCH.includes(field.type))
parsedValue = `'${val.replaceAll('\'', '\'\'')}'`;
else if (BIT.includes(field.type))
parsedValue = `b'${hexToBinary(Buffer.from(val).toString('hex') as undefined as HexChar[])}'`;
parsedValue = `b'${hexToBinary(Buffer.from(new Uint8Array(Object.values(val))).toString('hex') as undefined as HexChar[])}'`;
else if (BLOB.includes(field.type)) {
let buffer: Buffer;
if (val instanceof Uint8Array)
buffer = Buffer.from(val);
else
buffer = val;
if (['mysql', 'maria'].includes(client))
parsedValue = `X'${val.toString('hex').toUpperCase()}'`;
parsedValue = `X'${buffer.toString('hex').toUpperCase()}'`;
else if (client === 'pg')
parsedValue = `decode('${val.toString('hex').toUpperCase()}', 'hex')`;
parsedValue = `decode('${buffer.toString('hex').toUpperCase()}', 'hex')`;
}
else if (NUMBER.includes(field.type))
parsedValue = val;
@@ -146,17 +153,47 @@ export const valueToSqlString = (args: {
};
export const jsonToSqlInsert = (args: {
json: { [key: string]: any};
json: { [key: string]: any}[];
client: ClientCode;
fields: { [key: string]: {type: string; datePrecision: number}};
table: string;
options?: {sqlInsertAfter: number; sqlInsertDivider: 'bytes' | 'rows'};
}) => {
const { client, json, fields, table } = args;
const { client, json, fields, table, options } = args;
const sqlInsertAfter = options && options.sqlInsertAfter ? options.sqlInsertAfter : 1;
const sqlInsertDivider = options && options.sqlInsertDivider ? options.sqlInsertDivider : 'rows';
const { elementsWrapper: ew } = customizations[client];
const fieldNames = Object.keys(json).map(key => `${ew}${key}${ew}`);
const values = Object.keys(json).map(key => (
valueToSqlString({ val: json[key], client, field: fields[key] })
));
const fieldNames = Object.keys(json[0]).map(key => `${ew}${key}${ew}`);
let insertStmt = `INSERT INTO ${ew}${table}${ew} (${fieldNames.join(', ')}) VALUES `;
let insertsString = '';
let queryLength = 0;
let rowsWritten = 0;
return `INSERT INTO ${ew}${table}${ew} (${fieldNames.join(', ')}) VALUES (${values.join(', ')});`;
for (const row of json) {
const values = [];
values.push(Object.keys(row).map(key => (
valueToSqlString({ val: row[key], client, field: fields[key] })
)));
if (
(sqlInsertDivider === 'bytes' && queryLength >= sqlInsertAfter * 1024) ||
(sqlInsertDivider === 'rows' && rowsWritten === sqlInsertAfter)
) {
insertsString += insertStmt+';';
insertStmt = `\nINSERT INTO ${ew}${table}${ew} (${fieldNames.join(', ')}) VALUES `;
rowsWritten = 0;
}
rowsWritten++;
if (rowsWritten > 1) insertStmt += ',\n';
insertStmt += `(${values.join(',')})`;
queryLength = insertStmt.length;
}
if (rowsWritten > 0)
insertsString += insertStmt+';';
return insertsString;
};

View File

@@ -1,3 +1,3 @@
export function uidGen (prefix?: string) {
return (prefix ? `${prefix}:` : '') + Math.random().toString(36).substr(2, 9).toUpperCase();
return (prefix ? `${prefix}:` : '') + Math.random().toString(36).substring(2, 11).toUpperCase();
}

View File

@@ -1,69 +1,138 @@
export const shortcutEvents: { [key: string]: { l18n: string; l18nParam?: string | number; context?: 'tab' }} = {
'run-or-reload': { l18n: 'application.runOrReload', context: 'tab' },
'open-new-tab': { l18n: 'application.openNewTab', context: 'tab' },
'close-tab': { l18n: 'application.closeTab', context: 'tab' },
'format-query': { l18n: 'database.formatQuery', context: 'tab' },
'kill-query': { l18n: 'database.killQuery', context: 'tab' },
'query-history': { l18n: 'database.queryHistory', context: 'tab' },
'clear-query': { l18n: 'database.clearQuery', context: 'tab' },
'next-tab': { l18n: 'application.nextTab' },
'prev-tab': { l18n: 'application.previousTab' },
'open-all-connections': { l18n: 'application.openAllConnections' },
'open-filter': { l18n: 'application.openFilter' },
'next-page': { l18n: 'application.nextResultsPage' },
'prev-page': { l18n: 'application.previousResultsPage' },
'toggle-console': { l18n: 'application.toggleConsole' },
'save-content': { l18n: 'application.saveContent' },
'create-connection': { l18n: 'connection.createNewConnection' },
'open-settings': { l18n: 'application.openSettings' },
'open-scratchpad': { l18n: 'application.openScratchpad' }
};
interface ShortcutRecord {
event: string;
keys: Electron.Accelerator[];
description: string;
keys: Electron.Accelerator[] | string[];
/** Needed for default shortcuts */
os: NodeJS.Platform[];
}
/**
* Default shortcuts
*/
const shortcuts: ShortcutRecord[] = [
{
event: 'run-or-reload',
keys: ['F5'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'save-content',
keys: ['CommandOrControl+S'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'kill-query',
keys: ['CommandOrControl+K'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'format-query',
keys: ['CommandOrControl+B'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'clear-query',
keys: ['CommandOrControl+Alt+W'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'query-history',
keys: ['CommandOrControl+G'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'open-new-tab',
keys: ['CommandOrControl+T'],
description: 'Open a new query tab',
os: ['darwin', 'linux', 'win32']
},
{
event: 'close-tab',
keys: ['CommandOrControl+W'],
description: 'Close tab',
os: ['darwin', 'linux', 'win32']
},
{
event: 'next-tab',
keys: ['Alt+CommandOrControl+Right', 'CommandOrControl+PageDown'],
description: 'Next tab',
keys: ['Alt+CommandOrControl+Right'],
os: ['darwin', 'win32']
},
{
event: 'prev-tab',
keys: ['Alt+CommandOrControl+Left', 'CommandOrControl+PageUp'],
description: 'Previous tab',
keys: ['Alt+CommandOrControl+Left'],
os: ['darwin', 'win32']
},
{
event: 'next-tab',
keys: ['CommandOrControl+PageDown'],
description: 'Next tab',
os: ['linux']
os: ['linux', 'win32']
},
{
event: 'prev-tab',
keys: ['CommandOrControl+PageUp'],
description: 'Previous tab',
os: ['linux']
os: ['linux', 'win32']
},
{
event: 'open-connections-modal',
event: 'open-filter',
keys: ['CommandOrControl+F'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'next-page',
keys: ['CommandOrControl+Right'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'prev-page',
keys: ['CommandOrControl+Left'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'open-all-connections',
keys: ['Shift+CommandOrControl+Space'],
description: 'Show all connections',
os: ['darwin', 'linux', 'win32']
},
{
event: 'toggle-console',
keys: ['CommandOrControl+F12', 'CommandOrControl+`'],
description: 'Toggle console',
keys: ['CommandOrControl+F12'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'toggle-console',
keys: ['CommandOrControl+`'],
os: ['darwin', 'linux', 'win32']
}
];
for (let i = 1; i <= 9; i++) {
shortcuts.push(
{
event: `select-tab-${i}`,
keys: [`CommandOrControl+${i}`],
description: `Select tab number ${i}`,
os: ['darwin', 'linux', 'win32']
});
shortcutEvents[`select-tab-${i}`] = {
l18n: 'application.selectTabNumber',
l18nParam: i
};
shortcuts.push({
event: `select-tab-${i}`,
keys: [`CommandOrControl+${i}`],
os: ['darwin', 'linux', 'win32']
});
}
export { shortcuts, ShortcutRecord };
export { ShortcutRecord, shortcuts };

View File

@@ -1,15 +1,45 @@
import { app, ipcMain, dialog } from 'electron';
import { app, dialog, ipcMain } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
import { ShortcutRegister } from '../libs/ShortcutRegister';
export default () => {
ipcMain.on('close-app', () => {
ipcMain.on('close-app', (event) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
app.exit();
});
ipcMain.handle('show-open-dialog', (event, options) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
return dialog.showOpenDialog(options);
});
ipcMain.handle('get-download-dir-path', () => {
ipcMain.handle('get-download-dir-path', (event) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
return app.getPath('downloads');
});
ipcMain.handle('resotre-default-shortcuts', (event) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
const shortCutRegister = ShortcutRegister.getInstance();
shortCutRegister.restoreDefaults();
});
ipcMain.handle('reload-shortcuts', (event) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
const shortCutRegister = ShortcutRegister.getInstance();
shortCutRegister.reload();
});
ipcMain.handle('update-shortcuts', (event, shortcuts) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
const shortCutRegister = ShortcutRegister.getInstance();
shortCutRegister.updateShortcuts(shortcuts);
});
ipcMain.handle('unregister-shortcuts', (event) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
const shortCutRegister = ShortcutRegister.getInstance();
shortCutRegister.unregister();
});
};

View File

@@ -1,11 +1,15 @@
import * as antares from 'common/interfaces/antares';
import * as fs from 'fs';
import { ipcMain } from 'electron';
import { ClientsFactory } from '../libs/ClientsFactory';
import * as fs from 'fs';
import { SslOptions } from 'mysql2';
import { ClientsFactory } from '../libs/ClientsFactory';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('test-connection', async (event, conn: antares.ConnectionParams) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
const params = {
host: conn.host,
port: +conn.port,
@@ -23,6 +27,7 @@ export default (connections: {[key: string]: antares.Client}) => {
port: number;
privateKey: string;
passphrase: string;
keepaliveInterval: number;
}
};
@@ -49,7 +54,8 @@ export default (connections: {[key: string]: antares.Client}) => {
password: conn.sshPass,
port: conn.sshPort ? conn.sshPort : 22,
privateKey: conn.sshKey ? fs.readFileSync(conn.sshKey).toString() : null,
passphrase: conn.sshPassphrase
passphrase: conn.sshPassphrase,
keepaliveInterval: conn.sshKeepAliveInterval ? conn.sshKeepAliveInterval*1000 : null
};
}
@@ -61,7 +67,11 @@ export default (connections: {[key: string]: antares.Client}) => {
});
await connection.connect();
await connection.select('1+1').run();
if (conn.client === 'firebird')
connection.raw('SELECT rdb$get_context(\'SYSTEM\', \'DB_NAME\') FROM rdb$database');
else
await connection.select('1+1').run();
connection.destroy();
return { status: 'success' };
@@ -76,6 +86,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('connect', async (event, conn: antares.ConnectionParams) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
const params = {
host: conn.host,
port: +conn.port,
@@ -94,6 +106,7 @@ export default (connections: {[key: string]: antares.Client}) => {
port: number;
privateKey: string;
passphrase: string;
keepaliveInterval: number;
}
};
@@ -123,7 +136,8 @@ export default (connections: {[key: string]: antares.Client}) => {
password: conn.sshPass,
port: conn.sshPort ? conn.sshPort : 22,
privateKey: conn.sshKey ? fs.readFileSync(conn.sshKey).toString() : null,
passphrase: conn.sshPassphrase
passphrase: conn.sshPassphrase,
keepaliveInterval: conn.sshKeepAliveInterval ? conn.sshKeepAliveInterval*1000 : null
};
}
@@ -149,6 +163,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('disconnect', (event, uid) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
connections[uid].destroy();
delete connections[uid];
});

View File

@@ -0,0 +1,18 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-databases', async (event, uid) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[uid].getDatabases();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
};

View File

@@ -1,8 +1,12 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-function-informations', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getFunctionInformations(params);
return { status: 'success', response: result };
@@ -13,6 +17,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('drop-function', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].dropFunction(params);
return { status: 'success' };
@@ -23,6 +29,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('alter-function', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].alterFunction(params);
return { status: 'success' };
@@ -33,6 +41,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('alter-trigger-function', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].alterTriggerFunction(params);
return { status: 'success' };
@@ -43,6 +53,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('create-function', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].createFunction(params);
return { status: 'success' };
@@ -53,6 +65,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('create-trigger-function', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].createTriggerFunction(params);
return { status: 'success' };

View File

@@ -1,16 +1,17 @@
import * as antares from 'common/interfaces/antares';
import connection from './connection';
import tables from './tables';
import views from './views';
import triggers from './triggers';
import routines from './routines';
import functions from './functions';
import schedulers from './schedulers';
import updates from './updates';
import application from './application';
import connection from './connection';
import database from './database';
import functions from './functions';
import routines from './routines';
import schedulers from './schedulers';
import schema from './schema';
import tables from './tables';
import triggers from './triggers';
import updates from './updates';
import users from './users';
import views from './views';
const connections: {[key: string]: antares.Client} = {};
@@ -22,6 +23,7 @@ export default () => {
routines(connections);
functions(connections);
schedulers(connections);
database(connections);
schema(connections);
users(connections);
updates();

View File

@@ -1,8 +1,12 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-routine-informations', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getRoutineInformations(params);
return { status: 'success', response: result };
@@ -13,6 +17,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('drop-routine', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].dropRoutine(params);
return { status: 'success' };
@@ -23,6 +29,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('alter-routine', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].alterRoutine(params);
return { status: 'success' };
@@ -33,6 +41,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('create-routine', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].createRoutine(params);
return { status: 'success' };

View File

@@ -1,8 +1,12 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-scheduler-informations', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getEventInformations(params);
return { status: 'success', response: result };
@@ -13,6 +17,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('drop-scheduler', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].dropEvent(params);
return { status: 'success' };
@@ -23,6 +29,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('alter-scheduler', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].alterEvent(params);
return { status: 'success' };
@@ -33,6 +41,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('create-scheduler', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].createEvent(params);
return { status: 'success' };
@@ -43,6 +53,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('toggle-scheduler', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
if (!params.enabled)
await connections[params.uid].enableEvent({ ...params });

View File

@@ -1,9 +1,11 @@
import { ChildProcess, fork } from 'child_process';
import * as antares from 'common/interfaces/antares';
import * as workers from 'common/interfaces/workers';
import { dialog, ipcMain } from 'electron';
import * as fs from 'fs';
import * as path from 'path';
import { ChildProcess, fork } from 'child_process';
import { ipcMain, dialog } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
const isDevelopment = process.env.NODE_ENV !== 'production';
@@ -12,6 +14,8 @@ export default (connections: {[key: string]: antares.Client}) => {
let importer: ChildProcess = null;
ipcMain.handle('create-schema', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].createSchema(params);
@@ -23,6 +27,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('update-schema', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].alterSchema(params);
@@ -34,6 +40,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('delete-schema', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].dropSchema(params);
@@ -45,6 +53,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-schema-collation', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const collation = await connections[params.uid].getDatabaseCollation(
params
@@ -61,8 +71,10 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-structure', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const structure = await connections[params.uid].getStructure(
const structure: unknown = await connections[params.uid].getStructure(
params.schemas
);
@@ -74,6 +86,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-collations', async (event, uid) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[uid].getCollations();
@@ -85,6 +99,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-variables', async (event, uid) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[uid].getVariables();
@@ -96,8 +112,10 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-engines', async (event, uid) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[uid].getEngines();
const result: unknown = await connections[uid].getEngines();
return { status: 'success', response: result };
}
@@ -107,6 +125,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-version', async (event, uid) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[uid].getVersion();
@@ -118,6 +138,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-processes', async (event, uid) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[uid].getProcesses();
@@ -129,6 +151,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('kill-process', async (event, { uid, pid }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[uid].killProcess(pid);
@@ -140,6 +164,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('use-schema', async (event, { uid, schema }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (!schema) return;
try {
@@ -152,6 +178,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('raw-query', async (event, { uid, query, schema, tabUid, autocommit }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (!query) return;
try {
@@ -160,8 +188,7 @@ export default (connections: {[key: string]: antares.Client}) => {
details: true,
schema,
tabUid,
autocommit,
comments: false
autocommit
});
return { status: 'success', response: result };
@@ -172,6 +199,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('export', (event, { uid, type, tables, ...rest }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (exporter !== null) {
exporter.kill();
return;
@@ -246,7 +275,9 @@ export default (connections: {[key: string]: antares.Client}) => {
});
});
ipcMain.handle('abort-export', async () => {
ipcMain.handle('abort-export', async (event) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
let willAbort = false;
if (exporter) {
@@ -268,6 +299,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('import-sql', async (event, options) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (importer !== null) {
importer.kill();
return;
@@ -319,7 +352,9 @@ export default (connections: {[key: string]: antares.Client}) => {
});
});
ipcMain.handle('abort-import-sql', async () => {
ipcMain.handle('abort-import-sql', async (event) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
let willAbort = false;
if (importer) {
@@ -341,6 +376,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('kill-tab-query', async (event, { uid, tabUid }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (!tabUid) return;
try {
@@ -353,6 +390,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('commit-tab', async (event, { uid, tabUid }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (!tabUid) return;
try {
@@ -365,6 +404,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('rollback-tab', async (event, { uid, tabUid }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (!tabUid) return;
try {
@@ -377,6 +418,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('destroy-connection-to-commit', async (event, { uid, tabUid }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (!tabUid) return;
try {

View File

@@ -1,15 +1,19 @@
import * as fs from 'fs';
import customizations from 'common/customizations';
import { ARRAY, BIT, BLOB, BOOLEAN, DATE, DATETIME, FLOAT, LONG_TEXT, NUMBER, TEXT, TEXT_SEARCH } from 'common/fieldTypes';
import * as antares from 'common/interfaces/antares';
import { InsertRowsParams } from 'common/interfaces/tableApis';
import { ipcMain } from 'electron';
import { faker } from '@faker-js/faker';
import * as moment from 'moment';
import { fakerCustom } from 'common/libs/fakerCustom';
import { sqlEscaper } from 'common/libs/sqlUtils';
import { TEXT, LONG_TEXT, ARRAY, TEXT_SEARCH, NUMBER, FLOAT, BLOB, BIT, DATE, DATETIME } from 'common/fieldTypes';
import customizations from 'common/customizations';
import { ipcMain } from 'electron';
import * as fs from 'fs';
import * as moment from 'moment';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-table-columns', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getTableColumns(params);
return { status: 'success', response: result };
@@ -20,6 +24,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-table-data', async (event, { uid, schema, table, limit, page, sortParams, where }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const offset = (page - 1) * limit;
const query = connections[uid]
@@ -45,6 +51,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-table-count', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getTableApproximateCount(params);
return { status: 'success', response: result };
@@ -55,6 +63,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-table-options', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getTableOptions(params);
return { status: 'success', response: result };
@@ -65,6 +75,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-table-indexes', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getTableIndexes(params);
@@ -75,7 +87,22 @@ export default (connections: {[key: string]: antares.Client}) => {
}
});
ipcMain.handle('get-table-ddl', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getTableDll(params);
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-key-usage', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getKeyUsage(params);
@@ -87,6 +114,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('update-table-cell', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
delete params.row._antares_id;
const { stringsWrapper: sw } = customizations[connections[params.uid]._client];
@@ -105,6 +134,7 @@ export default (connections: {[key: string]: antares.Client}) => {
break;
case 'pg':
case 'sqlite':
case 'firebird':
escapedParam = `'${params.content.replaceAll('\'', '\'\'')}'`;
break;
}
@@ -124,6 +154,7 @@ export default (connections: {[key: string]: antares.Client}) => {
escapedParam = `0x${fileBlob.toString('hex')}`;
break;
case 'pg':
case 'firebird':
fileBlob = fs.readFileSync(params.content);
escapedParam = `decode('${fileBlob.toString('hex')}', 'hex')`;
break;
@@ -141,6 +172,7 @@ export default (connections: {[key: string]: antares.Client}) => {
escapedParam = '\'\'';
break;
case 'pg':
case 'firebird':
escapedParam = 'decode(\'\', \'hex\')';
break;
case 'sqlite':
@@ -153,6 +185,19 @@ export default (connections: {[key: string]: antares.Client}) => {
escapedParam = `b'${sqlEscaper(params.content)}'`;
reload = true;
}
else if (BOOLEAN.includes(params.type)) {
switch (connections[params.uid]._client) {
case 'mysql':
case 'maria':
case 'pg':
case 'firebird':
escapedParam = params.content;
break;
case 'sqlite':
escapedParam = Number(params.content === 'true');
break;
}
}
else if (params.content === null)
escapedParam = 'NULL';
else
@@ -177,7 +222,10 @@ export default (connections: {[key: string]: antares.Client}) => {
if (typeof orgRow[key] === 'string')
orgRow[key] = `'${orgRow[key]}'`;
orgRow[key] = `= ${orgRow[key]}`;
if (orgRow[key] === null)
orgRow[key] = `IS ${orgRow[key]}`;
else
orgRow[key] = `= ${orgRow[key]}`;
}
await connections[params.uid]
@@ -197,6 +245,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('delete-table-rows', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
if (params.primary) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const idString = params.rows.map((row: {[key: string]: any}) => {
@@ -208,10 +258,11 @@ export default (connections: {[key: string]: antares.Client}) => {
}).join(',');
try {
const result = await connections[params.uid]
const result: unknown = await connections[params.uid]
.schema(params.schema)
.delete(params.table)
.where({ [params.primary]: `IN (${idString})` })
.limit(params.rows.length)
.run();
return { status: 'success', response: result };
@@ -227,7 +278,10 @@ export default (connections: {[key: string]: antares.Client}) => {
if (typeof row[key] === 'string')
row[key] = `'${row[key]}'`;
row[key] = `= ${row[key]}`;
if (row[key] === null)
row[key] = 'IS NULL';
else
row[key] = `= ${row[key]}`;
}
await connections[params.uid]
@@ -247,6 +301,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('insert-table-fake-rows', async (event, params: InsertRowsParams) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try { // TODO: move to client classes
const rows: {[key: string]: string | number | boolean | Date | Buffer}[] = [];
@@ -270,6 +326,7 @@ export default (connections: {[key: string]: antares.Client}) => {
break;
case 'pg':
case 'sqlite':
case 'firebird':
escapedParam = `'${params.row[key].value.replaceAll('\'', '\'\'')}'`;
break;
}
@@ -314,24 +371,35 @@ export default (connections: {[key: string]: antares.Client}) => {
let fakeValue;
if (params.locale)
faker.locale = params.locale;
fakerCustom.locale = params.locale;
if (Object.keys(params.row[key].params).length) {
Object.keys(params.row[key].params).forEach(param => {
if (!isNaN(params.row[key].params[param]))
parsedParams[param] = +params.row[key].params[param];
if (!isNaN(params.row[key].params[param]))// Converts string numerics params to number
parsedParams[param] = Number(params.row[key].params[param]);
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fakeValue = (faker as any)[params.row[key].group][params.row[key].method](parsedParams);
fakeValue = (fakerCustom as any)[params.row[key].group][params.row[key].method](parsedParams);
}
else
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fakeValue = (faker as any)[params.row[key].group][params.row[key].method]();
fakeValue = (fakerCustom as any)[params.row[key].group][params.row[key].method]();
if (typeof fakeValue === 'string') {
if (params.row[key].length)
fakeValue = fakeValue.substring(0, params.row[key].length);
fakeValue = `'${sqlEscaper(fakeValue)}'`;
switch (connections[params.uid]._client) {
case 'mysql':
case 'maria':
fakeValue = `'${sqlEscaper(fakeValue)}'`;
break;
case 'pg':
case 'sqlite':
case 'firebird':
fakeValue = `'${fakeValue.replaceAll('\'', '\'\'')}'`;
break;
}
}
else if ([...DATE, ...DATETIME].includes(type))
fakeValue = `'${moment(fakeValue).format('YYYY-MM-DD HH:mm:ss.SSSSSS')}'`;
@@ -357,6 +425,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('get-foreign-list', async (event, { uid, schema, table, column, description }) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const query = connections[uid]
.select(`${column} AS foreign_column`)
@@ -367,7 +437,20 @@ export default (connections: {[key: string]: antares.Client}) => {
if (description)
query.select(`LEFT(${description}, 20) AS foreign_description`);
const results = await query.run();
const results = await query.run<{[key: string]: string}>();
const parsedResults: {[key: string]: string}[] = [];
for (const row of results.rows) {
const remappedRow: {[key: string]: string} = {};
for (const key in row)
remappedRow[key.toLowerCase()] = row[key];// Thanks Firebird -.-
parsedResults.push(remappedRow);
}
results.rows = parsedResults;
return { status: 'success', response: results };
}
@@ -377,6 +460,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('create-table', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].createTable(params);
return { status: 'success' };
@@ -387,6 +472,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('alter-table', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].alterTable(params);
return { status: 'success' };
@@ -397,6 +484,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('duplicate-table', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].duplicateTable(params);
return { status: 'success' };
@@ -407,6 +496,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('truncate-table', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].truncateTable(params);
return { status: 'success' };
@@ -417,6 +508,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('drop-table', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].dropTable(params);
return { status: 'success' };

View File

@@ -1,8 +1,12 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-trigger-informations', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getTriggerInformations(params);
return { status: 'success', response: result };
@@ -13,6 +17,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('drop-trigger', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].dropTrigger(params);
return { status: 'success' };
@@ -23,6 +29,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('alter-trigger', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].alterTrigger(params);
return { status: 'success' };
@@ -33,6 +41,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('create-trigger', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].createTrigger(params);
return { status: 'success' };
@@ -43,6 +53,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('toggle-trigger', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
if (!params.enabled)
await connections[params.uid].enableTrigger(params);

View File

@@ -1,11 +1,20 @@
import { ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
import * as Store from 'electron-store';
const persistentStore = new Store({ name: 'settings', clearInvalidConfig: true });
const isMacOS = process.platform === 'darwin';
import { autoUpdater } from 'electron-updater';
const persistentStore = new Store({
name: 'settings',
clearInvalidConfig: true,
migrations: {
'0.7.15': store => {
store.set('allow_prerelease', false);
}
}
});
const isMacOS = process.platform === 'darwin';
let mainWindow: Electron.IpcMainEvent;
autoUpdater.allowPrerelease = persistentStore.get('allow_prerelease', true) as boolean;
autoUpdater.allowPrerelease = persistentStore.get('allow_prerelease', false) as boolean;
export default () => {
ipcMain.on('check-for-updates', event => {
@@ -42,8 +51,8 @@ export default () => {
mainWindow.reply('update-not-available');
});
autoUpdater.on('download-progress', data => {
mainWindow.reply('download-progress', data);
autoUpdater.on('download-progress', event => {
mainWindow.reply('download-progress', event);
});
autoUpdater.on('update-downloaded', () => {

View File

@@ -1,8 +1,12 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-users', async (event, uid) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[uid].getUsers();
return { status: 'success', response: result };

View File

@@ -1,8 +1,12 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
import { validateSender } from '../libs/misc/validateSender';
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-view-informations', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getViewInformations(params);
return { status: 'success', response: result };
@@ -13,6 +17,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('drop-view', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].dropView(params);
return { status: 'success' };
@@ -23,6 +29,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('alter-view', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].alterView(params);
return { status: 'success' };
@@ -33,6 +41,8 @@ export default (connections: {[key: string]: antares.Client}) => {
});
ipcMain.handle('create-view', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
await connections[params.uid].createView(params);
return { status: 'success' };

View File

@@ -1,4 +1,6 @@
import * as antares from 'common/interfaces/antares';
import { FirebirdSQLClient } from './clients/FirebirdSQLClient';
import { MySQLClient } from './clients/MySQLClient';
import { PostgreSQLClient } from './clients/PostgreSQLClient';
import { SQLiteClient } from './clients/SQLiteClient';
@@ -13,6 +15,8 @@ export class ClientsFactory {
return new PostgreSQLClient(args);
case 'sqlite':
return new SQLiteClient(args);
case 'firebird':
return new FirebirdSQLClient(args);
default:
throw new Error(`Unknown database client: ${args.client}`);
}

View File

@@ -0,0 +1,139 @@
import { ShortcutRecord, shortcuts } from 'common/shortcuts';
import { BrowserWindow, globalShortcut, Menu, MenuItem, MenuItemConstructorOptions } from 'electron';
import * as Store from 'electron-store';
const shortcutsStore = new Store({ name: 'shortcuts' });
const isDevelopment = process.env.NODE_ENV !== 'production';
const defaultShortcuts = shortcuts.filter(s => s.os.includes(process.platform));
export type ShortcutMode = 'local' | 'global'
export type OsMenu = {
[key in NodeJS.Platform]?: MenuItemConstructorOptions[];
};
export class ShortcutRegister {
private _shortcuts: ShortcutRecord[];
private _mainWindow: BrowserWindow;
private _menu: Menu;
private _menuTemplate: OsMenu;
private _mode: ShortcutMode;
private static _instance: ShortcutRegister;
private constructor (args: { mainWindow: BrowserWindow; menuTemplate?: OsMenu; mode: ShortcutMode }) {
this._mainWindow = args.mainWindow;
this._menuTemplate = args.menuTemplate || {};
this._mode = args.mode;
this.shortcuts = shortcutsStore.get('shortcuts', defaultShortcuts) as ShortcutRecord[];
}
public static getInstance (args?: { mainWindow?: BrowserWindow; menuTemplate?: OsMenu; mode?: ShortcutMode }) {
if (!ShortcutRegister._instance && args.menuTemplate !== undefined && args.mode !== undefined) {
ShortcutRegister._instance = new ShortcutRegister({
mainWindow: args.mainWindow,
menuTemplate: args.menuTemplate,
mode: args.mode
});
}
return ShortcutRegister._instance;
}
get shortcuts () {
return this._shortcuts;
}
private set shortcuts (value: ShortcutRecord[]) {
this._shortcuts = value;
shortcutsStore.set('shortcuts', value);
}
init () {
this._mainWindow.webContents.send('update-shortcuts', this.shortcuts);
this.buildBaseMenu();
if (this._mode === 'global')
this.setGlobalShortcuts();
else if (this._mode === 'local')
this.setLocalShortcuts();
else
throw new Error(`Unknown mode "${this._mode}"`);
Menu.setApplicationMenu(this._menu);
}
private buildBaseMenu () {
if (Object.keys(this._menuTemplate).includes(process.platform))
this._menu = Menu.buildFromTemplate(this._menuTemplate[process.platform]);
else
this._menu = new Menu();
}
private setLocalShortcuts () {
for (const shortcut of this.shortcuts) {
if (shortcut.os.includes(process.platform)) {
for (const key of shortcut.keys) {
try {
this._menu.append(new MenuItem({
label: '.',
visible: false,
submenu: [{
label: String(key),
accelerator: key,
visible: false,
click: () => {
this._mainWindow.webContents.send(shortcut.event);
if (isDevelopment) console.log('LOCAL EVENT:', shortcut);
}
}]
}));
}
catch (error) {
if (isDevelopment) console.log(error);
this.restoreDefaults();
throw error;
}
}
}
}
}
private setGlobalShortcuts () {
for (const shortcut of this.shortcuts) {
if (shortcut.os.includes(process.platform)) {
for (const key of shortcut.keys) {
try {
globalShortcut.register(key, () => {
this._mainWindow.webContents.send(shortcut.event);
if (isDevelopment) console.log('GLOBAL EVENT:', shortcut);
});
}
catch (error) {
if (isDevelopment) console.log(error);
this.restoreDefaults();
throw error;
}
}
}
}
}
reload () {
this.unregister();
this.init();
}
updateShortcuts (shortcuts: ShortcutRecord[]) {
this.shortcuts = shortcuts;
this.reload();
}
restoreDefaults () {
this.shortcuts = defaultShortcuts;
this.reload();
}
unregister () {
if (this._mode === 'global') globalShortcut.unregisterAll();
}
}

View File

@@ -1,7 +1,7 @@
import * as antares from 'common/interfaces/antares';
import mysql from 'mysql2/promise';
import * as pg from 'pg';
import SSH2Promise from 'ssh2-promise';
import SSH2Promise = require('@fabio286/ssh2-promise');
const queryLogger = ({ sql, cUid }: {sql: string; cUid: string}) => {
// Remove comments, newlines and multiple spaces
@@ -16,7 +16,7 @@ const queryLogger = ({ sql, cUid }: {sql: string; cUid: string}) => {
/**
* As Simple As Possible Query Builder Core
*/
export class AntaresCore {
export abstract class BaseClient {
_client: antares.ClientCode;
protected _cUid: string
protected _params: mysql.ConnectionOptions | pg.ClientConfig | { databasePath: string; readonly: boolean};
@@ -162,6 +162,10 @@ export class AntaresCore {
throw new Error('Method "getDbConfig" not implemented');
}
getDatabases () {
throw new Error('Method "getDatabases" not implemented');
}
createSchema (...args: any) {
throw new Error('Method "createSchema" not implemented');
}
@@ -174,6 +178,10 @@ export class AntaresCore {
throw new Error('Method "dropSchema" not implemented');
}
getTableDll (...args: any) {
throw new Error('Method "getTableDll" not implemented');
}
getDatabaseCollation (...args: any) {
throw new Error('Method "getDatabaseCollation" not implemented');
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,17 @@
import SSH2Promise = require('@fabio286/ssh2-promise');
import SSHConfig from '@fabio286/ssh2-promise/lib/sshConfig';
import dataTypes from 'common/data-types/mysql';
import * as antares from 'common/interfaces/antares';
import * as mysql from 'mysql2/promise';
import { AntaresCore } from '../AntaresCore';
import dataTypes from 'common/data-types/mysql';
import SSH2Promise = require('ssh2-promise');
import SSHConfig from 'ssh2-promise/lib/sshConfig';
export class MySQLClient extends AntaresCore {
import { BaseClient } from './BaseClient';
export class MySQLClient extends BaseClient {
private _schema?: string;
private _runningConnections: Map<string, number>;
private _connectionsToCommit: Map<string, mysql.Connection | mysql.PoolConnection>;
private _keepaliveTimer: NodeJS.Timer;
private _keepaliveMs: number;
_connection?: mysql.Connection | mysql.Pool;
_params: mysql.ConnectionOptions & {schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean};
@@ -52,6 +55,7 @@ export class MySQLClient extends AntaresCore {
this._schema = null;
this._runningConnections = new Map();
this._connectionsToCommit = new Map();
this._keepaliveMs = 10*60*1000;
}
private _getType (field: mysql.FieldPacket & { columnType?: number; columnLength?: number }) {
@@ -147,7 +151,13 @@ export class MySQLClient extends AntaresCore {
if (this._params.ssh) {
try {
this._ssh = new SSH2Promise({ ...this._params.ssh });
if (this._params.ssh.password === '') delete this._params.ssh.password;
if (this._params.ssh.passphrase === '') delete this._params.ssh.passphrase;
this._ssh = new SSH2Promise({
...this._params.ssh,
debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null
});
const tunnel = await this._ssh.addTunnel({
remoteAddr: this._params.host,
@@ -158,7 +168,10 @@ export class MySQLClient extends AntaresCore {
dbConfig.port = tunnel.localPort;
}
catch (err) {
if (this._ssh) this._ssh.close();
if (this._ssh) {
this._ssh.close();
this._ssh.closeTunnel();
}
throw err;
}
}
@@ -175,7 +188,12 @@ export class MySQLClient extends AntaresCore {
destroy () {
this._connection.end();
if (this._ssh) this._ssh.close();
clearInterval(this._keepaliveTimer);
this._keepaliveTimer = undefined;
if (this._ssh) {
this._ssh.close();
this._ssh.closeTunnel();
}
}
async getConnection () {
@@ -225,6 +243,9 @@ export class MySQLClient extends AntaresCore {
if (hasAnsiQuotes)
await connection.query(`SET SESSION sql_mode = '${sqlMode.filter((m: string) => !['ANSI', 'ANSI_QUOTES'].includes(m)).join(',')}'`);
if (this._params.readonly)
await connection.query('SET SESSION TRANSACTION READ ONLY');
connection.on('connection', conn => {
if (this._params.readonly)
conn.query('SET SESSION TRANSACTION READ ONLY');
@@ -233,9 +254,22 @@ export class MySQLClient extends AntaresCore {
conn.query(`SET SESSION sql_mode = '${sqlMode.filter((m: string) => !['ANSI', 'ANSI_QUOTES'].includes(m)).join(',')}'`);
});
this._keepaliveTimer = setInterval(async () => {
await this.keepAlive();
}, this._keepaliveMs);
return connection;
}
private async keepAlive () {
try {
const connection = await (this._connection as mysql.Pool).getConnection();
await connection.ping();
connection.release();
}
catch (_) {}
}
use (schema: string) {
this._schema = schema;
return this.raw(`USE \`${schema}\``);
@@ -244,25 +278,15 @@ export class MySQLClient extends AntaresCore {
async getStructure (schemas: Set<string>) {
/* eslint-disable camelcase */
interface ShowTableResult {
Db?: string;
Name: string;
Engine: string;
Version: number;
Row_format: string;
Rows: number;
Avg_row_length: number;
Data_length: number;
Max_data_length: number;
Index_length: number;
Data_free: number;
Auto_increment: number;
Create_time: Date;
Update_time: Date;
Check_time?: number;
Collation: string;
Checksum?: number;
Create_options: string;
Comment: string;
TABLE_SCHEMA?: string;
TABLE_NAME: string;
TABLE_TYPE: string;
TABLE_ROWS: number;
ENGINE: string;
DATA_LENGTH: number;
INDEX_LENGTH: number;
TABLE_COLLATION: string;
TABLE_COMMENT: string;
}
interface ShowTriggersResult {
@@ -290,22 +314,69 @@ export class MySQLClient extends AntaresCore {
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`');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let schedulers: any[] = [];
try { // Avoid exception with event_scheduler DISABLED with MariaDB 10
const { rows } = await this.raw('SELECT *, EVENT_SCHEMA AS `Db`, EVENT_NAME AS `Name` FROM information_schema.`EVENTS`');
schedulers = rows;
}
catch (err) {
console.log(err);
}
const tablesArr: ShowTableResult[] = [];
const triggersArr: ShowTriggersResult[] = [];
let schemaSize = 0;
const Store = require('electron-store');
Store.initRenderer();
const settingsStore = new Store({ name: 'settings' });
for (const db of filteredDatabases) {
if (!schemas.has(db.Database)) continue;
let { rows: tables } = await this.raw<antares.QueryResult<ShowTableResult>>(`SHOW TABLE STATUS FROM \`${db.Database}\``);
if (tables.length) {
tables = tables.map(table => {
table.Db = db.Database;
return table;
});
tablesArr.push(...tables);
const showTableSize = settingsStore.get('show_table_size', false);
if (showTableSize) {
let { rows: tables } = await this.raw<antares.QueryResult<ShowTableResult>>(`
SELECT
TABLE_NAME,
TABLE_TYPE,
ENGINE,
DATA_LENGTH,
INDEX_LENGTH,
TABLE_COMMENT,
TABLE_COLLATION,
CREATE_TIME,
UPDATE_TIME
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = "${db.Database}"
ORDER BY TABLE_NAME
`);
if (tables.length) {
tables = tables.map(table => {
table.TABLE_SCHEMA = db.Database;
return table;
});
tablesArr.push(...tables);
}
}
else {
let { rows: tables } = await this.raw<antares.QueryResult<ShowTableResult>>(`SHOW FULL TABLES FROM \`${db.Database}\``);
if (tables.length) {
tables = tables.map(table => {
const [name, type] = Object.values(table);
table.TABLE_SCHEMA = db.Database;
table.TABLE_NAME = name;
table.TABLE_TYPE = type;
return table;
});
tablesArr.push(...tables);
}
}
let { rows: triggers } = await this.raw<antares.QueryResult<ShowTriggersResult>>(`SHOW TRIGGERS FROM \`${db.Database}\``);
@@ -321,9 +392,9 @@ export class MySQLClient extends AntaresCore {
return filteredDatabases.map(db => {
if (schemas.has(db.Database)) {
// TABLES
const remappedTables: antares.TableInfos[] = tablesArr.filter(table => table.Db === db.Database).map(table => {
const remappedTables: antares.TableInfos[] = tablesArr.filter(table => table.TABLE_SCHEMA === db.Database).map(table => {
let tableType;
switch (table.Comment) {
switch (table.TABLE_TYPE) {
case 'VIEW':
tableType = 'view';
break;
@@ -332,20 +403,17 @@ export class MySQLClient extends AntaresCore {
break;
}
const tableSize = Number(table.Data_length) + Number(table.Index_length);
const tableSize = Number(table.DATA_LENGTH) + Number(table.INDEX_LENGTH);
schemaSize += tableSize;
return {
name: table.Name,
name: table.TABLE_NAME,
type: tableType,
rows: table.Rows,
created: table.Create_time,
updated: table.Update_time,
engine: table.Engine,
comment: table.Comment,
rows: table.TABLE_ROWS,
engine: table.ENGINE,
comment: table.TABLE_COMMENT,
size: tableSize,
autoIncrement: table.Auto_increment,
collation: table.Collation
collation: table.TABLE_COLLATION
};
});
@@ -469,7 +537,12 @@ export class MySQLClient extends AntaresCore {
.orderBy({ ORDINAL_POSITION: 'ASC' })
.run<TableColumnsResult>();
const { rows: fields } = await this.raw<antares.QueryResult<CreateTableResult>>(`SHOW CREATE TABLE \`${schema}\`.\`${table}\``);
let fields: CreateTableResult[] = [];
try {
const { rows } = await this.raw<antares.QueryResult<CreateTableResult>>(`SHOW CREATE TABLE \`${schema}\`.\`${table}\``);
fields = rows;
}
catch (_) {}
const remappedFields = fields.map(row => {
if (!row['Create Table']) return false;
@@ -518,7 +591,7 @@ export class MySQLClient extends AntaresCore {
return rows.map((field) => {
const numLengthMatch = field.COLUMN_TYPE.match(/int\(([^)]+)\)/);
const numLength = numLengthMatch ? +numLengthMatch.pop() : field.NUMERIC_PRECISION || null;
const enumValues = /(enum|set)/.test(field.COLUMN_TYPE)
const enumValues = /(enum)/.test(field.COLUMN_TYPE)
? field.COLUMN_TYPE.match(/\(([^)]+)\)/)[0].slice(1, -1)
: null;
@@ -625,11 +698,11 @@ export class MySQLClient extends AntaresCore {
return rows.map(row => {
return {
unique: !row.Non_unique,
unique: !Number(row.Non_unique),
name: row.Key_name,
column: row.Column_name,
indexType: row.Index_type,
type: row.Key_name === 'PRIMARY' ? 'PRIMARY' : !row.Non_unique ? 'UNIQUE' : row.Index_type === 'FULLTEXT' ? 'FULLTEXT' : 'INDEX',
type: row.Key_name === 'PRIMARY' ? 'PRIMARY' : !Number(row.Non_unique) ? 'UNIQUE' : row.Index_type === 'FULLTEXT' ? 'FULLTEXT' : 'INDEX',
cardinality: row.Cardinality,
comment: row.Comment,
indexComment: row.Index_comment
@@ -637,6 +710,17 @@ export class MySQLClient extends AntaresCore {
});
}
async getTableDll ({ schema, table }: { schema: string; table: string }) {
const { rows } = await this.raw<antares.QueryResult<{
'Create Table'?: string;
Table: string;
}>>(`SHOW CREATE TABLE \`${schema}\`.\`${table}\``);
if (rows.length)
return rows[0]['Create Table'];
else return '';
}
async getKeyUsage ({ schema, table }: { schema: string; table: string }) {
interface KeyResult {
TABLE_SCHEMA: string;
@@ -689,7 +773,7 @@ export class MySQLClient extends AntaresCore {
}
async getUsers () {
const { rows } = await this.raw('SELECT `user`, `host`, authentication_string AS `password` FROM `mysql`.`user`');
const { rows } = await this.raw('SELECT `user` as \'user\', `host` as \'host\', authentication_string AS `password` FROM `mysql`.`user`');
return rows.map(row => {
return {
@@ -790,21 +874,23 @@ export class MySQLClient extends AntaresCore {
options
} = params;
let sql = `ALTER TABLE \`${schema}\`.\`${table}\` `;
const alterColumns: string[] = [];
const sql = `ALTER TABLE \`${schema}\`.\`${table}\` `;
const alterColumnsAdd: string[] = [];
const alterColumnsChange: string[] = [];
const alterColumnsDrop: string[] = [];
// OPTIONS
if ('comment' in options) alterColumns.push(`COMMENT='${options.comment}'`);
if ('engine' in options) alterColumns.push(`ENGINE=${options.engine}`);
if ('autoIncrement' in options) alterColumns.push(`AUTO_INCREMENT=${+options.autoIncrement}`);
if ('collation' in options) alterColumns.push(`COLLATE='${options.collation}'`);
if ('comment' in options) alterColumnsChange.push(`COMMENT='${options.comment}'`);
if ('engine' in options) alterColumnsChange.push(`ENGINE=${options.engine}`);
if ('autoIncrement' in options) alterColumnsChange.push(`AUTO_INCREMENT=${+options.autoIncrement}`);
if ('collation' in options) alterColumnsChange.push(`COLLATE='${options.collation}'`);
// ADD FIELDS
additions.forEach(addition => {
const typeInfo = this.getTypeInfo(addition.type);
const length = typeInfo.length ? addition.enumValues || addition.numLength || addition.charLength || addition.datePrecision : false;
alterColumns.push(`ADD COLUMN \`${addition.name}\`
alterColumnsAdd.push(`ADD COLUMN \`${addition.name}\`
${addition.type.toUpperCase()}${length ? `(${length}${addition.numScale ? `,${addition.numScale}` : ''})` : ''}
${addition.unsigned ? 'UNSIGNED' : ''}
${addition.zerofill ? 'ZEROFILL' : ''}
@@ -823,18 +909,18 @@ export class MySQLClient extends AntaresCore {
let type = addition.type;
if (type === 'PRIMARY')
alterColumns.push(`ADD PRIMARY KEY (${fields})`);
alterColumnsAdd.push(`ADD PRIMARY KEY (${fields})`);
else {
if (type === 'UNIQUE')
type = 'UNIQUE INDEX';
alterColumns.push(`ADD ${type} \`${addition.name}\` (${fields})`);
alterColumnsAdd.push(`ADD ${type} \`${addition.name}\` (${fields})`);
}
});
// ADD FOREIGN KEYS
foreignChanges.additions.forEach(addition => {
alterColumns.push(`ADD CONSTRAINT \`${addition.constraintName}\` FOREIGN KEY (\`${addition.field}\`) REFERENCES \`${addition.refTable}\` (\`${addition.refField}\`) ON UPDATE ${addition.onUpdate} ON DELETE ${addition.onDelete}`);
alterColumnsAdd.push(`ADD CONSTRAINT \`${addition.constraintName}\` FOREIGN KEY (\`${addition.field}\`) REFERENCES \`${addition.refTable}\` (\`${addition.refField}\`) ON UPDATE ${addition.onUpdate} ON DELETE ${addition.onDelete}`);
});
// CHANGE FIELDS
@@ -842,7 +928,7 @@ export class MySQLClient extends AntaresCore {
const typeInfo = this.getTypeInfo(change.type);
const length = typeInfo.length ? change.enumValues || change.numLength || change.charLength || change.datePrecision : false;
alterColumns.push(`CHANGE COLUMN \`${change.orgName}\` \`${change.name}\`
alterColumnsChange.push(`CHANGE COLUMN \`${change.orgName}\` \`${change.name}\`
${change.type.toUpperCase()}${length ? `(${length}${change.numScale ? `,${change.numScale}` : ''})` : ''}
${change.unsigned ? 'UNSIGNED' : ''}
${change.zerofill ? 'ZEROFILL' : ''}
@@ -858,53 +944,56 @@ export class MySQLClient extends AntaresCore {
// CHANGE INDEX
indexChanges.changes.forEach(change => {
if (change.oldType === 'PRIMARY')
alterColumns.push('DROP PRIMARY KEY');
alterColumnsChange.push('DROP PRIMARY KEY');
else
alterColumns.push(`DROP INDEX \`${change.oldName}\``);
alterColumnsChange.push(`DROP INDEX \`${change.oldName}\``);
const fields = change.fields.map(field => `\`${field}\``).join(',');
let type = change.type;
if (type === 'PRIMARY')
alterColumns.push(`ADD PRIMARY KEY (${fields})`);
alterColumnsChange.push(`ADD PRIMARY KEY (${fields})`);
else {
if (type === 'UNIQUE')
type = 'UNIQUE INDEX';
alterColumns.push(`ADD ${type} \`${change.name}\` (${fields})`);
alterColumnsChange.push(`ADD ${type} \`${change.name}\` (${fields})`);
}
});
// CHANGE FOREIGN KEYS
foreignChanges.changes.forEach(change => {
alterColumns.push(`DROP FOREIGN KEY \`${change.oldName}\``);
alterColumns.push(`ADD CONSTRAINT \`${change.constraintName}\` FOREIGN KEY (\`${change.field}\`) REFERENCES \`${change.refTable}\` (\`${change.refField}\`) ON UPDATE ${change.onUpdate} ON DELETE ${change.onDelete}`);
alterColumnsChange.push(`DROP FOREIGN KEY \`${change.oldName}\``);
alterColumnsChange.push(`ADD CONSTRAINT \`${change.constraintName}\` FOREIGN KEY (\`${change.field}\`) REFERENCES \`${change.refTable}\` (\`${change.refField}\`) ON UPDATE ${change.onUpdate} ON DELETE ${change.onDelete}`);
});
// DROP FIELDS
deletions.forEach(deletion => {
alterColumns.push(`DROP COLUMN \`${deletion.name}\``);
alterColumnsDrop.push(`DROP COLUMN \`${deletion.name}\``);
});
// DROP INDEX
indexChanges.deletions.forEach(deletion => {
if (deletion.type === 'PRIMARY')
alterColumns.push('DROP PRIMARY KEY');
alterColumnsDrop.push('DROP PRIMARY KEY');
else
alterColumns.push(`DROP INDEX \`${deletion.name}\``);
alterColumnsDrop.push(`DROP INDEX \`${deletion.name}\``);
});
// DROP FOREIGN KEYS
foreignChanges.deletions.forEach(deletion => {
alterColumns.push(`DROP FOREIGN KEY \`${deletion.constraintName}\``);
alterColumnsDrop.push(`DROP FOREIGN KEY \`${deletion.constraintName}\``);
});
sql += alterColumns.join(', ');
const alterQueryes = [];
if (alterColumnsAdd.length) alterQueryes.push(sql+alterColumnsAdd.join(', '));
if (alterColumnsChange.length) alterQueryes.push(sql+alterColumnsChange.join(', '));
if (alterColumnsDrop.length) alterQueryes.push(sql+alterColumnsDrop.join(', '));
// RENAME
if (options.name) sql += `; RENAME TABLE \`${schema}\`.\`${table}\` TO \`${schema}\`.\`${options.name}\``;
if (options.name) alterQueryes.push(`RENAME TABLE \`${schema}\`.\`${table}\` TO \`${schema}\`.\`${options.name}\``);
return await this.raw(sql);
return await this.raw(alterQueryes.join(';'));
}
async duplicateTable (params: { schema: string; table: string }) {
@@ -940,7 +1029,7 @@ export class MySQLClient extends AntaresCore {
return {
algorithm: algorithm[0]['Create View'].match(/(?<=CREATE ALGORITHM=).*?(?=\s)/gs)[0],
definer: viewInfo[0].DEFINER,
definer: viewInfo[0].DEFINER.split('@').map((str: string) => `\`${str}\``).join('@'),
security: viewInfo[0].SECURITY_TYPE,
updateOption: viewInfo[0].CHECK_OPTION === 'NONE' ? '' : viewInfo[0].CHECK_OPTION,
sql: viewInfo[0].VIEW_DEFINITION,
@@ -1588,7 +1677,8 @@ export class MySQLClient extends AntaresCore {
let timeStop: Date;
let keysArr: antares.QueryForeign[] = [];
const { rows, report, fields, keys, duration } = await new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { rows, report, fields, keys, duration }: any = await new Promise((resolve, reject) => {
connection.query({ sql: query, nestTables }).then(async ([response, fields]) => {
timeStop = new Date();
const queryResult = response;
@@ -1598,7 +1688,7 @@ export class MySQLClient extends AntaresCore {
if (!field || Array.isArray(field))
return undefined;
const type = this._getType(field);
const type = this._getType(field as undefined);
return {
name: field.orgName,

View File

@@ -1,11 +1,12 @@
import SSH2Promise = require('@fabio286/ssh2-promise');
import SSHConfig from '@fabio286/ssh2-promise/lib/sshConfig';
import dataTypes from 'common/data-types/postgresql';
import * as antares from 'common/interfaces/antares';
import * as mysql from 'mysql2';
import * as pg from 'pg';
import * as pgAst from 'pgsql-ast-parser';
import { AntaresCore } from '../AntaresCore';
import dataTypes from 'common/data-types/postgresql';
import SSH2Promise = require('ssh2-promise');
import SSHConfig from 'ssh2-promise/lib/sshConfig';
import { ConnectionOptions } from 'tls';
import { BaseClient } from './BaseClient';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function pgToString (value: any) {
@@ -80,10 +81,12 @@ type builtinsTypes =
'JSONB' |
'REGNAMESPACE' |
'REGROLE';
export class PostgreSQLClient extends AntaresCore {
export class PostgreSQLClient extends BaseClient {
private _schema?: string;
private _runningConnections: Map<string, number>;
private _connectionsToCommit: Map<string, pg.Client | pg.PoolClient>;
private _keepaliveTimer: NodeJS.Timer;
private _keepaliveMs: number;
protected _connection?: pg.Client | pg.Pool;
private types: {[key: string]: string} = {};
private _arrayTypes: {[key: string]: string} = {
@@ -96,7 +99,7 @@ export class PostgreSQLClient extends AntaresCore {
_varchar: 'CHARACTER VARYING'
}
_params: pg.ClientConfig & {schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean};
_params: pg.ClientConfig & {schema: string; ssl?: ConnectionOptions; ssh?: SSHConfig; readonly: boolean};
constructor (args: antares.ClientParams) {
super(args);
@@ -104,6 +107,7 @@ export class PostgreSQLClient extends AntaresCore {
this._schema = null;
this._runningConnections = new Map();
this._connectionsToCommit = new Map();
this._keepaliveMs = 10*60*1000;
for (const key in pg.types.builtins) {
const builtinKey = key as builtinsTypes;
@@ -151,9 +155,9 @@ export class PostgreSQLClient extends AntaresCore {
host: this._params.host,
port: this._params.port,
user: this._params.user,
database: undefined as string | undefined,
database: 'postgres' as string,
password: this._params.password,
ssl: null as mysql.SslOptions
ssl: null as ConnectionOptions
};
if (this._params.database?.length) dbConfig.database = this._params.database;
@@ -162,7 +166,10 @@ export class PostgreSQLClient extends AntaresCore {
if (this._params.ssh) {
try {
this._ssh = new SSH2Promise({ ...this._params.ssh });
this._ssh = new SSH2Promise({
...this._params.ssh,
debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null
});
const tunnel = await this._ssh.addTunnel({
remoteAddr: this._params.host,
@@ -173,7 +180,10 @@ export class PostgreSQLClient extends AntaresCore {
dbConfig.port = tunnel.localPort;
}
catch (err) {
if (this._ssh) this._ssh.close();
if (this._ssh) {
this._ssh.close();
this._ssh.closeTunnel();
}
throw err;
}
}
@@ -218,12 +228,30 @@ export class PostgreSQLClient extends AntaresCore {
});
}
this._keepaliveTimer = setInterval(async () => {
await this.keepAlive();
}, this._keepaliveMs);
return connection;
}
destroy () {
this._connection.end();
if (this._ssh) this._ssh.close();
clearInterval(this._keepaliveTimer);
this._keepaliveTimer = undefined;
if (this._ssh) {
this._ssh.close();
this._ssh.closeTunnel();
}
}
private async keepAlive () {
try {
const connection = await this._connection.connect() as pg.PoolClient;
await connection.query('SELECT 1+1');
connection.release();
}
catch (_) {}
}
use (schema: string, connection?: pg.Client | pg.PoolClient) {
@@ -243,6 +271,18 @@ export class PostgreSQLClient extends AntaresCore {
return [];
}
async getDatabases () {
const { rows } = await this.raw('SELECT datname FROM pg_database WHERE datistemplate = false');
if (rows) {
return rows.reduce((acc, cur) => {
acc.push(cur.datname);
return acc;
}, [] as string[]);
}
else
return [];
}
async getStructure (schemas: Set<string>) {
/* eslint-disable camelcase */
interface ShowTableResult {
@@ -540,11 +580,7 @@ export class PostgreSQLClient extends AntaresCore {
return {
name: row.constraint_name,
column: row.column_name,
indexType: null as null,
type: row.constraint_type,
cardinality: null as null,
comment: '',
indexComment: ''
type: row.constraint_type
};
});
}
@@ -567,6 +603,142 @@ export class PostgreSQLClient extends AntaresCore {
}, {} as {table: string; schema: string}[]);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async getTableDll ({ schema, table }: { schema: string; table: string }) {
// const { rows } = await this.raw<antares.QueryResult<{'ddl'?: string}>>(`
// SELECT
// 'CREATE TABLE ' || relname || E'\n(\n' ||
// array_to_string(
// array_agg(' ' || column_name || ' ' || type || ' '|| not_null)
// , E',\n'
// ) || E'\n);\n' AS ddl
// FROM (
// SELECT
// a.attname AS column_name
// , pg_catalog.format_type(a.atttypid, a.atttypmod) AS type
// , CASE WHEN a.attnotnull THEN 'NOT NULL' ELSE 'NULL' END AS not_null
// , c.relname
// FROM pg_attribute a, pg_class c, pg_type t
// WHERE a.attnum > 0
// AND a.attrelid = c.oid
// AND a.atttypid = t.oid
// AND c.relname = '${table}'
// ORDER BY a.attnum
// ) AS tabledefinition
// GROUP BY relname
// `);
// if (rows.length)
// return rows[0].ddl;
// else return '';
/* eslint-disable camelcase */
interface SequenceRecord {
sequence_catalog: string;
sequence_schema: string;
sequence_name: string;
data_type: string;
numeric_precision: number;
numeric_precision_radix: number;
numeric_scale: number;
start_value: string;
minimum_value: string;
maximum_value: string;
increment: string;
cycle_option: string;
}
/* eslint-enable camelcase */
let createSql = '';
const sequences = [];
const columnsSql = [];
const arrayTypes: {[key: string]: string} = {
_int2: 'smallint',
_int4: 'integer',
_int8: 'bigint',
_float4: 'real',
_float8: 'double precision',
_char: '"char"',
_varchar: 'character varying'
};
// Table columns
const { rows } = await this.raw(`
SELECT *
FROM "information_schema"."columns"
WHERE "table_schema" = '${schema}'
AND "table_name" = '${table}'
ORDER BY "ordinal_position" ASC
`, { schema: 'information_schema' });
if (!rows.length) return '';
for (const column of rows) {
let fieldType = column.data_type;
if (fieldType === 'USER-DEFINED') fieldType = `"${schema}".${column.udt_name}`;
else if (fieldType === 'ARRAY') {
if (Object.keys(arrayTypes).includes(fieldType))
fieldType = arrayTypes[column.udt_name] + '[]';
else
fieldType = column.udt_name.replaceAll('_', '') + '[]';
}
const columnArr = [
`"${column.column_name}"`,
`${fieldType}${column.character_maximum_length ? `(${column.character_maximum_length})` : ''}`
];
if (column.column_default) {
columnArr.push(`DEFAULT ${column.column_default}`);
if (column.column_default.includes('nextval')) {
const sequenceName = column.column_default.split('\'')[1];
sequences.push(sequenceName);
}
}
if (column.is_nullable === 'NO') columnArr.push('NOT NULL');
columnsSql.push(columnArr.join(' '));
}
// Table sequences
for (let sequence of sequences) {
if (sequence.includes('.')) sequence = sequence.split('.')[1];
const { rows } = await this.select('*')
.schema('information_schema')
.from('sequences')
.where({ sequence_schema: `= '${schema}'`, sequence_name: `= '${sequence}'` })
.run<SequenceRecord>();
if (rows.length) {
createSql += `CREATE SEQUENCE "${schema}"."${sequence}"
START WITH ${rows[0].start_value}
INCREMENT BY ${rows[0].increment}
MINVALUE ${rows[0].minimum_value}
MAXVALUE ${rows[0].maximum_value}
CACHE 1;\n`;
}
}
// Table create
createSql += `\nCREATE TABLE "${schema}"."${table}"(
${columnsSql.join(',\n ')}
);\n`;
// Table indexes
createSql += '\n';
const { rows: indexes } = await this.select('*')
.schema('pg_catalog')
.from('pg_indexes')
.where({ schemaname: `= '${schema}'`, tablename: `= '${table}'` })
.run<{indexdef: string}>();
for (const index of indexes)
createSql += `${index.indexdef};\n`;
return createSql;
}
async getKeyUsage ({ schema, table }: { schema: string; table: string }) {
/* eslint-disable camelcase */
interface KeyResult {
@@ -1416,7 +1588,7 @@ export class PostgreSQLClient extends AntaresCore {
if (args.tabUid && isPool)
this._runningConnections.set(args.tabUid, (connection as pg.PoolClient & { processID: number }).processID);
if (args.schema && args.schema !== 'public')
if (args.schema)
await this.use(args.schema, connection);
for (const query of queries) {
@@ -1426,7 +1598,8 @@ export class PostgreSQLClient extends AntaresCore {
let timeStop: Date;
let keysArr: antares.QueryForeign[] = [];
const { rows, report, fields, keys, duration } = await new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { rows, report, fields, keys, duration }: any = await new Promise((resolve, reject) => {
(async () => {
try {
const res = await connection.query({ rowMode: args.nest ? 'array' : null, text: query });

View File

@@ -1,10 +1,11 @@
import * as antares from 'common/interfaces/antares';
import * as sqlite from 'better-sqlite3';
import { AntaresCore } from '../AntaresCore';
import dataTypes from 'common/data-types/sqlite';
import { NUMBER, FLOAT, TIME, DATETIME } from 'common/fieldTypes';
import { DATETIME, FLOAT, NUMBER, TIME } from 'common/fieldTypes';
import * as antares from 'common/interfaces/antares';
export class SQLiteClient extends AntaresCore {
import { BaseClient } from './BaseClient';
export class SQLiteClient extends BaseClient {
private _schema?: string;
private _connectionsToCommit: Map<string, sqlite.Database>;
protected _connection?: sqlite.Database;
@@ -34,8 +35,8 @@ export class SQLiteClient extends AntaresCore {
});
}
destroy (): void {
return null;
destroy () {
this._connection.close();
}
use (): void {
@@ -217,11 +218,7 @@ export class SQLiteClient extends AntaresCore {
remappedIndexes.push({
name: 'PRIMARY',
column: key.name,
indexType: null as never,
type: 'PRIMARY',
cardinality: null as never,
comment: '',
indexComment: ''
type: 'PRIMARY'
});
}
@@ -299,7 +296,13 @@ export class SQLiteClient extends AntaresCore {
// ADD FIELDS
fields.forEach(field => {
const typeInfo = this.getTypeInfo(field.type);
const length = typeInfo?.length ? field.enumValues || field.numLength || field.charLength || field.datePrecision : false;
const length = typeInfo?.length
? field.enumValues ||
field.numLength ||
field.numPrecision ||
field.charLength ||
field.datePrecision
: false;
newColumns.push(`"${field.name}"
${field.type.toUpperCase()}${length ? `(${length})` : ''}
@@ -348,6 +351,20 @@ export class SQLiteClient extends AntaresCore {
const tmpName = `Antares_${table}_tmp`;
await this.raw(`CREATE TABLE "${tmpName}" AS SELECT * FROM "${table}"`);
// Get table triggers before drop
const { rows: triggers } = await this.raw(`SELECT * FROM "${schema}".sqlite_master WHERE type='trigger' AND tbl_name = '${table}'`);
const remappedTriggers = triggers.map((row) => {
return {
schema,
sql: row.sql.match(/(BEGIN|begin)(.*)(END|end)/gs)[0],
name: row.name,
table: row.sql.match(/(?<=ON `).*?(?=`)/gs)[0],
activation: row.sql.match(/(BEFORE|AFTER)/gs)[0],
event: row.sql.match(/(INSERT|UPDATE|DELETE)/gs)[0]
};
});
await this.dropTable(params);
const createTableParams = {
@@ -380,6 +397,11 @@ export class SQLiteClient extends AntaresCore {
await this.raw(`INSERT INTO "${createTableParams.options.name}" (${insertFields.join(',')}) SELECT ${selectFields.join(',')} FROM "${tmpName}"`);
await this.dropTable({ schema: schema, table: tmpName });
// Recreates triggers
for (const trigger of remappedTriggers)
await this.createTrigger(trigger);
await this.raw('PRAGMA foreign_keys = 1');
await this.raw('COMMIT');
}
@@ -410,7 +432,7 @@ export class SQLiteClient extends AntaresCore {
return results.rows.map(row => {
return {
sql: row.sql.match(/(?<=AS ).*?$/gs)[0],
sql: row.sql.match(/(?<=(AS|as)( |\n)).*?$/gs)[0],
name: view
};
})[0];
@@ -628,7 +650,8 @@ export class SQLiteClient extends AntaresCore {
let timeStop;
const keysArr: antares.QueryForeign[] = [];
const { rows, report, fields, keys, duration } = await new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { rows, report, fields, keys, duration }: any = await new Promise((resolve, reject) => {
(async () => {
let queryRunResult: sqlite.RunResult;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -675,8 +698,8 @@ export class SQLiteClient extends AntaresCore {
if ([...TIME, ...DATETIME].includes(parsedType)) {
const firstNotNull = queryAllResult.find(res => res[field.name] !== null);
if (firstNotNull && firstNotNull[field.name].includes('.'))
length = firstNotNull[field.name].split('.').pop().length;
if (firstNotNull && String(firstNotNull[field.name]).includes('.'))
length = String(firstNotNull[field.name]).split('.').pop().length;
}
return {

View File

@@ -1,8 +1,8 @@
import * as exporter from 'common/interfaces/exporter';
import * as fs from 'fs';
import { createGzip, Gzip } from 'zlib';
import * as path from 'path';
import * as EventEmitter from 'events';
import * as fs from 'fs';
import * as path from 'path';
import { createGzip, Gzip } from 'zlib';
export class BaseExporter extends EventEmitter {
protected _tables;

View File

@@ -1,8 +1,9 @@
import * as exporter from 'common/interfaces/exporter';
import * as mysql from 'mysql2/promise';
import { SqlExporter } from './SqlExporter';
import { MySQLClient } from '../../clients/MySQLClient';
import { valueToSqlString } from 'common/libs/sqlUtils';
import * as mysql from 'mysql2/promise';
import { MySQLClient } from '../../clients/MySQLClient';
import { SqlExporter } from './SqlExporter';
export default class MysqlExporter extends SqlExporter {
protected _client: MySQLClient;
@@ -184,9 +185,9 @@ CREATE TABLE \`${view.Name}\`(
const { rows: triggers } = await this._client.raw(
`SHOW TRIGGERS FROM \`${this.schemaName}\``
);
const generatedTables = this._tables
.filter(t => t.includeStructure)
.map(t => t.table);
// const generatedTables = this._tables
// .filter(t => t.includeStructure)
// .map(t => t.table);
let sqlString = '';
@@ -200,7 +201,7 @@ CREATE TABLE \`${view.Name}\`(
sql_mode: sqlMode
} = trigger;
if (!generatedTables.includes(table)) continue;
// if (!generatedTables.includes(table)) continue;// Commented to avoid issues if export contains triggers without tables
const definer = this.getEscapedDefiner(trigger.Definer);
sqlString += '/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;;\n';

View File

@@ -1,11 +1,12 @@
import * as antares from 'common/interfaces/antares';
import * as exporter from 'common/interfaces/exporter';
import { SqlExporter } from './SqlExporter';
import { valueToSqlString } from 'common/libs/sqlUtils';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import * as QueryStream from 'pg-query-stream';
import { PostgreSQLClient } from '../../clients/PostgreSQLClient';
import { valueToSqlString } from 'common/libs/sqlUtils';
import { SqlExporter } from './SqlExporter';
export default class PostgreSQLExporter extends SqlExporter {
constructor (client: PostgreSQLClient, tables: exporter.TableParams[], options: exporter.ExportOptions) {

View File

@@ -1,4 +1,5 @@
import * as moment from 'moment';
import { MySQLClient } from '../../clients/MySQLClient';
import { PostgreSQLClient } from '../../clients/PostgreSQLClient';
import { BaseExporter } from '../BaseExporter';

View File

@@ -1,6 +1,6 @@
import * as importer from 'common/interfaces/importer';
import * as fs from 'fs';
import * as EventEmitter from 'events';
import * as fs from 'fs';
export class BaseImporter extends EventEmitter {
protected _options;

View File

@@ -1,6 +1,7 @@
import * as mysql from 'mysql2';
import * as importer from 'common/interfaces/importer';
import * as fs from 'fs/promises';
import * as mysql from 'mysql2';
import MySQLParser from '../../parsers/MySQLParser';
import { BaseImporter } from '../BaseImporter';
@@ -47,7 +48,7 @@ export default class MySQLImporter extends BaseImporter {
catch (error) {
this.emit('query-error', {
sql: query,
message: error.sqlMessage,
message: error.sqlMessage || error.message,
sqlSnippet: error.sql,
time: new Date().getTime()
});

View File

@@ -1,6 +1,7 @@
import * as pg from 'pg';
import * as importer from 'common/interfaces/importer';
import * as fs from 'fs/promises';
import * as pg from 'pg';
import PostgreSQLParser from '../../parsers/PostgreSQLParser';
import { BaseImporter } from '../BaseImporter';

View File

@@ -0,0 +1,16 @@
import { WebFrameMain } from 'electron';
import * as path from 'path';
const isDevelopment = process.env.NODE_ENV !== 'production';
const isWindows = process.platform === 'win32';
const indexPath = path.resolve(__dirname, 'index.html').split(path.sep).join('/');
export function validateSender (frame: WebFrameMain) {
if (process.windowsStore) return true; // TEMP HOTFIX
const frameUrl = new URL(frame.url);
const prefix = isWindows ? 'file:///' : 'file://';
const framePath = frameUrl.href.replace(prefix, '');
if ((isDevelopment && frameUrl.host === 'localhost:9080') || framePath === indexPath) return true;
return false;
}

View File

@@ -1,16 +1,15 @@
import { app, BrowserWindow, globalShortcut, nativeImage, Menu, ipcMain } from 'electron';
import * as path from 'path';
import * as remoteMain from '@electron/remote/main';
import { app, BrowserWindow, ipcMain, nativeImage } from 'electron';
import * as Store from 'electron-store';
import * as windowStateKeeper from 'electron-window-state';
import * as remoteMain from '@electron/remote/main';
import * as path from 'path';
import ipcHandlers from './ipc-handlers';
import { shortcuts } from 'common/shortcuts';
import { OsMenu, ShortcutRegister } from './libs/ShortcutRegister';
Store.initRenderer();
const persistentStore = new Store({ name: 'settings' });
const appTheme = persistentStore.get('application_theme');
const settingsStore = new Store({ name: 'settings' });
const appTheme = settingsStore.get('application_theme');
const isDevelopment = process.env.NODE_ENV !== 'production';
const isMacOS = process.platform === 'darwin';
const isLinux = process.platform === 'linux';
@@ -38,6 +37,7 @@ async function createMainWindow () {
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
devTools: isDevelopment,
spellcheck: false
},
autoHideMenuBar: true,
@@ -86,7 +86,7 @@ else {
ipcHandlers();
ipcMain.on('refresh-theme-settings', () => {
const appTheme = persistentStore.get('application_theme');
const appTheme = settingsStore.get('application_theme');
if (isWindows && mainWindow) {
mainWindow.setTitleBarOverlay({
color: appTheme === 'dark' ? '#3f3f3f' : '#fff',
@@ -124,8 +124,8 @@ else {
if (isWindows)
mainWindow.show();
if (isDevelopment)
mainWindow.webContents.openDevTools();
// if (isDevelopment)
// mainWindow.webContents.openDevTools();
process.on('uncaughtException', error => {
mainWindow.webContents.send('unhandled-exception', error);
@@ -142,41 +142,20 @@ else {
const extensionPath = path.resolve(__dirname, `../../misc/${antares.devtoolsId}`);
window.webContents.session.loadExtension(extensionPath, { allowFileAccess: true }).catch(console.error);
}
});
app.on('browser-window-focus', () => {
// Send registered shortcut events to window
for (const shortcut of shortcuts) {
if (shortcut.os.includes(process.platform)) {
for (const key of shortcut.keys) {
globalShortcut.register(key, () => {
mainWindow.webContents.send(shortcut.event);
if (isDevelopment) console.log('EVENT:', shortcut);
});
}
}
}
window.webContents.on('will-navigate', (e) => { // Prevent browser navigation
e.preventDefault();
});
if (isDevelopment) { // Dev shortcuts
globalShortcut.register('Shift+CommandOrControl+F5', () => {
mainWindow.reload();
});
globalShortcut.register('Shift+CommandOrControl+F12', () => {
mainWindow.webContents.openDevTools();
});
}
});
app.on('browser-window-blur', () => {
globalShortcut.unregisterAll();
window.webContents.on('did-create-window', (w) => { // Close new windows
w.close();
});
});
}
function createAppMenu () {
let menu: Electron.Menu = null;
if (isMacOS) {
menu = Menu.buildFromTemplate([
const menuTemplate: OsMenu = {
darwin: [
{
label: app.name,
submenu: [
@@ -201,16 +180,14 @@ function createAppMenu () {
{
role: 'editMenu'
},
{
role: 'viewMenu'
},
{
role: 'windowMenu'
}
]);
}
]
};
Menu.setApplicationMenu(menu);
const shortCutRegister = ShortcutRegister.getInstance({ mainWindow, menuTemplate, mode: 'local' });
shortCutRegister.init();
}
function saveWindowState () {

View File

@@ -1,5 +1,6 @@
import * as antares from 'common/interfaces/antares';
import * as fs from 'fs';
import { MySQLClient } from '../libs/clients/MySQLClient';
import { PostgreSQLClient } from '../libs/clients/PostgreSQLClient';
import { ClientsFactory } from '../libs/ClientsFactory';
@@ -7,7 +8,7 @@ import MysqlExporter from '../libs/exporters/sql/MysqlExporter';
import PostgreSQLExporter from '../libs/exporters/sql/PostgreSQLExporter';
let exporter: antares.Exporter;
process.on('message', async ({ type, client, tables, options }) => {
process.on('message', async ({ type, client, tables, options }: any) => {
if (type === 'init') {
const connection = await ClientsFactory.getClient({
client: client.name,

View File

@@ -1,6 +1,9 @@
import SSHConfig from '@fabio286/ssh2-promise/lib/sshConfig';
import * as antares from 'common/interfaces/antares';
import * as pg from 'pg';
import { ImportOptions } from 'common/interfaces/importer';
import * as mysql from 'mysql2';
import * as pg from 'pg';
import { MySQLClient } from '../libs/clients/MySQLClient';
import { PostgreSQLClient } from '../libs/clients/PostgreSQLClient';
import { ClientsFactory } from '../libs/ClientsFactory';
@@ -8,70 +11,102 @@ import MySQLImporter from '../libs/importers/sql/MySQLlImporter';
import PostgreSQLImporter from '../libs/importers/sql/PostgreSQLImporter';
let importer: antares.Importer;
process.on('message', async ({ type, dbConfig, options }) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
process.on('message', async ({ type, dbConfig, options }: {
type: string;
dbConfig: mysql.ConnectionOptions & { schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean }
| pg.ClientConfig & { schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean }
| { databasePath: string; readonly: boolean };
options: ImportOptions;
}) => {
if (type === 'init') {
const connection = await ClientsFactory.getClient({
client: options.type,
params: {
...dbConfig,
schema: options.schema
},
poolSize: 1
}) as MySQLClient | PostgreSQLClient;
try {
const connection = await ClientsFactory.getClient({
client: options.type,
params: {
...dbConfig,
schema: options.schema
},
poolSize: 1
}) as MySQLClient | PostgreSQLClient;
const pool = await connection.getConnectionPool();
const pool = await connection.getConnectionPool();
switch (options.type) {
case 'mysql':
case 'maria':
importer = new MySQLImporter(pool as unknown as mysql.Pool, options);
break;
case 'pg':
importer = new PostgreSQLImporter(pool as unknown as pg.PoolClient, options);
break;
default:
switch (options.type) {
case 'mysql':
case 'maria':
importer = new MySQLImporter(pool as unknown as mysql.Pool, options);
break;
case 'pg':
importer = new PostgreSQLImporter(pool as unknown as pg.PoolClient, options);
break;
default:
process.send({
type: 'error',
payload: `"${options.type}" importer not aviable`
});
return;
}
importer.once('error', err => {
console.error(err);
process.send({
type: 'error',
payload: `"${options.type}" importer not aviable`
payload: err.toString()
});
return;
}
});
importer.once('error', err => {
importer.once('end', () => {
process.send({
type: 'end',
payload: { cancelled: importer.isCancelled }
});
});
importer.once('cancel', () => {
process.send({ type: 'cancel' });
});
importer.on('progress', state => {
process.send({
type: 'import-progress',
payload: state
});
});
importer.on('query-error', state => {
process.send({
type: 'query-error',
payload: state
});
});
importer.run();
}
catch (err) {
console.error(err);
process.send({
type: 'error',
payload: err.toString()
});
});
importer.once('end', () => {
process.send({
type: 'end',
payload: { cancelled: importer.isCancelled }
});
});
importer.once('cancel', () => {
process.send({ type: 'cancel' });
});
importer.on('progress', state => {
process.send({
type: 'import-progress',
payload: state
});
});
importer.on('query-error', state => {
process.send({
type: 'query-error',
payload: state
});
});
importer.run();
}
}
else if (type === 'cancel')
importer.cancel();
});
process.on('uncaughtException', (err) => {
console.error(err);
process.send({
type: 'error',
payload: err.toString()
});
});
process.on('unhandledRejection', (err) => {
console.error(err);
process.send({
type: 'error',
payload: err.toString()
});
});

View File

@@ -21,21 +21,32 @@
<BaseTextEditor class="d-none" value="" />
</div>
</div>
<ModalAllConnections v-if="isAllConnectionsModal" @close="isAllConnectionsModal = false" />
<ModalAllConnections
v-if="isAllConnectionsModal"
@close="isAllConnectionsModal = false"
/>
<ModalExportSchema
v-if="isExportSchemaModal"
@close="hideExportModal"
/>
</div>
</template>
<script setup lang="ts">
import { defineAsyncComponent, onMounted, Ref, ref } from 'vue';
import { storeToRefs } from 'pinia';
import { getCurrentWindow, Menu } from '@electron/remote';
import { ipcRenderer } from 'electron';
import { storeToRefs } from 'pinia';
import { defineAsyncComponent, onMounted, Ref, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Menu, getCurrentWindow } from '@electron/remote';
import ModalExportSchema from '@/components/ModalExportSchema.vue';
import TheSettingBar from '@/components/TheSettingBar.vue';
import { useApplicationStore } from '@/stores/application';
import { useConnectionsStore } from '@/stores/connections';
import { useSchemaExportStore } from '@/stores/schemaExport';
import { useSettingsStore } from '@/stores/settings';
import { useWorkspacesStore } from '@/stores/workspaces';
import TheSettingBar from '@/components/TheSettingBar.vue';
const { t } = useI18n();
@@ -65,11 +76,11 @@ const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const { checkVersionUpdate } = applicationStore;
const { changeApplicationTheme } = settingsStore;
const isAllConnectionsModal: Ref<boolean> = ref(false);
const schemaExportStore = useSchemaExportStore();
const { hideExportModal } = schemaExportStore;
const { isExportModal: isExportSchemaModal } = storeToRefs(schemaExportStore);
ipcRenderer.on('open-connections-modal', () => {
isAllConnectionsModal.value = true;
});
const isAllConnectionsModal: Ref<boolean> = ref(false);
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
@@ -78,27 +89,43 @@ document.addEventListener('DOMContentLoaded', () => {
});
onMounted(() => {
ipcRenderer.on('open-all-connections', () => {
isAllConnectionsModal.value = true;
});
ipcRenderer.on('open-scratchpad', () => {
isScratchpad.value = true;
});
ipcRenderer.on('open-settings', () => {
isSettingModal.value = true;
});
ipcRenderer.on('create-connection', () => {
workspacesStore.selectWorkspace('NEW');
});
ipcRenderer.send('check-for-updates');
checkVersionUpdate();
const InputMenu = Menu.buildFromTemplate([
{
label: t('word.cut'),
label: t('general.cut'),
role: 'cut'
},
{
label: t('word.copy'),
label: t('general.copy'),
role: 'copy'
},
{
label: t('word.paste'),
label: t('general.paste'),
role: 'paste'
},
{
type: 'separator'
},
{
label: t('message.selectAll'),
label: t('general.selectAll'),
role: 'selectAll'
}
]);
@@ -118,6 +145,12 @@ onMounted(() => {
node = node.parentNode;
}
});
document.addEventListener('keydown', e => {
if (e.altKey && e.key === 'Alt') { // Prevent Alt key to trigger hidden shortcut menu
e.preventDefault();
}
});
});
</script>

View File

@@ -31,13 +31,13 @@
class="btn btn-primary mr-2"
@click.stop="confirmModal"
>
{{ confirmText || t('word.confirm') }}
{{ confirmText || t('general.confirm') }}
</button>
<button
class="btn btn-link"
@click="hideModal"
>
{{ cancelText || t('word.cancel') }}
{{ cancelText || t('general.cancel') }}
</button>
</div>
</div>
@@ -47,10 +47,11 @@
</template>
<script setup lang="ts">
import { useFocusTrap } from '@/composables/useFocusTrap';
import { computed, onBeforeUnmount, PropType, useSlots } from 'vue';
import { useI18n } from 'vue-i18n';
import { useFocusTrap } from '@/composables/useFocusTrap';
const { t } = useI18n();
const props = defineProps({
@@ -68,6 +69,10 @@ const props = defineProps({
disableAutofocus: {
type: Boolean,
default: false
},
closeOnConfirm: {
type: Boolean,
default: true
}
});
const emit = defineEmits(['confirm', 'hide']);
@@ -90,7 +95,7 @@ const modalSizeClass = computed(() => {
const confirmModal = () => {
emit('confirm');
hideModal();
if (props.closeOnConfirm) hideModal();
};
const hideModal = () => {

View File

@@ -1,5 +1,5 @@
<template>
<div class="context" :class="{'bottom': isBottom}">
<div class="context" :class="[{ 'bottom': isBottom }, { 'right': isRight }]">
<a
class="context-overlay"
@click="close"
@@ -19,9 +19,10 @@
import { computed, onBeforeUnmount, onMounted, Ref, ref } from 'vue';
const contextContent: Ref<HTMLDivElement> = ref(null);
const contextSize: Ref<DOMRect> = ref(null);
const contextSize: Ref<{height: number; width: number; subHeight?: number; subWidth?: number}> = ref(null);
const isBottom: Ref<boolean> = ref(false);
const props = defineProps<{contextEvent: MouseEvent}>();
const isRight: Ref<boolean> = ref(false);
const props = defineProps<{ contextEvent: MouseEvent }>();
const emit = defineEmits(['close-context']);
const position = computed(() => {
@@ -39,8 +40,16 @@ const position = computed(() => {
isBottom.value = true;
}
if (clientX + contextSize.value.width + 5 >= window.innerWidth)
if (clientY + contextSize.value.subHeight + contextSize.value.height >= window.innerHeight)
isBottom.value = true;
if (clientX + contextSize.value.width + 5 >= window.innerWidth) {
leftCord = `${clientX - contextSize.value.width}px`;
isRight.value = true;
}
if (clientX + contextSize.value.subWidth + contextSize.value.width >= window.innerWidth)
isRight.value = true;
}
}
@@ -62,8 +71,20 @@ const onKey = (e: KeyboardEvent) => {
window.addEventListener('keydown', onKey);
onMounted(() => {
if (contextContent.value)
if (contextContent.value) {
contextSize.value = contextContent.value.getBoundingClientRect();
const submenus = contextContent.value.querySelectorAll<HTMLDivElement>('.context-submenu');
for (const submenu of submenus) {
const submenuSize = submenu.getBoundingClientRect();
if (!contextSize.value.subHeight || submenuSize.height > contextSize.value.subHeight)
contextSize.value.subHeight = submenuSize.height;
if (!contextSize.value.subWidth || submenuSize.width > contextSize.value.subWidth)
contextSize.value.subWidth = submenuSize.width;
}
}
});
onBeforeUnmount(() => {
@@ -73,88 +94,94 @@ onBeforeUnmount(() => {
<style lang="scss">
.context {
display: flex;
font-size: 16px;
z-index: 400;
justify-content: center;
align-items: center;
overflow: hidden;
position: fixed;
height: 100vh;
right: 0;
top: 0;
left: 0;
bottom: 0;
display: flex;
font-size: 16px;
z-index: 400;
justify-content: center;
align-items: center;
overflow: hidden;
position: fixed;
height: 100vh;
right: 0;
top: 0;
left: 0;
bottom: 0;
&:not(.bottom) .context-submenu {
top: -0.2rem;
}
&:not(.bottom) .context-submenu {
top: -0.2rem;
}
&.bottom .context-submenu {
bottom: -0.2rem;
}
&.bottom .context-submenu {
bottom: -0.2rem;
}
.context-container {
min-width: 100px;
z-index: 10;
padding: 0;
background: #1d1d1d;
border-radius: $border-radius;
border: 1px solid $bg-color-light-dark;
display: flex;
flex-direction: column;
position: absolute;
pointer-events: initial;
&:not(.right) .context-submenu {
left: 100%;
}
.context-element {
display: flex;
align-items: center;
margin: 0.2rem;
padding: 0.1rem 0.3rem;
&.right .context-submenu {
right: 100%;
}
.context-container {
min-width: 100px;
z-index: 10;
padding: 0;
background: #1d1d1d;
border-radius: $border-radius;
cursor: pointer;
justify-content: space-between;
position: relative;
white-space: nowrap;
border: 1px solid $bg-color-light-dark;
display: flex;
flex-direction: column;
position: absolute;
pointer-events: initial;
.context-submenu {
border-radius: $border-radius;
border: 1px solid $bg-color-light-dark;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s;
position: absolute;
left: 100%;
min-width: 100px;
background: #1d1d1d;
.context-element {
display: flex;
align-items: center;
margin: 0.2rem;
padding: 0.1rem 0.3rem;
border-radius: $border-radius;
cursor: pointer;
justify-content: space-between;
position: relative;
white-space: nowrap;
.context-submenu {
border-radius: $border-radius;
border: 1px solid $bg-color-light-dark;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s;
position: absolute;
min-width: 100px;
background: #1d1d1d;
}
&:hover {
.context-submenu {
display: block;
visibility: visible;
opacity: 1;
}
}
}
}
&:hover {
.context-submenu {
display: block;
visibility: visible;
opacity: 1;
}
}
}
}
.context-overlay {
background: transparent;
bottom: 0;
cursor: default;
display: block;
left: 0;
position: absolute;
right: 0;
top: 0;
}
.context-overlay {
background: transparent;
bottom: 0;
cursor: default;
display: block;
left: 0;
position: absolute;
right: 0;
top: 0;
}
}
.disabled {
pointer-events: none;
filter: grayscale(100%);
opacity: 0.5;
pointer-events: none;
filter: grayscale(100%);
opacity: 0.5;
}
</style>

View File

@@ -0,0 +1,62 @@
<template>
<SvgIcon
:type="type"
:path="iconPath"
:size="size"
:rotate="rotate"
:class="iconFlip"
/>
</template>
<script setup lang="ts">
import SvgIcon from '@jamescoyle/vue-icon';
import * as Icons from '@mdi/js';
import { computed, PropType } from 'vue';
const props = defineProps({
iconName: {
type: String,
required: true
},
size: {
type: Number,
default: 48
},
type: {
type: String,
default: () => 'mdi'
},
flip: {
type: String as PropType<'horizontal' | 'vertical' | 'both'>,
default: () => null
},
rotate: {
type: Number,
default: () => null
}
});
const iconPath = computed(() => {
return (Icons as {[k:string]: string})[props.iconName];
});
const iconFlip = computed(() => {
if (['horizontal', 'vertical', 'both'].includes(props.flip))
return `flip-${props.flip}`;
else return '';
});
</script>
<style lang="scss" scoped>
.flip-horizontal {
transform: scaleX(-1);
}
.flip-vertical {
transform: scaleY(-1);
}
.flip-both {
transform: scale(-1, -1);
}
</style>

View File

@@ -3,15 +3,15 @@
</template>
<script setup lang="ts">
import { onMounted, PropType, Ref, ref } from 'vue';
import * as L from 'leaflet';
import {
point,
lineString,
point,
polygon
} from '@turf/helpers';
import { GeoJsonObject } from 'geojson';
import { getArrayDepth } from 'common/libs/getArrayDepth';
import { GeoJsonObject } from 'geojson';
import * as L from 'leaflet';
import { onMounted, PropType, Ref, ref } from 'vue';
interface Coordinates { x: number; y: number }

View File

@@ -1,13 +1,18 @@
<template>
<div class="toast mt-2" :class="notificationStatus.className">
<span class="p-vcentered text-left" :class="{'expanded': isExpanded}">
<i class="mdi mdi-24px mr-2" :class="notificationStatus.iconName" />
<BaseIcon
:icon-name="notificationStatus.iconName"
class="mr-2"
:size="24"
/>
<span class="notification-message">{{ message }}</span>
</span>
<i
<BaseIcon
v-if="isExpandable"
class="mdi mdi-24px c-hand expand-btn"
:class="isExpanded ? 'mdi-chevron-up' : 'mdi-chevron-down'"
:icon-name="isExpanded ? 'mdiChevronUp' : 'mdiChevronDown'"
class=" c-hand expand-btn"
:size="24"
@click="toggleExpand"
/>
<button class="btn btn-clear ml-2" @click="hideToast" />
@@ -17,6 +22,8 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import BaseIcon from '@/components/BaseIcon.vue';
const props = defineProps({
message: {
type: String,
@@ -36,19 +43,19 @@ const notificationStatus = computed(() => {
switch (props.status) {
case 'success':
className = 'toast-success';
iconName = 'mdi-check';
iconName = 'mdiCheck';
break;
case 'error':
className = 'toast-error';
iconName = 'mdi-alert-rhombus';
iconName = 'mdiAlertRhombus';
break;
case 'warning':
className = 'toast-warning';
iconName = 'mdi-alert';
iconName = 'mdiAlert';
break;
case 'primary':
className = 'toast-primary';
iconName = 'mdi-information-outline';
iconName = 'mdiInformationOutline';
break;
}

View File

@@ -70,7 +70,7 @@
</template>
<script>
import { defineComponent, computed, ref, watch, nextTick, onMounted, onUnmounted } from 'vue';
import { computed, defineComponent, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
export default defineComponent({
name: 'BaseSelect',

View File

@@ -10,12 +10,16 @@
</template>
<script setup lang="ts">
import { onMounted, watch } from 'vue';
/* eslint-disable simple-import-sort/imports */
import * as ace from 'ace-builds';
import 'ace-builds/webpack-resolver';
import { storeToRefs } from 'pinia';
import { useSettingsStore } from '@/stores/settings';
/* eslint-enable simple-import-sort/imports */
import { uidGen } from 'common/libs/uidGen';
import { storeToRefs } from 'pinia';
import { onMounted, watch } from 'vue';
import { useSettingsStore } from '@/stores/settings';
const props = defineProps({
modelValue: String,
@@ -44,6 +48,11 @@ watch(() => props.mode, () => {
editor.session.setMode(`ace/mode/${props.mode}`);
});
watch(() => props.modelValue, () => {
if (editor && props.readOnly)
editor.session.setValue(props.modelValue);
});
watch(editorTheme, () => {
if (editor)
editor.setTheme(`ace/theme/${editorTheme.value}`);
@@ -51,14 +60,17 @@ watch(editorTheme, () => {
watch(editorFontSize, () => {
const sizes = {
small: 12,
medium: 14,
large: 16
xsmall: '10px',
small: '12px',
medium: '14px',
large: '16px',
xlarge: '18px',
xxlarge: '20px'
};
if (editor) {
editor.setOptions({
fontSize: sizes[editorFontSize.value as undefined as 'small' | 'medium' | 'large']
fontSize: sizes[editorFontSize.value]
});
}
});
@@ -110,6 +122,8 @@ onMounted(() => {
}, 20);
}
editor.commands.removeCommand('showSettingsMenu');
setTimeout(() => {
editor.resize();
}, 20);
@@ -122,9 +136,4 @@ onMounted(() => {
width: 100%;
}
}
.ace_.mdi {
display: inline-block;
width: 17px;
}
</style>

View File

@@ -1,76 +0,0 @@
<template>
<div
:style="{display: isVisible ? 'flex' : 'none'}"
class="toast mt-2"
:class="toastStatus.className"
>
<span class="p-vcentered text-left"><i class="mdi mdi-24px mr-1" :class="toastStatus.iconName" /> {{ message }}</span>
<button class="btn btn-clear" @click="hideToast" />
</div>
</template>
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
const props = defineProps({
message: {
type: String,
default: ''
},
status: {
type: String,
default: ''
}
});
const isVisible = ref(false);
const message = ref(props.message);
const emit = defineEmits(['close']);
const toastStatus = computed(() => {
let className = '';
let iconName = '';
switch (props.status) {
case 'success':
className = 'toast-success';
iconName = 'mdi-check';
break;
case 'error':
className = 'toast-error';
iconName = 'mdi-alert-rhombus';
break;
case 'warning':
className = 'toast-warning';
iconName = 'mdi-alert';
break;
case 'primary':
className = 'toast-primary';
iconName = 'mdi-information-outline';
break;
}
return { className, iconName };
});
watch(message, () => {
if (message.value)
isVisible.value = true;
else
isVisible.value = false;
});
const hideToast = () => {
isVisible.value = false;
emit('close');
};
</script>
<style scoped>
.toast {
display: flex;
justify-content: space-between;
user-select: text;
word-break: break-all;
}
</style>

View File

@@ -1,14 +1,20 @@
<template>
<label :for="`id_${id}`" class="file-uploader">
<span class="file-uploader-message">
<i class="mdi mdi-folder-open mr-1" />{{ message }}
<BaseIcon
icon-name="mdiFolderOpen"
class="mr-1 mt-1"
:size="18"
/>{{ message }}
</span>
<span class="text-ellipsis file-uploader-value">
{{ lastPart(modelValue, 19) }}
</span>
<i
<BaseIcon
v-if="modelValue"
class="file-uploader-reset mdi mdi-close"
class="file-upload-icon-clear"
icon-name="mdiClose"
:size="18"
@click.prevent="clear"
/>
<form :ref="`form_${id}`">
@@ -16,6 +22,7 @@
:id="`id_${id}`"
class="file-uploader-input"
type="file"
:accept="accept"
@change="$emit('change', $event)"
>
</form>
@@ -24,6 +31,8 @@
<script setup lang="ts">
import { uidGen } from 'common/libs/uidGen';
import BaseIcon from '@/components/BaseIcon.vue';
import { useFilters } from '@/composables/useFilters';
const { lastPart } = useFilters();
@@ -33,6 +42,10 @@ defineProps({
default: 'Browse',
type: String
},
accept: {
default: '',
type: String
},
modelValue: {
default: '',
type: String
@@ -59,6 +72,12 @@ const clear = () => {
position: relative;
flex: 1 1 auto;
.file-upload-icon-clear {
position: absolute;
right: 4px;
top: 8px;
}
> span {
padding: 0.25rem 0.4rem;
}

View File

@@ -4,10 +4,10 @@
v-model="selectedGroup"
class="form-select"
:options="[{name: 'manual'}, ...fakerGroups]"
:option-label="(opt: any) => opt.name === 'manual' ? t('message.manualValue') : t(`faker.${opt.name}`)"
:option-label="(opt: any) => opt.name === 'manual' ? t('general.manualValue') : t(`faker.${opt.name}`)"
option-track-by="name"
:disabled="!isChecked"
style="flex-grow: 0;"
:style="'flex-grow: 0;'"
@change="onChange"
/>
@@ -41,7 +41,7 @@
<BaseUploadInput
v-else-if="inputProps().type === 'file'"
:model-value="selectedValue"
:message="t('word.browse')"
:message="t('general.browse')"
@clear="clearValue"
@change="filesChange($event)"
/>
@@ -86,13 +86,14 @@
</template>
<script setup lang="ts">
import FakerMethods from 'common/FakerMethods';
import { BIT, BLOB, DATE, DATETIME, FLOAT, IS_BIGINT, LONG_TEXT, NUMBER, TEXT, TIME, UUID } from 'common/fieldTypes';
import { computed, PropType, Ref, ref, watch } from 'vue';
import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
import { useI18n } from 'vue-i18n';
import BaseSelect from '@/components/BaseSelect.vue';
import BaseUploadInput from '@/components/BaseUploadInput.vue';
import ForeignKeySelect from '@/components/ForeignKeySelect.vue';
import FakerMethods from 'common/FakerMethods';
import BaseSelect from '@/components/BaseSelect.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
@@ -126,6 +127,8 @@ const fakerGroups = computed(() => {
localType.value = 'datetime';
else if (TIME.includes(props.type))
localType.value = 'time';
else if (UUID.includes(props.type))
localType.value = 'uuid';
else
localType.value = 'none';
@@ -144,8 +147,12 @@ const inputProps = () => {
if ([...TEXT, ...LONG_TEXT].includes(props.type))
return { type: 'text', mask: false };
if ([...NUMBER, ...FLOAT].includes(props.type))
return { type: 'number', mask: false };
if ([...NUMBER, ...FLOAT].includes(props.type)) {
if (IS_BIGINT.includes(props.type))
return { type: 'text', mask: false };
else
return { type: 'number', mask: false };
}
if (TIME.includes(props.type)) {
let timeMask = '##:##:##';

View File

@@ -13,15 +13,16 @@
</template>
<script setup lang="ts">
import { computed, Ref, ref, watch } from 'vue';
import { LONG_TEXT, TEXT } from 'common/fieldTypes';
import { TableField } from 'common/interfaces/antares';
import { storeToRefs } from 'pinia';
import { computed, Ref, ref, watch } from 'vue';
import BaseSelect from '@/components/BaseSelect.vue';
import { useFilters } from '@/composables/useFilters';
import Tables from '@/ipc-api/Tables';
import { useNotificationsStore } from '@/stores/notifications';
import { useWorkspacesStore } from '@/stores/workspaces';
import { TEXT, LONG_TEXT } from 'common/fieldTypes';
import BaseSelect from '@/components/BaseSelect.vue';
import { TableField } from 'common/interfaces/antares';
import { useFilters } from '@/composables/useFilters';
const props = defineProps({
modelValue: [String, Number],

View File

@@ -0,0 +1,128 @@
<template>
<div class="form-group has-icon-right m-0">
<input
class="form-input"
type="text"
:value="pressedKeys"
:placeholder="t('application.registerAShortcut')"
@focus="isFocus = true"
@blur="isFocus = false"
@keydown.prevent.stop="onKey"
>
<BaseIcon
icon-name="mdiKeyboardOutline"
class="form-icon"
:size="24"
/>
</div>
</template>
<script setup lang="ts">
import { computed, PropType, Ref, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import BaseIcon from '@/components/BaseIcon.vue';
import Application from '@/ipc-api/Application';
const { t } = useI18n();
const emit = defineEmits(['update:modelValue']);
const isMacOS = process.platform === 'darwin';
const props = defineProps({
modelValue: String as PropType<string | Electron.Accelerator>
});
const isFocus = ref(false);
const keyboardEvent: Ref<KeyboardEvent> = ref(null);
const pressedKeys = computed(() => {
const keys: string[] = [];
const singleKeysToIgnore = ['Dead', 'Backspace', 'ArrotLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
const specialKeys = ['Control', 'Alt', 'AltGraph', 'Shift', 'Meta', 'CapsLock', 'ContextMenu', 'Escape'];
const keysFromCode = ['Space', 'Minus', 'Equal', 'Slash', 'Quote', 'Semicolon', 'Comma', 'Period', 'Backslash', 'BracketLeft', 'BracketRight'];
if (props.modelValue && !keyboardEvent.value)
return props.modelValue;
else if (keyboardEvent.value) {
if (keyboardEvent.value.altKey)
keys.push('Alt');
if (keyboardEvent.value.ctrlKey)
keys.push('Control');
if (keyboardEvent.value.metaKey && isMacOS)
keys.push('Command');
if (keyboardEvent.value.shiftKey && keys.length)
keys.push('Shift');
if (keyboardEvent.value.code) {
if (keys.length === 0 && (keyboardEvent.value.key.length === 1 || singleKeysToIgnore.includes(keyboardEvent.value.key)))
return t('application.invalidShortcutMessage');
else if (!specialKeys.includes(keyboardEvent.value.key)) {
if (keyboardEvent.value.key === 'Dead') {
keys.push(keyboardEvent.value.code
.replace('Digit', '')
.replace('Key', '')
.replace('Quote', '\'')
.replace('Backquote', '`'));
}
else if (keysFromCode.includes(keyboardEvent.value.code) || keyboardEvent.value.code.includes('Digit')) {
keys.push(keyboardEvent.value.code
.replace('Quote', '\'')
.replace('Semicolon', ';')
.replace('Slash', '/')
.replace('Backslash', '\\')
.replace('BracketLeft', '[')
.replace('BracketRight', ']')
.replace('Comma', ',')
.replace('Period', '.')
.replace('Minus', '-')
.replace('Equal', '=')
.replace('Digit', '')
.replace('Key', ''));
}
else {
keys.push(keyboardEvent.value.key.length === 1
? keyboardEvent.value.key.toUpperCase()
: keyboardEvent.value.key
.replace('Arrow', '')
);
}
}
else
return t('application.invalidShortcutMessage');
}
}
return keys.join('+');
});
const onKey = (e: KeyboardEvent) => {
e.stopPropagation();
e.preventDefault();
keyboardEvent.value = e;
};
watch(pressedKeys, (value) => {
if (value !== t('application.invalidShortcutMessage'))
emit('update:modelValue', pressedKeys.value);
});
watch(isFocus, (val) => {
if (val)
Application.unregisterShortcuts();
else
Application.reloadShortcuts();
});
</script>
<style lang="scss" scoped>
.has-icon-right {
.form-input {
padding-right: 1.8rem;
overflow: hidden;
text-overflow: ellipsis;
caret-color: transparent;
}
.form-icon {
right: 0.4rem;
}
}
</style>

View File

@@ -6,8 +6,12 @@
<div class="modal-header pl-2">
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-apps mr-1" />
<span class="cut-text">{{ t('message.allConnections') }}</span>
<BaseIcon
icon-name="mdiApps"
class="mr-1"
:size="24"
/>
<span class="cut-text">{{ t('connection.allConnections') }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -21,13 +25,20 @@
v-model="searchTerm"
class="form-input"
type="text"
:placeholder="t('message.searchForConnections')"
:placeholder="t('connection.searchForConnections')"
@keypress.esc="searchTerm = ''"
>
<i v-if="!searchTerm" class="form-icon mdi mdi-magnify mdi-18px pr-4" />
<i
<BaseIcon
v-if="!searchTerm"
icon-name="mdiMagnify"
class="form-icon pr-4"
:size="18"
/>
<BaseIcon
v-else
class="form-icon c-hand mdi mdi-backspace mdi-18px pr-4"
icon-name="mdiBackspace"
class="form-icon c-hand pr-4"
:size="18"
@click="searchTerm = ''"
/>
</div>
@@ -55,23 +66,12 @@
<div class="panel-subtitle">
{{ clients.get(connection.client) || connection.client }}
</div>
<div class="all-connections-buttons p-absolute d-flex" style="top: 0; right: 0;">
<i
v-if="connection.isPinned"
class="all-connections-pinned mdi mdi-18px"
:class="connectionHover === connection.uid ? 'mdi-pin-off' : 'mdi-pin'"
:title="t('word.unpin')"
@click.stop="unpinConnection(connection.uid)"
/>
<i
v-else
class="all-connections-pin mdi mdi-18px mdi-pin mdi-rotate-45"
:title="t('word.pin')"
@click.stop="pinConnection(connection.uid)"
/>
<i
class="all-connections-delete mdi mdi-delete mdi-18px ml-2"
:title="t('word.delete')"
<div class="all-connections-buttons p-absolute d-flex" :style="'top: 0; right: 0;'">
<BaseIcon
icon-name="mdiDelete"
class="all-connections-delete ml-2"
:title="t('general.delete')"
:size="18"
@click.stop="askToDelete(connection)"
/>
</div>
@@ -79,32 +79,57 @@
<div class="panel-body text-center">
<div v-if="connection.databasePath">
<div class="text-ellipsis" :title="connection.databasePath">
<i class="mdi mdi-database d-inline" /> <span class="text-bold">{{
<BaseIcon
icon-name="mdiDatabase"
class="p-relative"
:style="'top:3px'"
:size="18"
/> <span class="text-bold">{{
connection.databasePath
}}</span>
</div>
</div>
<div v-else>
<div class="text-ellipsis" :title="`${connection.host}:${connection.port}`">
<i class="mdi mdi-server d-inline" /> <span class="text-bold">{{ connection.host
<BaseIcon
icon-name="mdiServer"
class="p-relative"
:style="'top:3px'"
:size="18"
/> <span class="text-bold">{{ connection.host
}}:{{ connection.port }}</span>
</div>
</div>
<div v-if="connection.user">
<div class="text-ellipsis">
<i class="mdi mdi-account d-inline" /> <span class="text-bold">{{ connection.user
<BaseIcon
icon-name="mdiAccount"
class="p-relative"
:style="'top:3px'"
:size="18"
/> <span class="text-bold">{{ connection.user
}}</span>
</div>
</div>
<div v-if="connection.schema">
<div class="text-ellipsis">
<i class="mdi mdi-database d-inline" /> <span class="text-bold">{{ connection.schema
<BaseIcon
icon-name="mdiDatabase"
class="p-relative"
:style="'top:3px'"
:size="18"
/> <span class="text-bold">{{ connection.schema
}}</span>
</div>
</div>
<div v-if="connection.database">
<div class="text-ellipsis">
<i class="mdi mdi-database d-inline" /> <span class="text-bold">{{
<BaseIcon
icon-name="mdiDatabase"
class="p-relative"
:style="'top:3px'"
:size="18"
/> <span class="text-bold">{{
connection.database
}}</span>
</div>
@@ -112,11 +137,19 @@
</div>
<div class="panel-footer text-center py-0">
<div v-if="connection.ssl" class="chip bg-success mt-2">
<i class="mdi mdi-lock mdi-18px mr-1" />
<BaseIcon
icon-name="mdiShieldKey"
class="mr-1"
:size="18"
/>
SSL
</div>
<div v-if="connection.ssh" class="chip bg-success mt-2">
<i class="mdi mdi-console-network mdi-18px mr-1" />
<BaseIcon
icon-name="mdiConsoleNetwork"
class="mr-1"
:size="18"
/>
SSH
</div>
</div>
@@ -126,7 +159,7 @@
key="trick"
readonly
class="p-absolute"
style="width: 1px; height: 1px; opacity: 0"
:style="'width: 1px; height: 1px; opacity: 0;'"
type="text"
>
<!-- workaround for useFocusTrap $lastFocusable -->
@@ -143,12 +176,16 @@
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-server-remove mr-1" /> {{ t('message.deleteConnection') }}
<BaseIcon
icon-name="mdiServerRemove"
class="mr-1"
:size="24"
/> {{ t('connection.deleteConnection') }}
</div>
</template>
<template #body>
<div class="mb-2">
{{ t('message.deleteCorfirm') }} <b>{{ selectedConnectionName }}</b>?
{{ t('general.deleteConfirm') }} <b>{{ selectedConnectionName }}</b>?
</div>
</template>
</ConfirmModal>
@@ -156,14 +193,16 @@
</template>
<script setup lang="ts">
import { computed, onBeforeUnmount, Ref, ref } from 'vue';
import { ConnectionParams } from 'common/interfaces/antares';
import { storeToRefs } from 'pinia';
import { computed, onBeforeUnmount, Ref, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import BaseIcon from '@/components/BaseIcon.vue';
import { useFocusTrap } from '@/composables/useFocusTrap';
import { useConnectionsStore } from '@/stores/connections';
import { useWorkspacesStore } from '@/stores/workspaces';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import { ConnectionParams } from 'common/interfaces/antares';
const { t } = useI18n();
@@ -171,15 +210,12 @@ const connectionsStore = useConnectionsStore();
const workspacesStore = useWorkspacesStore();
const { connections,
pinnedConnections,
lastConnections
} = storeToRefs(connectionsStore);
const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const {
getConnectionName,
pinConnection,
unpinConnection,
deleteConnection
} = connectionsStore;
const { selectWorkspace } = workspacesStore;
@@ -206,13 +242,10 @@ const sortedConnections = computed(() => {
const connTime = lastConnections.value.find((lc) => lc.uid === c.uid)?.time || 0;
return {
...c,
time: connTime,
isPinned: pinnedConnections.value.has(c.uid)
time: connTime
};
})
.sort((a, b) => {
if (a.isPinned < b.isPinned) return 1;
if (a.isPinned > b.isPinned) return -1;
if (a.time < b.time) return 1;
if (a.time > b.time) return -1;
return 0;
@@ -270,89 +303,87 @@ onBeforeUnmount(() => {
<style lang="scss" scoped>
.vscroll {
height: 1000px;
overflow: auto;
overflow-anchor: none;
height: 1000px;
overflow: auto;
overflow-anchor: none;
}
.column-resizable {
&:hover,
&:active {
resize: horizontal;
overflow: hidden;
}
&:hover,
&:active {
resize: horizontal;
overflow: hidden;
}
}
.table-column-title {
display: flex;
align-items: center;
display: flex;
align-items: center;
}
.sort-icon {
font-size: 0.7rem;
line-height: 1;
margin-left: 0.2rem;
font-size: 0.7rem;
line-height: 1;
margin-left: 0.2rem;
}
.modal {
align-items: flex-start;
align-items: flex-start;
.modal-container {
max-width: 75vw;
margin-top: 10vh;
.modal-container {
max-width: 75vw;
margin-top: 10vh;
.modal-body {
height: 80vh;
}
}
.modal-body {
height: 80vh;
}
}
}
.connections-search {
display: flex;
justify-content: space-around;
display: flex;
justify-content: space-around;
}
.connection-block {
cursor: pointer;
transition: all .2s;
border-radius: $border-radius;
outline: none;
cursor: pointer;
transition: all 0.2s;
border-radius: $border-radius;
outline: none;
&:focus {
box-shadow: 0 0 3px .1rem rgba($primary-color, 80%);
}
&:hover {
.all-connections-buttons {
.all-connections-delete,
.all-connections-pinned,
.all-connections-pin {
opacity: .5;
}
}
}
.all-connections-buttons {
.all-connections-pinned {
opacity: .3;
transition: opacity .2s;
&:hover {
opacity: 1;
}
}
&:focus {
box-shadow: 0 0 3px 0.1rem rgba($primary-color, 80%);
}
&:hover {
.all-connections-buttons {
.all-connections-delete,
.all-connections-pinned,
.all-connections-pin {
opacity: 0;
transition: opacity .2s;
&:hover {
opacity: 1;
}
opacity: 0.5;
}
}
}
}
.all-connections-buttons {
.all-connections-pinned {
opacity: 0.3;
transition: opacity 0.2s;
&:hover {
opacity: 1;
}
}
.all-connections-delete,
.all-connections-pin {
opacity: 0;
transition: opacity 0.2s;
&:hover {
opacity: 1;
}
}
}
}
</style>

View File

@@ -6,7 +6,11 @@
<div class="modal-header pl-2">
<div class="modal-title h6">
<div class="d-flex">
<i class="mdi mdi-24px mdi-key-variant mr-1" /> {{ t('word.credentials') }}
<BaseIcon
icon-name="mdiKeyVariant"
class="mr-1"
:size="24"
/> {{ t('connection.credentials') }}
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
@@ -16,7 +20,7 @@
<form class="form-horizontal">
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ t('word.user') }}</label>
<label class="form-label">{{ t('connection.user') }}</label>
</div>
<div class="col-9">
<input
@@ -29,7 +33,7 @@
</div>
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ t('word.password') }}</label>
<label class="form-label">{{ t('connection.password') }}</label>
</div>
<div class="col-9">
<input
@@ -44,10 +48,10 @@
</div>
<div class="modal-footer">
<button class="btn btn-primary mr-2" @click.stop="sendCredentials">
{{ t('word.send') }}
{{ t('general.send') }}
</button>
<button class="btn btn-link" @click.stop="closeModal">
{{ t('word.close') }}
{{ t('general.close') }}
</button>
</div>
</div>
@@ -57,9 +61,11 @@
<script setup lang="ts">
import { Ref, ref } from 'vue';
import { useFocusTrap } from '@/composables/useFocusTrap';
import { useI18n } from 'vue-i18n';
import BaseIcon from '@/components/BaseIcon.vue';
import { useFocusTrap } from '@/composables/useFocusTrap';
const { t } = useI18n();
const { trapRef } = useFocusTrap();

View File

@@ -1,15 +1,19 @@
<template>
<ConfirmModal
:confirm-text="t('word.run')"
:cancel-text="t('word.cancel')"
:confirm-text="t('general.run')"
:cancel-text="t('general.cancel')"
size="400"
@confirm="runRoutine"
@hide="closeModal"
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-play mr-1" />
<span class="cut-text">{{ t('word.parameters') }}: {{ localRoutine.name }}</span>
<BaseIcon
icon-name="mdiPlay"
class="mr-1"
:size="24"
/>
<span class="cut-text">{{ t('database.parameters') }}: {{ localRoutine.name }}</span>
</div>
</template>
<template #body>
@@ -48,13 +52,15 @@
</template>
<script setup lang="ts">
import { computed, PropType, Ref, ref } from 'vue';
import { NUMBER, FLOAT } from 'common/fieldTypes';
import { FLOAT, NUMBER } from 'common/fieldTypes';
import { FunctionInfos, RoutineInfos } from 'common/interfaces/antares';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import { useFilters } from '@/composables/useFilters';
import { computed, PropType, Ref, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import BaseIcon from '@/components/BaseIcon.vue';
import { useFilters } from '@/composables/useFilters';
const { t } = useI18n();
const { wrapNumber } = useFilters();

View File

@@ -0,0 +1,224 @@
<template>
<Teleport to="#window-content">
<div class="modal active">
<a class="modal-overlay" @click.stop="closeModal" />
<div ref="trapRef" class="modal-container p-0">
<div class="modal-header pl-2">
<div class="modal-title h6">
<div class="d-flex">
<BaseIcon
icon-name="mdiBrushVariant"
class="mr-1"
:size="24"
/>
<span class="cut-text">{{ t('application.editConnectionAppearance') }}</span>
</div>
</div>
<a class="btn btn-clear c-hand" @click.stop="closeModal" />
</div>
<div class="modal-body pb-0">
<div class="content">
<form class="form-horizontal">
<div class="form-group mb-4">
<div class="col-3">
<label class="form-label">{{ t('application.label') }}</label>
</div>
<div class="col-9">
<input
ref="firstInput"
v-model="localConnection.name"
class="form-input"
type="text"
:placeholder="getConnectionName(localConnection.uid)"
>
</div>
</div>
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ t('application.icon') }}</label>
</div>
<div class="col-9 icons-wrapper">
<div
v-for="icon in icons"
:key="icon.name"
>
<BaseIcon
v-if="icon.code"
:icon-name="camelize(icon.code)"
:size="36"
class="icon-box"
:title="icon.name"
:class="[{'selected': localConnection.icon === icon.code}]"
@click="localConnection.icon = icon.code"
/>
<div
v-else
class="icon-box"
:title="icon.name"
:class="[`dbi dbi-${connection.client}`, {'selected': localConnection.icon === icon.code}]"
@click="localConnection.icon = icon.code"
/>
</div>
</div>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary mr-2" @click.stop="editFolderAppearance">
{{ t('application.update') }}
</button>
<button class="btn btn-link" @click.stop="closeModal">
{{ t('general.close') }}
</button>
</div>
</div>
</div>
</Teleport>
</template>
<script setup lang="ts">
import { onBeforeUnmount, PropType, Ref, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import BaseIcon from '@/components/BaseIcon.vue';
import { useFocusTrap } from '@/composables/useFocusTrap';
import { unproxify } from '@/libs/unproxify';
import { SidebarElement, useConnectionsStore } from '@/stores/connections';
const connectionsStore = useConnectionsStore();
const { t } = useI18n();
const props = defineProps({
connection: {
type: Object as PropType<SidebarElement>,
required: true
}
});
const emit = defineEmits(['close']);
const { updateConnectionOrder, getConnectionName } = connectionsStore;
const icons = [
{ name: 'default', code: null },
// Symbols
{ name: 'account-group', code: 'mdi-account-group-outline' },
{ name: 'cloud', code: 'mdi-cloud-outline' },
{ name: 'key-chain', code: 'mdi-key-chain-variant' },
{ name: 'lightning-bolt', code: 'mdi-lightning-bolt' },
{ name: 'map-marker', code: 'mdi-map-marker-radius-outline' },
{ name: 'api', code: 'mdi-api' },
{ name: 'chart-line', code: 'mdi-chart-line' },
{ name: 'chat', code: 'mdi-chat-outline' },
{ name: 'bug', code: 'mdi-bug-outline' },
{ name: 'shield', code: 'mdi-shield-outline' },
{ name: 'cart', code: 'mdi-cart-variant' },
{ name: 'bank', code: 'mdi-bank-outline' },
{ name: 'receipt', code: 'mdi-receipt-text-outline' },
{ name: 'raspberry-pi', code: 'mdi-raspberry-pi' },
{ name: 'book', code: 'mdi-book-outline' },
{ name: 'web', code: 'mdi-web' },
{ name: 'multimedia', code: 'mdi-multimedia' },
{ name: 'qr-code', code: 'mdi-qrcode' },
{ name: 'flask', code: 'mdi-flask-outline' },
{ name: 'memory', code: 'mdi-memory' },
{ name: 'cube', code: 'mdi-cube-outline' },
{ name: 'weather', code: 'mdi-weather-partly-snowy-rainy' },
{ name: 'controller', code: 'mdi-controller' },
{ name: 'home-group', code: 'mdi-home-group' },
// Vehicles
{ name: 'truck', code: 'mdi-truck-outline' },
{ name: 'car', code: 'mdi-car' },
{ name: 'motorbike', code: 'mdi-atv' },
{ name: 'train', code: 'mdi-train' },
{ name: 'airplane', code: 'mdi-airplane' },
{ name: 'ferry', code: 'mdi-ferry' },
// Brand
{ name: 'docker', code: 'mdi-docker' },
{ name: 'open-source', code: 'mdi-open-source-initiative' },
{ name: 'aws', code: 'mdi-aws' },
{ name: 'google-cloud', code: 'mdi-google-cloud' },
{ name: 'microsoft-azure', code: 'mdi-microsoft-azure' },
{ name: 'linux', code: 'mdi-linux' },
{ name: 'microsoft-windows', code: 'mdi-microsoft-windows' },
{ name: 'apple', code: 'mdi-apple' },
{ name: 'android', code: 'mdi-android' }
];
const { trapRef } = useFocusTrap();
const firstInput: Ref<HTMLInputElement> = ref(null);
const localConnection: Ref<SidebarElement> = ref(unproxify(props.connection));
const editFolderAppearance = () => {
updateConnectionOrder(localConnection.value);
closeModal();
};
const camelize = (text: string) => {
const textArr = text.split('-');
for (let i = 0; i < textArr.length; i++) {
if (i === 0) continue;
textArr[i] = textArr[i].charAt(0).toUpperCase() + textArr[i].slice(1);
}
return textArr.join('');
};
const closeModal = () => emit('close');
const onKey =(e: KeyboardEvent) => {
e.stopPropagation();
if (e.key === 'Escape')
closeModal();
};
onBeforeUnmount(() => {
window.removeEventListener('keydown', onKey);
});
</script>
<style scoped lang="scss">
.modal-container {
max-width: 360px;
}
.icons-wrapper{
display: grid;
grid-template-columns: repeat(auto-fill, 40px);
gap: 5px;
.icon-box {
height: 40px;
width: 40px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&.selected {
outline: 2px solid $primary-color;
border-radius: 8px;
}
}
}
.theme-light {
.icons-wrapper {
.dbi {
filter: invert(100%) opacity(.8);
&.selected {
outline-color: #1c96d6;
}
}
}
}
</style>

View File

@@ -1,28 +1,34 @@
<template>
<ConfirmModal
:confirm-text="t('word.discard')"
:cancel-text="t('word.stay')"
:confirm-text="t('general.discard')"
:cancel-text="t('general.stay')"
@confirm="emit('confirm')"
@hide="emit('close')"
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-content-save-alert mr-1" /> {{ t('message.unsavedChanges') }}
<BaseIcon
icon-name="mdiContentSaveAlert"
class="mr-1"
:size="24"
/> {{ t('application.unsavedChanges') }}
</div>
</template>
<template #body>
<div>
{{ t('message.discardUnsavedChanges') }}
{{ t('application.discardUnsavedChanges') }}
</div>
</template>
</ConfirmModal>
</template>
<script setup lang="ts">
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import { onBeforeUnmount } from 'vue';
import { useI18n } from 'vue-i18n';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import BaseIcon from '@/components/BaseIcon.vue';
const { t } = useI18n();
const emit = defineEmits(['confirm', 'close']);

Some files were not shown because too many files have changed in this diff Show More