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

Compare commits

...

105 Commits

Author SHA1 Message Date
dependabot[bot]
67e849bc66 chore(deps): bump webpack from 5.91.0 to 5.98.0
Bumps [webpack](https://github.com/webpack/webpack) from 5.91.0 to 5.98.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.91.0...v5.98.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 19:25:34 +00:00
eb706c3e51 fix: issue with some SSH connections, definitely 2025-02-14 20:30:47 +01:00
971df3a989 chore(release): 0.7.33 2025-02-14 18:03:57 +01:00
3129bf4baa fix: issue with some SSH connections, fixes #947 2025-02-14 17:58:49 +01:00
c6d67cef01 chore(release): 0.7.32 2025-02-14 09:12:05 +01:00
1d7053ce03 fix: black background with light theme, fixes #945 2025-02-14 09:08:45 +01:00
41e797f9e2 fix(PostgreSQL): error with materialized view tabs 2025-02-13 18:01:19 +01:00
704f70819b fix: improve error handling in SSH connection 2025-02-12 18:10:27 +01:00
49a3589536 fix: enhance SVG support in connection customization, fixes #939 2025-02-12 18:09:11 +01:00
49ada059bc chore(release): 0.7.31 2025-02-11 18:22:37 +01:00
8003d3eb1e chore(release): 0.7.31-beta.5 2025-02-09 10:19:09 +01:00
48cfa67889 perf: improve button styles of notes 2025-02-09 10:17:38 +01:00
9cda38e9d1 perf(MySQL): long loading in table settings when no checks present 2025-02-06 18:25:27 +01:00
72f8d4249f fix: improve BLOB primary fields management, fixes #938 2025-02-06 13:28:12 +01:00
0f93d70417 fix: unable to delete rows from context menu 2025-02-06 13:27:02 +01:00
580bef76ba fix: replace 'this.addNotification' with 'addNotification' in useResultTables.ts 2025-02-06 13:25:57 +01:00
7595e89223 fix(devtoolsInstaller): improve file path handling and increase chromium version 2025-02-06 12:50:45 +01:00
7af44d4a2c refactor: add ciaplu for pattern matching in language detection and MIME type resolution 2025-02-05 15:34:01 +01:00
0479e5307c fix(Linux): restored AppImage auto updates 2025-02-03 18:14:38 +01:00
d03c1b90ce chore(release): 0.7.31-beta.4 2025-01-31 18:06:58 +01:00
d34e56a517 fix(Linux): missing window management icons 2025-01-31 18:06:16 +01:00
0f35814ca0 chore(release): 0.7.31-beta.3 2025-01-31 17:54:25 +01:00
96ae09feca feat: implement a better query splitter for SQL queries, fixes #926 2025-01-31 17:28:58 +01:00
e3b30359bf refactor: disable auto opening dev tools in development mode 2025-01-31 13:33:42 +01:00
f3c3284fd1 ci: add GitHub Actions workflow for creating Windows APPX artifacts 2025-01-31 13:32:44 +01:00
27387f18a1 fix(MySQL): adjust utf8mb3 encoding to resolve compatibility issue, fixes #646 2025-01-31 13:32:06 +01:00
8e54f7b801 feat(Linux): update title bar for better Linux experience 2025-01-30 18:01:56 +01:00
70aae2f194 chore(release): 0.7.31-beta.2 2025-01-30 16:16:14 +01:00
592d7b3517 feat: add developer tools and refresh buttons to console in development mode 2025-01-23 18:10:37 +01:00
2b743a2c79 Merge pull request #925 from dyaskur/develop
fix: fail to fill cell to datetime column(Postgre) fixes #924
2025-01-23 09:17:40 +01:00
️Yaskur Dyas⚔⚔️⚔
e493db5112 fix: reorder condition when format the update data 2025-01-23 08:16:52 +07:00
️Yaskur Dyas⚔⚔️⚔
d3d7ab38c0 fix: fail to fill cell to datetime column(Postgre) fixes #924 2025-01-23 06:32:22 +07:00
7a66c11868 chore(release): 0.7.31-beta.1 2025-01-22 10:56:01 +01:00
8544bb5378 refactor: reorder import statements in sqlUtils.ts for consistency 2025-01-22 10:53:58 +01:00
6709a75298 Merge pull request #921 from curiouslad/develop
Zoom in/out and fullscreen shortcuts
2025-01-20 09:07:08 +01:00
f25f6659d5 refactor: enhancement of new shortcuts implementation 2025-01-17 13:45:46 +01:00
8d0ff4953e Merge pull request #922 from jimcat8/cn_trans
Update localization
2025-01-16 09:45:33 +01:00
tianci
fbe28f0ff0 Update localization 2025-01-16 12:22:07 +08:00
0d8bcf5cd6 Merge pull request #920 from dyaskur/develop
fix: Cannot update column value with composite primary key and JSON column #916
2025-01-15 09:12:26 +01:00
mladen
47ac729d2f feat: zoom in/out and fullscreen shortcuts 2025-01-14 05:24:33 +01:00
️Yaskur Dyas⚔⚔️⚔
450c4c47f3 refactor: improve update cell condition and move whereJson formatter to sqlUtils 2025-01-14 05:44:12 +07:00
️Yaskur Dyas⚔⚔️⚔
110dcd335a fix: cannot update on JSON column in MariaDB and PostgreSQL 2025-01-14 05:15:46 +07:00
️Yaskur Dyas⚔⚔️⚔
0029967619 fix: cannot update column value with composite primary key and JSON column, fixes #916 2025-01-14 04:44:29 +07:00
34848e8dc3 Merge branch 'develop' of https://github.com/antares-sql/antares into develop 2025-01-13 10:23:23 +01:00
c32add76e8 Merge pull request #919 from dyaskur/develop
fix: fail to duplicate JSON row
2025-01-13 10:23:17 +01:00
️Yaskur Dyas⚔⚔️⚔
507dc7d55b fix: fail to duplicate JSON row 2025-01-12 10:30:31 +07:00
4a2b5926f4 fix: saved connections lost opening a second window after first app run 2025-01-10 18:20:36 +01:00
ed90b12a7b Merge pull request #918 from antares-sql/all-contributors/add-JoseGonzalez84
docs: add JoseGonzalez84 as a contributor for translation
2025-01-10 08:46:59 +01:00
allcontributors[bot]
00ce76a12e docs: update .all-contributorsrc [skip ci] 2025-01-10 07:46:47 +00:00
allcontributors[bot]
77b3a8a354 docs: update README.md [skip ci] 2025-01-10 07:46:46 +00:00
d3ae45ec94 perf(translation): update spanish translation 2025-01-10 08:45:58 +01:00
ad4478a822 Merge pull request #917 from antares-sql/all-contributors/add-salvymc
docs: add salvymc as a contributor for code
2025-01-09 16:50:59 +01:00
allcontributors[bot]
ba5dd9ff15 docs: update .all-contributorsrc [skip ci] 2025-01-09 15:50:45 +00:00
allcontributors[bot]
5aab824fe9 docs: update README.md [skip ci] 2025-01-09 15:50:44 +00:00
87ab58c50f Merge pull request #912 from salvymc/patch-1
Update WorkspaceExploreBarSchema.vue - Changed search to not be case sensitive
2025-01-09 16:48:37 +01:00
e986f287c6 chore(release): 0.7.31-beta.0 2025-01-06 11:11:23 +01:00
Salvatore Forino
39a30e48dd Update WorkspaceExploreBarSchema.vue
Changed search to not be case sensitive
2025-01-03 13:09:15 +01:00
46165d2f4f Merge pull request #910 from antares-sql/all-contributors/add-r4f4dev
docs: add r4f4dev as a contributor for translation
2024-12-28 23:46:00 +01:00
allcontributors[bot]
d0e56e4eb6 docs: update .all-contributorsrc [skip ci] 2024-12-28 22:45:32 +00:00
allcontributors[bot]
c803c072d1 docs: update README.md [skip ci] 2024-12-28 22:45:31 +00:00
232211811b Merge pull request #909 from r4f4dev/feat/locale-uzbek
feat(language): add uzbek language support
2024-12-28 15:22:23 +01:00
r4f4dev
fb9c258cc1 feat(language): add uzbek language support 2024-12-28 19:15:41 +05:00
8de99dae7b fix: prevent delete confirmation modal from triggering on non-delete key presses, fixes #906 2024-12-24 11:03:27 +01:00
2bd69c6263 refactor: removed software-side sorting logic, fixes #904 2024-12-24 09:54:47 +01:00
4d1a81033d chore(release): 0.7.30 2024-12-04 18:14:31 +01:00
5887eea2ed Merge branch 'master' of https://github.com/antares-sql/antares 2024-12-04 18:14:11 +01:00
6c69583c90 Merge pull request #899 from antares-sql/all-contributors/add-carvalhods
docs: add carvalhods as a contributor for platform
2024-11-22 09:16:26 +01:00
allcontributors[bot]
03461522b7 docs: update .all-contributorsrc [skip ci] 2024-11-22 08:13:36 +00:00
allcontributors[bot]
11807e3bb6 docs: update README.md [skip ci] 2024-11-22 08:13:35 +00:00
a54b8d719c fix: issue saving queries as file 2024-11-21 13:28:33 +01:00
d1f68da495 chore(release): 0.7.30-beta.1 2024-11-15 14:27:20 +01:00
d666281daa Update README.md 2024-11-11 15:50:55 +01:00
481ae842dd Merge pull request #894 from leaked/master
Update README.md
2024-11-11 15:49:43 +01:00
Mohsen Nasiri
acf5d459e2 Update README.md 2024-11-10 02:47:52 +03:30
2ee9cfcf0b fix: missing support check for table check features 2024-11-08 18:12:02 +01:00
f0d312fb59 perf(PostgreSQL): improved support of connection strings, closes #893 2024-11-08 18:09:37 +01:00
c97ade949c chore(release): 0.7.30-beta.0 2024-10-25 18:46:27 +02:00
38af648440 refactor: ts fix 2024-10-25 18:44:49 +02:00
ccbcffc7f0 Merge pull request #890 from antares-sql/feat/mysql-check-support
Feat: MySQL check support
2024-10-25 18:34:06 +02:00
dfa7cf9905 perf: added more notifications in debug console 2024-10-25 18:32:07 +02:00
6365e07534 feat(MySQL): check constraints management support 2024-10-25 18:30:34 +02:00
24605d01e1 Merge pull request #887 from antares-sql/all-contributors/add-SawGoD
docs: add SawGoD as a contributor for translation
2024-10-22 15:53:15 +02:00
f083a8a185 Merge pull request #886 from SawGoD/master
feat: update ru-RU.ts file and update translation
2024-10-22 15:52:58 +02:00
allcontributors[bot]
f639bc7983 docs: update .all-contributorsrc [skip ci] 2024-10-22 13:26:01 +00:00
allcontributors[bot]
5e51997e5b docs: update README.md [skip ci] 2024-10-22 13:26:00 +00:00
SawGoD
1e3c9edb50 Update ru-RU.ts file and update translation 2024-10-22 11:41:36 +03:00
60e1e59505 fix: incorrect behavior sorting tables with numeric values 2024-10-18 18:24:46 +02:00
dba490f226 fix(MySQL): routines do not return results, fixes #885 2024-10-17 18:14:41 +02:00
b6c5dff15c fix: incorrect behavior in sorting tables with null/empty values, fixes #883 2024-10-17 18:12:34 +02:00
d2da8c2446 chore(release): 0.7.29 2024-10-14 09:40:47 +02:00
b54d2c9f5e chore(release): 0.7.29-beta.3 2024-10-08 18:38:02 +02:00
9a0ad80bb5 perf(MySQL): made some common errors related to corrupted tables non-blocking, closes #877 2024-10-08 18:34:29 +02:00
2f3f5de8d6 feat(translation): add hebrew translation, closes #878 2024-10-08 18:26:30 +02:00
b2c046fd38 Merge pull request #879 from antares-sql/all-contributors/add-LeviEyal
docs: add LeviEyal as a contributor for translation
2024-10-08 12:47:01 +02:00
allcontributors[bot]
bbc29a6335 docs: update .all-contributorsrc [skip ci] 2024-10-08 10:46:28 +00:00
allcontributors[bot]
b6c337638c docs: update README.md [skip ci] 2024-10-08 10:46:27 +00:00
2120a59d41 chore(release): 0.7.29-beta.2 2024-10-02 10:18:14 +02:00
2cda4a1fa1 fix(MySQL): missing exported values for DEFAULT_GENERATED table fields, fixes #854 2024-10-01 18:08:58 +02:00
76c8cd1beb Merge pull request #875 from mirrorb/master
fix(PostgreSQL): unable to change table comment to empty, error changing the comment for a specific table name
2024-09-30 18:12:02 +02:00
14aeebed9c feat(UI): new context menu and some minor improvements to query tabs, closes #867 2024-09-30 18:10:38 +02:00
mirrorb
1a1118452a Merge remote-tracking branch 'upstream/develop' 2024-09-30 11:22:46 +08:00
mirrorb
4b0f596405 Merge branch 'master' of https://github.com/antares-sql/antares 2024-09-30 11:05:02 +08:00
mirrorb
eb749f0f66 fix(PostgreSQL): error changing the comment for a specific table name 2024-09-30 11:02:26 +08:00
mirrorb
d78e59dd09 fix(PostgreSQL): unable to change table comment to empty 2024-09-30 10:57:19 +08:00
7969294a93 fix(MySQL): incorrect representation of the DATE if the year is prior to 1900, fixes #860 2024-09-29 13:50:22 +02:00
80 changed files with 3777 additions and 652 deletions

View File

@@ -311,6 +311,60 @@
"contributions": [
"code"
]
},
{
"login": "LeviEyal",
"name": "Eyal Levi",
"avatar_url": "https://avatars.githubusercontent.com/u/48846533?v=4",
"profile": "https://github.com/LeviEyal",
"contributions": [
"translation"
]
},
{
"login": "SawGoD",
"name": "Nikita Karelikov",
"avatar_url": "https://avatars.githubusercontent.com/u/67802757?v=4",
"profile": "http://telegram.dog/SawGoD",
"contributions": [
"translation"
]
},
{
"login": "carvalhods",
"name": "David Carvalho",
"avatar_url": "https://avatars.githubusercontent.com/u/6569255?v=4",
"profile": "https://github.com/carvalhods",
"contributions": [
"platform"
]
},
{
"login": "r4f4dev",
"name": "r4f4dev",
"avatar_url": "https://avatars.githubusercontent.com/u/65920592?v=4",
"profile": "https://github.com/r4f4dev",
"contributions": [
"translation"
]
},
{
"login": "salvymc",
"name": "Salvatore Forino",
"avatar_url": "https://avatars.githubusercontent.com/u/10051897?v=4",
"profile": "https://github.com/salvymc",
"contributions": [
"code"
]
},
{
"login": "JoseGonzalez84",
"name": "José González",
"avatar_url": "https://avatars.githubusercontent.com/u/16820141?v=4",
"profile": "https://gadev.com.es/",
"contributions": [
"translation"
]
}
],
"contributorsPerLine": 7,

View File

@@ -2,4 +2,5 @@ node_modules
assets
out
dist
build
build
misc

View File

@@ -0,0 +1,32 @@
name: Create artifact [WINDOWS APPX]
on:
workflow_dispatch: {}
jobs:
build:
runs-on: windows-2022
steps:
- name: Check out Git repository
uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm i
- name: "Build"
run: npm run build:appx
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: windows-build
retention-days: 3
path: |
build
!build/*-unpacked
!build/.icon-ico

View File

@@ -2,6 +2,173 @@
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.33](https://github.com/antares-sql/antares/compare/v0.7.32...v0.7.33) (2025-02-14)
### Bug Fixes
* issue with some SSH connections, fixes [#947](https://github.com/antares-sql/antares/issues/947) ([3129bf4](https://github.com/antares-sql/antares/commit/3129bf4baa5e72b1d79df986605fd5fad1dce291))
### [0.7.32](https://github.com/antares-sql/antares/compare/v0.7.31...v0.7.32) (2025-02-14)
### Bug Fixes
* black background with light theme, fixes [#945](https://github.com/antares-sql/antares/issues/945) ([1d7053c](https://github.com/antares-sql/antares/commit/1d7053ce032efec8377d9500f2e24618f6381ab4))
* enhance SVG support in connection customization, fixes [#939](https://github.com/antares-sql/antares/issues/939) ([49a3589](https://github.com/antares-sql/antares/commit/49a3589536d2e75a14125be7b874e29b60fb56c4))
* improve error handling in SSH connection ([704f708](https://github.com/antares-sql/antares/commit/704f70819b21a42194d8f68cf9b58ba337f1ada7))
* **PostgreSQL:** error with materialized view tabs ([41e797f](https://github.com/antares-sql/antares/commit/41e797f9e27db66370d3ae7750c057f708af76f9))
### [0.7.31](https://github.com/antares-sql/antares/compare/v0.7.31-beta.5...v0.7.31) (2025-02-11)
### [0.7.31-beta.5](https://github.com/antares-sql/antares/compare/v0.7.31-beta.4...v0.7.31-beta.5) (2025-02-09)
### Bug Fixes
* **devtoolsInstaller:** improve file path handling and increase chromium version ([7595e89](https://github.com/antares-sql/antares/commit/7595e892238d2a93c454e9c1f236915fb458eed1))
* improve BLOB primary fields management, fixes [#938](https://github.com/antares-sql/antares/issues/938) ([72f8d42](https://github.com/antares-sql/antares/commit/72f8d4249f7f587d3e92b46cf7709ddab42107d4))
* **Linux:** restored AppImage auto updates ([0479e53](https://github.com/antares-sql/antares/commit/0479e5307c9a9d5f791e1c61fa772d331f6f7f1f))
* replace 'this.addNotification' with 'addNotification' in useResultTables.ts ([580bef7](https://github.com/antares-sql/antares/commit/580bef76ba390fc85df0892265f31392b80301bd))
* unable to delete rows from context menu ([0f93d70](https://github.com/antares-sql/antares/commit/0f93d70417871f02f9f64f203f6654fa1bf2004b))
### Improvements
* improve button styles of notes ([48cfa67](https://github.com/antares-sql/antares/commit/48cfa67889bd83228c109b7966c4acea4e542fc6))
* **MySQL:** long loading in table settings when no checks present ([9cda38e](https://github.com/antares-sql/antares/commit/9cda38e9d10e3000473863560d8be8f426a5ed17))
### [0.7.31-beta.4](https://github.com/antares-sql/antares/compare/v0.7.31-beta.3...v0.7.31-beta.4) (2025-01-31)
### Bug Fixes
* **Linux:** missing window management icons ([d34e56a](https://github.com/antares-sql/antares/commit/d34e56a517784dea16a7a53bc2249072a3b96596))
### [0.7.31-beta.3](https://github.com/antares-sql/antares/compare/v0.7.31-beta.2...v0.7.31-beta.3) (2025-01-31)
### Features
* implement a better query splitter for SQL queries, fixes [#926](https://github.com/antares-sql/antares/issues/926) ([96ae09f](https://github.com/antares-sql/antares/commit/96ae09fecad0c1fc8926d5dcf64cc779abe5ed49))
* **Linux:** update title bar for better Linux experience ([8e54f7b](https://github.com/antares-sql/antares/commit/8e54f7b80135768a33934bc9336239dee38401a5))
### Bug Fixes
* **MySQL:** adjust utf8mb3 encoding to resolve compatibility issue, fixes [#646](https://github.com/antares-sql/antares/issues/646) ([27387f1](https://github.com/antares-sql/antares/commit/27387f18a107fc6c09afec5f85134496ce764355))
### [0.7.31-beta.2](https://github.com/antares-sql/antares/compare/v0.7.31-beta.1...v0.7.31-beta.2) (2025-01-30)
### Features
* add developer tools and refresh buttons to console in development mode ([592d7b3](https://github.com/antares-sql/antares/commit/592d7b35170f8437ebc15221c97985e889fccb40))
### Bug Fixes
* fail to fill cell to datetime column(Postgre) fixes [#924](https://github.com/antares-sql/antares/issues/924) ([d3d7ab3](https://github.com/antares-sql/antares/commit/d3d7ab38c029fc5ec23767c6c86c49a96e4e329c))
* reorder condition when format the update data ([e493db5](https://github.com/antares-sql/antares/commit/e493db5112478ff121e4e77f69c21747c5d2e032))
### [0.7.31-beta.1](https://github.com/antares-sql/antares/compare/v0.7.31-beta.0...v0.7.31-beta.1) (2025-01-22)
### Features
* zoom in/out and fullscreen shortcuts ([47ac729](https://github.com/antares-sql/antares/commit/47ac729d2f5cced2c503358f7d45a1795f232a20))
### Bug Fixes
* cannot update column value with composite primary key and JSON column, fixes [#916](https://github.com/antares-sql/antares/issues/916) ([0029967](https://github.com/antares-sql/antares/commit/002996761997444ff689bf2384dae64ccb9ef8f7))
* fail to duplicate JSON row ([507dc7d](https://github.com/antares-sql/antares/commit/507dc7d55b342240bf18fd58e6bc71709e8e33a0))
* saved connections lost opening a second window after first app run ([4a2b592](https://github.com/antares-sql/antares/commit/4a2b5926f4783d0b9b1e28485e9293a25ddd31f3))
### Improvements
* **translation:** update spanish translation ([d3ae45e](https://github.com/antares-sql/antares/commit/d3ae45ec94b3538e84ac3013b285034caea695cf))
### [0.7.31-beta.0](https://github.com/antares-sql/antares/compare/v0.7.30...v0.7.31-beta.0) (2025-01-06)
### Features
* **language:** add uzbek language support ([fb9c258](https://github.com/antares-sql/antares/commit/fb9c258cc10e4d85242ca533a66a95f4101d472c))
### Bug Fixes
* prevent delete confirmation modal from triggering on non-delete key presses, fixes [#906](https://github.com/antares-sql/antares/issues/906) ([8de99da](https://github.com/antares-sql/antares/commit/8de99dae7b6eb72bd6833c607d3c3a5db9508ebb))
### [0.7.30](https://github.com/antares-sql/antares/compare/v0.7.30-beta.1...v0.7.30) (2024-12-04)
### Bug Fixes
* issue saving queries as file ([a54b8d7](https://github.com/antares-sql/antares/commit/a54b8d719c6454500b885050c9ce6feaf7cfae1f))
### [0.7.30-beta.1](https://github.com/antares-sql/antares/compare/v0.7.30-beta.0...v0.7.30-beta.1) (2024-11-15)
### Bug Fixes
* missing support check for table check features ([2ee9cfc](https://github.com/antares-sql/antares/commit/2ee9cfcf0bbcf86e8a194d2eff78801300ce7cb3))
### Improvements
* **PostgreSQL:** improved support of connection strings, closes [#893](https://github.com/antares-sql/antares/issues/893) ([f0d312f](https://github.com/antares-sql/antares/commit/f0d312fb59fd98d6e4501bc407959b91eb0650f2))
### [0.7.30-beta.0](https://github.com/antares-sql/antares/compare/v0.7.29...v0.7.30-beta.0) (2024-10-25)
### Features
* **MySQL:** check constraints management support ([6365e07](https://github.com/antares-sql/antares/commit/6365e075349e00caa1454cce862e918f2069878f))
### Bug Fixes
* incorrect behavior in sorting tables with null/empty values, fixes [#883](https://github.com/antares-sql/antares/issues/883) ([b6c5dff](https://github.com/antares-sql/antares/commit/b6c5dff15c165261e9a11a389ed415e59c7b7628))
* incorrect behavior sorting tables with numeric values ([60e1e59](https://github.com/antares-sql/antares/commit/60e1e595057c3ba7f36e0f829dba11b470e1069b))
* **MySQL:** routines do not return results, fixes [#885](https://github.com/antares-sql/antares/issues/885) ([dba490f](https://github.com/antares-sql/antares/commit/dba490f22634f87d3af5a3a4c0866fc3095c9842))
### Improvements
* added more notifications in debug console ([dfa7cf9](https://github.com/antares-sql/antares/commit/dfa7cf9905a4d0a79eaed823a14477574b329dfa))
### [0.7.29](https://github.com/antares-sql/antares/compare/v0.7.29-beta.3...v0.7.29) (2024-10-14)
### [0.7.29-beta.3](https://github.com/antares-sql/antares/compare/v0.7.29-beta.2...v0.7.29-beta.3) (2024-10-08)
### Features
* **translation:** add hebrew translation, closes [#878](https://github.com/antares-sql/antares/issues/878) ([2f3f5de](https://github.com/antares-sql/antares/commit/2f3f5de8d6b02cfbf5217adfcb09a61e13d1e901))
### Improvements
* **MySQL:** made some common errors related to corrupted tables non-blocking, closes [#877](https://github.com/antares-sql/antares/issues/877) ([9a0ad80](https://github.com/antares-sql/antares/commit/9a0ad80bb55f84bd6c90cc1e9b63b33512d336a8))
### [0.7.29-beta.2](https://github.com/antares-sql/antares/compare/v0.7.29-beta.1...v0.7.29-beta.2) (2024-10-02)
### Features
* **UI:** new context menu and some minor improvements to query tabs, closes [#867](https://github.com/antares-sql/antares/issues/867) ([14aeebe](https://github.com/antares-sql/antares/commit/14aeebed9cd8e475548f5e0ade105f4b11954cb2))
### Bug Fixes
* **MySQL:** incorrect representation of the DATE if the year is prior to 1900, fixes [#860](https://github.com/antares-sql/antares/issues/860) ([7969294](https://github.com/antares-sql/antares/commit/7969294a93a51861c57d4396c7a0d89ecc7e8a84))
* **MySQL:** missing exported values for DEFAULT_GENERATED table fields, fixes [#854](https://github.com/antares-sql/antares/issues/854) ([2cda4a1](https://github.com/antares-sql/antares/commit/2cda4a1fa1c80f3567e160caf0b93bc19d76fbaa))
* **PostgreSQL:** error changing the comment for a specific table name ([eb749f0](https://github.com/antares-sql/antares/commit/eb749f0f66bf6547053e30b1503c8b2990ae5950))
* **PostgreSQL:** unable to change table comment to empty ([d78e59d](https://github.com/antares-sql/antares/commit/d78e59dd0910d3ea6ec5183a8748420b2db57050))
### [0.7.29-beta.1](https://github.com/antares-sql/antares/compare/v0.7.29-beta.0...v0.7.29-beta.1) (2024-09-28)

View File

@@ -1,13 +1,13 @@
<!-- markdownlint-disable -->
<p align="center">
<img width="800" src="https://raw.githubusercontent.com/Fabio286/antares/master/docs/gh-logo.png">
<img width="800" src="https://raw.githubusercontent.com/antares-sql/antares/master/docs/gh-logo.png">
</p>
<!-- markdownlint-restore -->
# 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) ![Test e2e](https://github.com/antares-sql/antares/actions/workflows/test-e2e-win.yml/badge.svg?branch=develop) ![Mastodon Follow](https://img.shields.io/mastodon/follow/%20110860460902482117?domain=https%3A%2F%2Ffosstodon.org&style=social) [![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/antares-sql/antares) ![GitHub](https://img.shields.io/github/license/antares-sql/antares) ![Test e2e](https://github.com/antares-sql/antares/actions/workflows/test-e2e-win.yml/badge.svg?branch=develop) ![Mastodon Follow](https://img.shields.io/mastodon/follow/%20110860460902482117?domain=https%3A%2F%2Ffosstodon.org&style=social) [![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.
@@ -16,7 +16,7 @@ Our target is to support as many databases as possible, and all major operating
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).
🔗 If you are curious to try Antares you can download and install the [latest release](https://github.com/antares-sql/antares/releases/latest).
👁 To stay tuned for new releases follow Antares SQL on [Mastodon](https://fosstodon.org/@AntaresSQL).
🌟 Don't forget to **leave a star** if you appreciate this project.
@@ -60,7 +60,7 @@ On Linux you can simply download and run the `.AppImage` distribution, install f
### Windows
On Windows you can choose between downloading the app from Microsoft Store or downloading the `.exe` from our [website](https://antares-sql.app/downloads) or [this github repo](https://github.com/Fabio286/antares/releases/latest). Distributions that are not from Microsoft Store are not signed with a certificate, so to install you need to click on "More info" and then "Run anyway" on SmartScreen prompt.
On Windows you can choose between downloading the app from Microsoft Store or downloading the `.exe` from our [website](https://antares-sql.app/downloads) or [this github repo](https://github.com/antares-sql/antares/releases/latest). Distributions that are not from Microsoft Store are not signed with a certificate, so to install you need to click on "More info" and then "Run anyway" on SmartScreen prompt.
### MacOS
@@ -99,8 +99,8 @@ On macOS you can run `.dmg` distribution following [this guide](https://support.
## How to contribute
- 🌍 [Translate Antares](https://github.com/Fabio286/antares/wiki/Translate-Antares)
- 📖 [Contributors Guide](https://github.com/Fabio286/antares/wiki/Contributors-Guide)
- 🌍 [Translate Antares](https://github.com/antares-sql/antares/wiki/Translate-Antares)
- 📖 [Contributors Guide](https://github.com/antares-sql/antares/wiki/Contributors-Guide)
- 🚧 [Project Board](https://github.com/orgs/antares-sql/projects/3/views/2)
## Contributors ✨
@@ -154,6 +154,14 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="https://fazevedo.dev"><img src="https://avatars.githubusercontent.com/u/1640325?v=4?s=100" width="100px;" alt="Filipe Azevedo"/><br /><sub><b>Filipe Azevedo</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=mangas" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/zwei-c"><img src="https://avatars.githubusercontent.com/u/55912811?v=4?s=100" width="100px;" alt="CHANG, CHIH WEI"/><br /><sub><b>CHANG, CHIH WEI</b></sub></a><br /><a href="#translation-zwei-c" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mirrorb"><img src="https://avatars.githubusercontent.com/u/34116207?v=4?s=100" width="100px;" alt="GaoChun"/><br /><sub><b>GaoChun</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=mirrorb" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LeviEyal"><img src="https://avatars.githubusercontent.com/u/48846533?v=4?s=100" width="100px;" alt="Eyal Levi"/><br /><sub><b>Eyal Levi</b></sub></a><br /><a href="#translation-LeviEyal" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://telegram.dog/SawGoD"><img src="https://avatars.githubusercontent.com/u/67802757?v=4?s=100" width="100px;" alt="Nikita Karelikov"/><br /><sub><b>Nikita Karelikov</b></sub></a><br /><a href="#translation-SawGoD" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/carvalhods"><img src="https://avatars.githubusercontent.com/u/6569255?v=4?s=100" width="100px;" alt="David Carvalho"/><br /><sub><b>David Carvalho</b></sub></a><br /><a href="#platform-carvalhods" title="Packaging/porting to new platform">📦</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/r4f4dev"><img src="https://avatars.githubusercontent.com/u/65920592?v=4?s=100" width="100px;" alt="r4f4dev"/><br /><sub><b>r4f4dev</b></sub></a><br /><a href="#translation-r4f4dev" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/salvymc"><img src="https://avatars.githubusercontent.com/u/10051897?v=4?s=100" width="100px;" alt="Salvatore Forino"/><br /><sub><b>Salvatore Forino</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=salvymc" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://gadev.com.es/"><img src="https://avatars.githubusercontent.com/u/16820141?v=4?s=100" width="100px;" alt="José González"/><br /><sub><b>José González</b></sub></a><br /><a href="#translation-JoseGonzalez84" title="Translation">🌍</a></td>
</tr>
</tbody>
</table>

692
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.7.29-beta.1",
"version": "0.7.33",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT",
"repository": "https://github.com/antares-sql/antares.git",
@@ -131,6 +131,7 @@
"babel-loader": "~8.2.3",
"better-sqlite3": "~10.0.0",
"chalk": "~4.1.2",
"ciaplu": "^2.2.0",
"cpu-features": "^0.0.10",
"cross-env": "~7.0.2",
"css-loader": "~6.5.0",
@@ -151,7 +152,6 @@
"node-firebird": "~1.1.8",
"node-loader": "~2.0.0",
"pg": "~8.11.5",
"pg-connection-string": "~2.5.0",
"pg-query-stream": "~4.2.3",
"pgsql-ast-parser": "~7.2.1",
"pinia": "~2.1.7",
@@ -174,7 +174,7 @@
"vue-i18n": "~9.13.1",
"vue-loader": "~16.8.3",
"vuedraggable": "~4.1.0",
"webpack": "^5.91.0",
"webpack": "^5.98.0",
"webpack-cli": "~4.9.1"
},
"devDependencies": {

View File

@@ -1,5 +1,5 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
// @ts-check
const fs = require('fs');
const path = require('path');
const https = require('https');
@@ -7,13 +7,18 @@ const unzip = require('unzip-crx-3');
const { antares } = require('../package.json');
const extensionID = antares.devtoolsId;
const chromiumVersion = '124';
const destFolder = path.resolve(__dirname, `../misc/${extensionID}`);
const filePath = path.resolve(__dirname, `${destFolder}${extensionID}.crx`);
const fileUrl = `https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D${extensionID}%26uc&prodversion=32`;
const filePath = path.resolve(__dirname, `${destFolder}/${extensionID}.crx`);
const fileUrl = `https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D${extensionID}%26uc&prodversion=${chromiumVersion}`;
if (!fs.existsSync(destFolder))
fs.mkdirSync(destFolder, { recursive: true });
const fileStream = fs.createWriteStream(filePath);
const downloadFile = url => {
return new Promise((resolve, reject) => {
return /** @type {Promise<void>} */(new Promise((resolve, reject) => {
const request = https.get(url);
request.on('response', response => {
@@ -33,7 +38,7 @@ const downloadFile = url => {
});
request.on('error', reject);
request.end();
});
}));
};
(async () => {

View File

@@ -55,6 +55,7 @@ export const defaults: Customizations = {
tableArray: false,
tableRealCount: false,
tableDuplicate: false,
tableCheck: false,
viewSettings: false,
triggerSettings: false,
triggerFunctionSettings: false,

View File

@@ -47,6 +47,7 @@ export const customizations: Customizations = {
tableTruncateDisableFKCheck: true,
tableDuplicate: true,
tableDdl: true,
tableCheck: true,
viewAdd: true,
triggerAdd: true,
routineAdd: true,

View File

@@ -34,6 +34,7 @@ export interface ClientParams {
| { databasePath: string; readonly: boolean };
poolSize?: number;
logger?: () => void;
querySplitter?: (sql: string, clieng?: string) => string[];
}
/**
@@ -57,6 +58,7 @@ export interface ConnectionParams {
cert?: string;
key?: string;
ca?: string;
connString?: string;
untrustedConnection: boolean;
ciphers?: string;
ssh: boolean;
@@ -159,6 +161,13 @@ export interface TableForeign {
oldName?: string;
}
export interface TableCheck {
// eslint-disable-next-line camelcase
_antares_id?: string;
name: string;
clause: string;
}
export interface CreateTableParams {
/** Connection UID */
uid?: string;
@@ -166,6 +175,7 @@ export interface CreateTableParams {
fields: TableField[];
foreigns: TableForeign[];
indexes: TableIndex[];
checks?: TableCheck[];
options: TableOptions;
}
@@ -193,6 +203,11 @@ export interface AlterTableParams {
changes: TableForeign[];
deletions: TableForeign[];
};
checkChanges?: {
additions: TableCheck[];
changes: TableCheck[];
deletions: TableCheck[];
};
options: TableOptions;
}

View File

@@ -43,6 +43,7 @@ export interface Customizations {
tableArray?: boolean;
tableRealCount?: boolean;
tableTruncateDisableFKCheck?: boolean;
tableCheck?: boolean;
tableDdl?: boolean;
viewAdd?: boolean;
viewSettings?: boolean;

View File

@@ -1,3 +1,5 @@
import { match } from 'ciaplu';
function isJSON (str: string) {
try {
if (!['{', '['].includes(str.trim()[0]))
@@ -176,17 +178,13 @@ function isMD (str: string) {
}
export function langDetector (str: string) {
if (!str || !str.trim().length)
return 'text';
if (isJSON(str))
return 'json';
if (isHTML(str))
return 'html';
if (isSVG(str))
return 'svg';
if (isXML(str))
return 'xml';
if (isMD(str))
return 'markdown';
return 'text';
return match(str)
.when(() => !str || !str.trim().length, () => 'text')
.when(isJSON, () => 'json')
.when(isHTML, () => 'html')
.when(isSVG, () => 'svg')
.when(isXML, () => 'xml')
.when(isMD, () => 'markdown')
.otherwise(() => 'text')
.return();
}

View File

@@ -1,45 +1,25 @@
import { match } from 'ciaplu';
export function mimeFromHex (hex: string) {
switch (hex.substring(0, 4)) { // 2 bytes
case '424D':
return { ext: 'bmp', mime: 'image/bmp' };
case '1F8B':
return { ext: 'tar.gz', mime: 'application/gzip' };
case '0B77':
return { ext: 'ac3', mime: 'audio/vnd.dolby.dd-raw' };
case '7801':
return { ext: 'dmg', mime: 'application/x-apple-diskimage' };
case '4D5A':
return { ext: 'exe', mime: 'application/x-msdownload' };
case '1FA0':
case '1F9D':
return { ext: 'Z', mime: 'application/x-compress' };
default:
switch (hex.substring(0, 6)) { // 3 bytes
case 'FFD8FF':
return { ext: 'jpg', mime: 'image/jpeg' };
case '4949BC':
return { ext: 'jxr', mime: 'image/vnd.ms-photo' };
case '425A68':
return { ext: 'bz2', mime: 'application/x-bzip2' };
default:
switch (hex) { // 4 bites
case '89504E47':
return { ext: 'png', mime: 'image/png' };
case '47494638':
return { ext: 'gif', mime: 'image/gif' };
case '25504446':
return { ext: 'pdf', mime: 'application/pdf' };
case '504B0304':
return { ext: 'zip', mime: 'application/zip' };
case '425047FB':
return { ext: 'bpg', mime: 'image/bpg' };
case '4D4D002A':
return { ext: 'tif', mime: 'image/tiff' };
case '00000100':
return { ext: 'ico', mime: 'image/x-icon' };
default:
return { ext: '', mime: 'unknown ' + hex };
}
}
}
return match(hex.substring(0, 4)) // 2 bytes
.with('424D', () => ({ ext: 'bmp', mime: 'image/bmp' }))
.with('1F8B', () => ({ ext: 'tar.gz', mime: 'application/gzip' }))
.with('0B77', () => ({ ext: 'ac3', mime: 'audio/vnd.dolby.dd-raw' }))
.with('7801', () => ({ ext: 'dmg', mime: 'application/x-apple-diskimage' }))
.with('4D5A', () => ({ ext: 'exe', mime: 'application/x-msdownload' }))
.when((val) => ['1FA0', '1F9D'].includes(val), () => ({ ext: 'Z', mime: 'application/x-compress' }))
.extracting(() => hex.substring(0, 6)) // 3 bytes
.with('FFD8FF', () => ({ ext: 'jpg', mime: 'image/jpeg' }))
.with('4949BC', () => ({ ext: 'jxr', mime: 'image/vnd.ms-photo' }))
.with('425A68', () => ({ ext: 'bz2', mime: 'application/x-bzip2' }))
.extracting(() => hex) // 4 bytes
.with('89504E47', () => ({ ext: 'png', mime: 'image/png' }))
.with('47494638', () => ({ ext: 'gif', mime: 'image/gif' }))
.with('25504446', () => ({ ext: 'pdf', mime: 'application/pdf' }))
.with('504B0304', () => ({ ext: 'zip', mime: 'application/zip' }))
.with('425047FB', () => ({ ext: 'bpg', mime: 'image/bpg' }))
.with('4D4D002A', () => ({ ext: 'tif', mime: 'image/tiff' }))
.with('00000100', () => ({ ext: 'ico', mime: 'image/x-icon' }))
.otherwise(() => ({ ext: '', mime: 'unknown ' + hex }))
.return();
}

View File

@@ -0,0 +1,86 @@
import { ClientCode } from 'common/interfaces/antares';
export const querySplitter =(sql: string, dbType: ClientCode): string[] => {
const queries: string[] = [];
let currentQuery = '';
let insideBlock = false;
let insideString = false;
let stringDelimiter: string | null = null;
let insideDollarTag = false;
let dollarTagDelimiter: string | null = null;
// Regex patterns for BEGIN-END blocks, dollar tags in PostgreSQL, and semicolons
const beginRegex = /\bBEGIN\b/i;
const endRegex = /\bEND\b;/i;
const dollarTagRegex = /\$(\w+)?\$/; // Matches $tag$ or $$
// Split on semicolons, keeping semicolons attached to the lines
const lines = sql.split(/(?<=;)/);
for (let line of lines) {
line = line.trim();
if (!line) continue;
for (let i = 0; i < line.length; i++) {
const char = line[i];
// Handle string boundaries
if ((char === '\'' || char === '"') && (!insideString || char === stringDelimiter)) {
if (!insideString) {
insideString = true;
stringDelimiter = char;
}
else {
insideString = false;
stringDelimiter = null;
}
}
currentQuery += char;
if (dbType === 'pg') {
// Handle dollar-quoted blocks in PostgreSQL
if (!insideString && line.slice(i).match(dollarTagRegex)) {
const match = line.slice(i).match(dollarTagRegex);
if (match) {
const tag = match[0];
if (!insideDollarTag) {
insideDollarTag = true;
dollarTagDelimiter = tag;
currentQuery += tag;
i += tag.length - 1;
}
else if (dollarTagDelimiter === tag) {
insideDollarTag = false;
dollarTagDelimiter = null;
currentQuery += tag;
i += tag.length - 1;
}
}
}
}
// Check BEGIN-END blocks
if (!insideString && !insideDollarTag) {
if (beginRegex.test(line))
insideBlock = true;
if (insideBlock && endRegex.test(line))
insideBlock = false;
}
}
// Append the query if we encounter a semicolon outside a BEGIN-END block, outside a string, and outside dollar tags
if (!insideBlock && !insideString && !insideDollarTag && /;\s*$/.test(line)) {
queries.push(currentQuery.trim());
currentQuery = '';
}
}
// Add any remaining query
if (currentQuery.trim())
queries.push(currentQuery.trim());
return queries;
};

View File

@@ -2,6 +2,7 @@
/* eslint-disable no-useless-escape */
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 antares from 'common/interfaces/antares';
import * as moment from 'moment';
import customizations from '../customizations';
@@ -209,3 +210,20 @@ export const jsonToSqlInsert = (args: {
return insertsString;
};
export const formatJsonForSqlWhere = (jsonValue: object, clientType: antares.ClientCode) => {
const formattedValue = JSON.stringify(jsonValue);
switch (clientType) {
case 'mysql':
return ` = CAST('${formattedValue}' AS JSON)`;
case 'maria':
return ` = '${formattedValue}'`;
case 'pg':
return `::text = '${formattedValue}'`;
case 'firebird':
case 'sqlite':
default:
return ` = '${formattedValue}'`;
}
};

View File

@@ -1,29 +1,34 @@
export const shortcutEvents: Record<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' },
// 'save-file': { l18n: 'application.saveFile', context: 'tab' },
'open-file': { l18n: 'application.openFile', context: 'tab' },
'save-file-as': { l18n: 'application.saveFileAs', 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.openNotes' }
export const shortcutEvents: Record<string, { i18n: string; i18nParam?: string | number; context?: 'tab' | 'main' }> = {
'run-or-reload': { i18n: 'application.runOrReload', context: 'tab' },
'open-new-tab': { i18n: 'application.openNewTab', context: 'tab' },
'close-tab': { i18n: 'application.closeTab', context: 'tab' },
'format-query': { i18n: 'database.formatQuery', context: 'tab' },
'kill-query': { i18n: 'database.killQuery', context: 'tab' },
'query-history': { i18n: 'database.queryHistory', context: 'tab' },
'clear-query': { i18n: 'database.clearQuery', context: 'tab' },
// 'save-file': { i18n: 'application.saveFile', context: 'tab' },
'open-file': { i18n: 'application.openFile', context: 'tab' },
'save-file-as': { i18n: 'application.saveFileAs', context: 'tab' },
'next-tab': { i18n: 'application.nextTab' },
'prev-tab': { i18n: 'application.previousTab' },
'open-all-connections': { i18n: 'application.openAllConnections' },
'open-filter': { i18n: 'application.openFilter' },
'next-page': { i18n: 'application.nextResultsPage' },
'prev-page': { i18n: 'application.previousResultsPage' },
'toggle-console': { i18n: 'application.toggleConsole' },
'save-content': { i18n: 'application.saveContent' },
'create-connection': { i18n: 'connection.createNewConnection' },
'open-settings': { i18n: 'application.openSettings' },
'open-scratchpad': { i18n: 'application.openNotes' },
setFullScreen: { i18n: 'application.fullScreen', context: 'main' },
setZoomIn: { i18n: 'application.zoomIn', context: 'main' },
setZoomOut: { i18n: 'application.zoomOut', context: 'main' },
setZoomReset: { i18n: 'application.zoomReset', context: 'main' }
};
interface ShortcutRecord {
event: string;
isFunction?: boolean;
keys: Electron.Accelerator[] | string[];
/** Needed for default shortcuts */
os: NodeJS.Platform[];
@@ -38,6 +43,30 @@ const shortcuts: ShortcutRecord[] = [
keys: ['F5'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'setFullScreen',
isFunction: true,
keys: ['F11'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'setZoomIn',
isFunction: true,
keys: ['CommandOrControl+='],
os: ['darwin', 'linux', 'win32']
},
{
event: 'setZoomOut',
isFunction: true,
keys: ['CommandOrControl+-'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'setZoomReset',
isFunction: true,
keys: ['CommandOrControl+0'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'save-content',
keys: ['CommandOrControl+S'],
@@ -142,8 +171,8 @@ const shortcuts: ShortcutRecord[] = [
for (let i = 1; i <= 9; i++) {
shortcutEvents[`select-tab-${i}`] = {
l18n: 'application.selectTabNumber',
l18nParam: i
i18n: 'application.selectTabNumber',
i18nParam: i
};
shortcuts.push({

View File

@@ -26,6 +26,7 @@ export default (connections: Record<string, antares.Client>) => {
user: conn.user,
password: conn.password,
readonly: conn.readonly,
connectionString: conn.connString,
database: '',
schema: '',
databasePath: '',
@@ -63,9 +64,9 @@ export default (connections: Record<string, antares.Client>) => {
username: conn.sshUser,
password: conn.sshPass,
port: conn.sshPort ? conn.sshPort : 22,
privateKey: conn.sshKey ? fs.readFileSync(conn.sshKey).toString() : null,
privateKey: conn.sshKey ? fs.readFileSync(conn.sshKey).toString() : undefined,
passphrase: conn.sshPassphrase,
keepaliveInterval: conn.sshKeepAliveInterval ? conn.sshKeepAliveInterval*1000 : null
keepaliveInterval: conn.sshKeepAliveInterval ? conn.sshKeepAliveInterval*1000 : undefined
};
}
@@ -89,11 +90,12 @@ export default (connections: Record<string, antares.Client>) => {
return { status: 'success' };
}
catch (err) {
catch (error) {
clearInterval(abortChecker);
if (!isLocalAborted)
return { status: 'error', response: err.toString() };
if (error instanceof AggregateError)
throw new Error(error.errors.reduce((acc, curr) => acc +' | '+ curr.message, ''));
else if (!isLocalAborted)
return { status: 'error', response: error.toString() };
else
return { status: 'abort', response: 'Connection aborted' };
}
@@ -122,6 +124,7 @@ export default (connections: Record<string, antares.Client>) => {
password: conn.password,
application_name: 'Antares SQL',
readonly: conn.readonly,
connectionString: conn.connString,
database: '',
schema: '',
databasePath: '',

View File

@@ -3,7 +3,7 @@ import { ARRAY, BIT, BLOB, BOOLEAN, DATE, DATETIME, FLOAT, LONG_TEXT, NUMBER, TE
import * as antares from 'common/interfaces/antares';
import { InsertRowsParams } from 'common/interfaces/tableApis';
import { fakerCustom } from 'common/libs/fakerCustom';
import { sqlEscaper } from 'common/libs/sqlUtils';
import { formatJsonForSqlWhere, sqlEscaper } from 'common/libs/sqlUtils';
import { ipcMain } from 'electron';
import * as fs from 'fs';
import * as moment from 'moment';
@@ -87,6 +87,19 @@ export default (connections: Record<string, antares.Client>) => {
}
});
ipcMain.handle('get-table-checks', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
try {
const result = await connections[params.uid].getTableChecks(params);
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-table-ddl', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };
@@ -220,9 +233,10 @@ export default (connections: Record<string, antares.Client>) => {
for (const key in orgRow) {
if (typeof orgRow[key] === 'string')
orgRow[key] = `'${orgRow[key]}'`;
if (orgRow[key] === null)
orgRow[key] = ` = '${orgRow[key]}'`;
else if (typeof orgRow[key] === 'object' && orgRow[key] !== null)
orgRow[key] = formatJsonForSqlWhere(orgRow[key], connections[params.uid]._client);
else if (orgRow[key] === null)
orgRow[key] = `IS ${orgRow[key]}`;
else
orgRow[key] = `= ${orgRow[key]}`;

View File

@@ -81,7 +81,15 @@ export class ShortcutRegister {
accelerator: key,
visible: isMenuVisible,
click: () => {
this._mainWindow.webContents.send(shortcut.event);
if (shortcut.isFunction) {
if (shortcut.event in this) {
type exporterMethods = 'setFullScreen' | 'setZoomIn' | 'setZoomOut' | 'setZoomReset';
this[shortcut.event as exporterMethods]();
}
}
else
this._mainWindow.webContents.send(shortcut.event);
if (isDevelopment) console.log('LOCAL EVENT:', shortcut);
}
});
@@ -121,6 +129,24 @@ export class ShortcutRegister {
}
}
setFullScreen () {
this._mainWindow.setFullScreen(!this._mainWindow.isFullScreen());
}
setZoomIn () {
const currentZoom = this._mainWindow.webContents.getZoomLevel();
this._mainWindow.webContents.setZoomLevel(currentZoom + 1);
}
setZoomOut () {
const currentZoom = this._mainWindow.webContents.getZoomLevel();
this._mainWindow.webContents.setZoomLevel(currentZoom - 1);
}
setZoomReset () {
this._mainWindow.webContents.setZoomLevel(0);
}
reload () {
this.unregister();
this.init();

View File

@@ -2,16 +2,9 @@ import * as antares from 'common/interfaces/antares';
import mysql from 'mysql2/promise';
import * as pg from 'pg';
import SSH2Promise = require('@fabio286/ssh2-promise');
import { querySplitter } from 'common/libs/querySplitter';
const queryLogger = ({ sql, cUid }: {sql: string; cUid: string}) => {
// Remove comments, newlines and multiple spaces
const escapedSql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '').replace(/\s\s+/g, ' ');
if (process.type !== undefined) {
const mainWindow = require('electron').webContents.fromId(1);
mainWindow.send('query-log', { cUid, sql: escapedSql, date: new Date() });
}
if (process.env.NODE_ENV === 'development' && process.type === 'browser') console.log(escapedSql);
};
import { ipcLogger, LoggerLevel } from '../misc/ipcLogger';
/**
* As Simple As Possible Query Builder Core
@@ -22,7 +15,8 @@ export abstract class BaseClient {
protected _params: mysql.ConnectionOptions | pg.ClientConfig | { databasePath: string; readonly: boolean};
protected _poolSize: number;
protected _ssh?: SSH2Promise;
protected _logger: (args: {sql: string; cUid: string}) => void;
protected _logger: (args: {content: string; cUid: string; level: LoggerLevel}) => void;
protected _querySplitter: (sql: string, client: antares.ClientCode) => string[];
protected _queryDefaults: antares.QueryBuilderObject;
protected _query: antares.QueryBuilderObject;
@@ -31,7 +25,8 @@ export abstract class BaseClient {
this._cUid = args.uid;
this._params = args.params;
this._poolSize = args.poolSize || undefined;
this._logger = args.logger || queryLogger;
this._logger = args.logger || ipcLogger;
this._querySplitter = args.querySplitter || querySplitter;
this._queryDefaults = {
schema: '',
@@ -178,6 +173,10 @@ export abstract class BaseClient {
throw new Error('Method "dropSchema" not implemented');
}
getTableChecks (...args: any) {
throw new Error('Method "getTableDll" not implemented');
}
getTableDll (...args: any) {
throw new Error('Method "getTableDll" not implemented');
}

View File

@@ -245,10 +245,10 @@ export class FirebirdSQLClient extends BaseClient {
name: db.name,
size: schemaSize,
tables: remappedTables,
functions: [],
functions: [] as null[],
procedures: remappedProcedures,
triggers: remappedTriggers,
schedulers: []
schedulers: [] as null[]
};
});
}
@@ -337,7 +337,7 @@ export class FirebirdSQLClient extends BaseClient {
return {
name: field.FIELD_NAME.trim(),
key: null,
key: null as null,
type: fieldType,
schema: schema,
table: table,
@@ -346,14 +346,14 @@ export class FirebirdSQLClient extends BaseClient {
datePrecision: field.FIELD_NAME.trim() === 'TIMESTAMP' ? 4 : null,
charLength: ![...NUMBER, ...FLOAT].includes(fieldType) ? field.FIELD_LENGTH : null,
nullable: !field.NOT_NULL,
unsigned: null,
zerofill: null,
unsigned: null as null,
zerofill: null as null,
order: field.FIELD_POSITION+1,
default: defaultValue,
charset: field.CHARSET,
collation: null,
collation: null as null,
autoIncrement: false,
onUpdate: null,
onUpdate: null as null,
comment: field.DESCRIPTION?.trim()
};
});
@@ -457,7 +457,7 @@ export class FirebirdSQLClient extends BaseClient {
table: table,
field: field.FKCOLUMN_NAME.trim(),
position: field.KEY_SEQ,
constraintPosition: null,
constraintPosition: null as null,
constraintName: field.FK_NAME.trim(),
refSchema: schema,
refTable: field.PKTABLE_NAME.trim(),
@@ -1024,7 +1024,7 @@ export class FirebirdSQLClient extends BaseClient {
alias: string;
}
this._logger({ cUid: this._cUid, sql });
this._logger({ cUid: this._cUid, content: sql, level: 'query' });
args = {
nest: false,
@@ -1041,9 +1041,7 @@ export class FirebirdSQLClient extends BaseClient {
const resultsArr = [];
let paramsArr = [];
const queries = args.split
? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm)
.filter(Boolean)
.map(q => q.trim())
? this._querySplitter(sql, 'firebird')
: [sql];
let connection: firebird.Database | firebird.Transaction;

View File

@@ -4,7 +4,9 @@ import dataTypes from 'common/data-types/mysql';
import * as antares from 'common/interfaces/antares';
import * as mysql from 'mysql2/promise';
import * as EncodingToCharset from '../../../../node_modules/mysql2/lib/constants/encoding_charset.js';
import { BaseClient } from './BaseClient';
EncodingToCharset.utf8mb3 = 192; // To fix https://github.com/sidorares/node-mysql2/issues/1398 until not included in mysql2
export class MySQLClient extends BaseClient {
private _schema?: string;
@@ -161,6 +163,8 @@ export class MySQLClient extends BaseClient {
this._ssh = new SSH2Promise({
...this._params.ssh,
reconnect: true,
reconnectTries: 3,
debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null
});
@@ -169,13 +173,13 @@ export class MySQLClient extends BaseClient {
remotePort: this._params.port
});
dbConfig.host = (this._ssh.config as SSHConfig[] & { host: string }).host;
dbConfig.host = undefined;
dbConfig.port = tunnel.localPort;
}
catch (err) {
if (this._ssh) {
this._ssh.close();
this._ssh.closeTunnel();
this._ssh.close();
}
throw err;
}
@@ -223,8 +227,8 @@ export class MySQLClient extends BaseClient {
clearInterval(this._keepaliveTimer);
this._keepaliveTimer = undefined;
if (this._ssh) {
this._ssh.close();
this._ssh.closeTunnel();
this._ssh.close();
}
}
@@ -232,12 +236,13 @@ export class MySQLClient extends BaseClient {
const dbConfig = await this.getDbConfig();
const connection = await mysql.createConnection({
...dbConfig,
typeCast: (field, next) => {
if (field.type === 'DATETIME')
return field.string();
else
return next();
}
dateStrings: true
// typeCast: (field, next) => {
// if (field.type === 'DATETIME')
// return field.string();
// else
// return next();
// }
});
return connection;
@@ -249,12 +254,13 @@ export class MySQLClient extends BaseClient {
...dbConfig,
connectionLimit: this._poolSize,
enableKeepAlive: true,
typeCast: (field, next) => {
if (field.type === 'DATETIME')
return field.string();
else
return next();
}
dateStrings: true
// typeCast: (field, next) => {
// if (field.type === 'DATETIME')
// return field.string();
// else
// return next();
// }
});
this._keepaliveTimer = setInterval(async () => {
@@ -296,6 +302,8 @@ export class MySQLClient extends BaseClient {
await this.connect();
return this.getConnection(args, true);
}
else if (error instanceof AggregateError)
throw new Error(error.errors.reduce((acc, curr) => acc +' | '+ curr.message, ''));
else
throw new Error(error.message);
}
@@ -352,10 +360,21 @@ export class MySQLClient extends BaseClient {
if (this._params.schema)
filteredDatabases = filteredDatabases.filter(db => db.Database === this._params.schema);
const { rows: functions } = await this.raw('SHOW FUNCTION STATUS');
const { rows: procedures } = await this.raw('SHOW PROCEDURE STATUS');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
/* eslint-disable @typescript-eslint/no-explicit-any */
let functions: any[] = [];
let procedures: any[] = [];
let schedulers: any[] = [];
/* eslint-enable @typescript-eslint/no-explicit-any */
try {
const { rows: functionRows } = await this.raw('SHOW FUNCTION STATUS');
const { rows: procedureRows } = await this.raw('SHOW PROCEDURE STATUS');
functions = functionRows;
procedures = procedureRows;
}
catch (err) {
this._logger({ content: err.sqlMessage, cUid: this._cUid, level: 'error' });
}
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`');
@@ -661,7 +680,7 @@ export class MySQLClient extends BaseClient {
charset: field.CHARACTER_SET_NAME,
collation: field.COLLATION_NAME,
autoIncrement: field.EXTRA.includes('auto_increment'),
generated: field.EXTRA.toLowerCase().includes('generated'),
generated: ['VIRTUAL GENERATED', 'VIRTUAL STORED'].includes(field.EXTRA),
onUpdate: field.EXTRA.toLowerCase().includes('on update')
? field.EXTRA.substr(field.EXTRA.indexOf('on update') + 9, field.EXTRA.length).trim()
: '',
@@ -676,6 +695,34 @@ export class MySQLClient extends BaseClient {
return rows.length ? rows[0].count : 0;
}
async getTableChecks ({ schema, table }: { schema: string; table: string }): Promise<antares.TableCheck[]> {
const { rows } = await this.raw(`
SELECT
CONSTRAINT_NAME as name,
CHECK_CLAUSE as clausole
FROM information_schema.CHECK_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = "${schema}"
AND CONSTRAINT_NAME IN (
SELECT
CONSTRAINT_NAME
FROM
information_schema.TABLE_CONSTRAINTS
WHERE
TABLE_SCHEMA = "${schema}"
AND TABLE_NAME = "${table}"
AND CONSTRAINT_TYPE = 'CHECK'
)
`);
if (rows.length) {
return rows.map(row => ({
name: row.name,
clause: row.clausole
}));
}
return [];
}
async getTableOptions ({ schema, table }: { schema: string; table: string }) {
/* eslint-disable camelcase */
interface TableOptionsResult {
@@ -852,11 +899,13 @@ export class MySQLClient extends BaseClient {
fields,
foreigns,
indexes,
checks,
options
} = params;
const newColumns: string[] = [];
const newIndexes: string[] = [];
const newForeigns: string[] = [];
const newChecks: string[] = [];
let sql = `CREATE TABLE \`${schema}\`.\`${options.name}\``;
@@ -897,7 +946,13 @@ export class MySQLClient extends BaseClient {
newForeigns.push(`CONSTRAINT \`${foreign.constraintName}\` FOREIGN KEY (\`${foreign.field}\`) REFERENCES \`${foreign.refTable}\` (\`${foreign.refField}\`) ON UPDATE ${foreign.onUpdate} ON DELETE ${foreign.onDelete}`);
});
sql = `${sql} (${[...newColumns, ...newIndexes, ...newForeigns].join(', ')}) COMMENT='${options.comment}', COLLATE='${options.collation}', ENGINE=${options.engine}`;
// ADD TABLE CHECKS
checks.forEach(check => {
if (!check.clause.trim().length) return;
newChecks.push(`${check.name ? `CONSTRAINT \`${check.name}\` ` : ''}CHECK (${check.clause})`);
});
sql = `${sql} (${[...newColumns, ...newIndexes, ...newForeigns, ...newChecks].join(', ')}) COMMENT='${options.comment}', COLLATE='${options.collation}', ENGINE=${options.engine}`;
return await this.raw(sql);
}
@@ -911,6 +966,7 @@ export class MySQLClient extends BaseClient {
changes,
indexChanges,
foreignChanges,
checkChanges,
options
} = params;
@@ -918,6 +974,7 @@ export class MySQLClient extends BaseClient {
const alterColumnsAdd: string[] = [];
const alterColumnsChange: string[] = [];
const alterColumnsDrop: string[] = [];
const alterQueryes: string[] = [];
// OPTIONS
if ('comment' in options) alterColumnsChange.push(`COMMENT='${options.comment}'`);
@@ -963,6 +1020,12 @@ export class MySQLClient extends BaseClient {
alterColumnsAdd.push(`ADD CONSTRAINT \`${addition.constraintName}\` FOREIGN KEY (\`${addition.field}\`) REFERENCES \`${addition.refTable}\` (\`${addition.refField}\`) ON UPDATE ${addition.onUpdate} ON DELETE ${addition.onDelete}`);
});
// ADD TABLE CHECKS
checkChanges.additions.forEach(addition => {
if (!addition.clause.trim().length) return;
alterColumnsAdd.push(`ADD ${addition.name ? `CONSTRAINT \`${addition.name}\` ` : ''}CHECK (${addition.clause})`);
});
// CHANGE FIELDS
changes.forEach(change => {
const typeInfo = this.getTypeInfo(change.type);
@@ -974,9 +1037,9 @@ export class MySQLClient extends BaseClient {
${change.zerofill ? 'ZEROFILL' : ''}
${change.nullable ? 'NULL' : 'NOT NULL'}
${change.autoIncrement ? 'AUTO_INCREMENT' : ''}
${change.collation ? `COLLATE ${change.collation}` : ''}
${change.default !== null ? `DEFAULT ${change.default || '\'\''}` : ''}
${change.comment ? `COMMENT '${change.comment}'` : ''}
${change.collation ? `COLLATE ${change.collation}` : ''}
${change.onUpdate ? `ON UPDATE ${change.onUpdate}` : ''}
${change.after ? `AFTER \`${change.after}\`` : 'FIRST'}`);
});
@@ -1007,6 +1070,13 @@ export class MySQLClient extends BaseClient {
alterColumnsChange.push(`ADD CONSTRAINT \`${change.constraintName}\` FOREIGN KEY (\`${change.field}\`) REFERENCES \`${change.refTable}\` (\`${change.refField}\`) ON UPDATE ${change.onUpdate} ON DELETE ${change.onDelete}`);
});
// CHANGE CHECK TABLE
checkChanges.changes.forEach(change => {
if (!change.clause.trim().length) return;
alterQueryes.push(`${sql} DROP CONSTRAINT \`${change.name}\``);
alterQueryes.push(`${sql} ADD ${change.name ? `CONSTRAINT \`${change.name}\` ` : ''}CHECK (${change.clause})`);
});
// DROP FIELDS
deletions.forEach(deletion => {
alterColumnsDrop.push(`DROP COLUMN \`${deletion.name}\``);
@@ -1025,7 +1095,11 @@ export class MySQLClient extends BaseClient {
alterColumnsDrop.push(`DROP FOREIGN KEY \`${deletion.constraintName}\``);
});
const alterQueryes = [];
// DROP CHECK TABLE
checkChanges.deletions.forEach(deletion => {
alterQueryes.push(`${sql} DROP CONSTRAINT \`${deletion.name}\``);
});
if (alterColumnsAdd.length) alterQueryes.push(sql+alterColumnsAdd.join(', '));
if (alterColumnsChange.length) alterQueryes.push(sql+alterColumnsChange.join(', '));
if (alterColumnsDrop.length) alterQueryes.push(sql+alterColumnsDrop.join(', '));
@@ -1665,7 +1739,7 @@ export class MySQLClient extends BaseClient {
}
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
this._logger({ cUid: this._cUid, sql });
this._logger({ cUid: this._cUid, content: sql, level: 'query' });
args = {
nest: false,
@@ -1683,9 +1757,7 @@ export class MySQLClient extends BaseClient {
const resultsArr: antares.QueryResult[] = [];
let paramsArr = [];
const queries = args.split
? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm)
.filter(Boolean)
.map(q => q.trim())
? this._querySplitter(sql, 'mysql')
: [sql];
const connection = await this.getConnection(args);
@@ -1701,9 +1773,10 @@ export class MySQLClient extends BaseClient {
connection.query({ sql: query, nestTables }).then(async ([response, fields]) => {
timeStop = new Date();
const queryResult = response;
const fieldsArr = fields ? Array.isArray(fields[0]) ? fields[0] : fields : false;// Some times fields are nested in an array
let remappedFields = fields
? fields.map(field => {
let remappedFields = fieldsArr
? fieldsArr.map(field => {
if (!field || Array.isArray(field))
return undefined;
@@ -1772,7 +1845,7 @@ export class MySQLClient extends BaseClient {
resolve({
duration: timeStop.getTime() - timeStart.getTime(),
rows: Array.isArray(queryResult) ? queryResult.some(el => Array.isArray(el)) ? [] : queryResult : false,
rows: Array.isArray(queryResult) ? queryResult.some(el => Array.isArray(el)) ? queryResult[0] : queryResult : false,
report: !Array.isArray(queryResult) ? queryResult : false,
fields: remappedFields,
keys: keysArr

View File

@@ -155,6 +155,7 @@ export class PostgreSQLClient extends BaseClient {
host: this._params.host,
port: this._params.port,
user: this._params.user,
connectionString: this._params.connectionString,
database: 'postgres' as string,
password: this._params.password,
ssl: null as ConnectionOptions
@@ -168,6 +169,8 @@ export class PostgreSQLClient extends BaseClient {
try {
this._ssh = new SSH2Promise({
...this._params.ssh,
reconnect: true,
reconnectTries: 3,
debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null
});
@@ -176,7 +179,7 @@ export class PostgreSQLClient extends BaseClient {
remotePort: this._params.port
});
dbConfig.host = (this._ssh.config as SSHConfig[] & { host: string }).host;
dbConfig.host = undefined;
dbConfig.port = tunnel.localPort;
}
catch (err) {
@@ -345,7 +348,7 @@ export class PostgreSQLClient extends BaseClient {
matviewowner AS owner,
ispopulated AS is_populated,
definition,
'materializedview' AS table_type
'materializedView' AS table_type
FROM pg_matviews
WHERE schemaname = '${db.database}'
ORDER BY schema_name,
@@ -405,8 +408,8 @@ export class PostgreSQLClient extends BaseClient {
name: table.table_name,
type: table.table_type === 'VIEW'
? 'view'
: table.table_type === 'materializedview'
? 'materializedview'
: table.table_type === 'materializedView'
? 'materializedView'
: 'table',
rows: table.reltuples,
size: tableSize,
@@ -463,7 +466,7 @@ export class PostgreSQLClient extends BaseClient {
procedures: remappedProcedures,
triggers: remappedTriggers,
triggerFunctions: remappedTriggerFunctions,
schedulers: []
schedulers: [] as null[]
};
}
else {
@@ -529,7 +532,7 @@ export class PostgreSQLClient extends BaseClient {
return {
name: field.column_name,
key: null,
key: null as null,
type: type.toUpperCase(),
isArray,
schema: field.table_schema,
@@ -539,14 +542,14 @@ export class PostgreSQLClient extends BaseClient {
datePrecision: field.datetime_precision,
charLength: field.character_maximum_length,
nullable: field.is_nullable.includes('YES'),
unsigned: null,
zerofill: null,
unsigned: null as null,
zerofill: null as null,
order: field.ordinal_position,
default: field.column_default,
charset: field.character_set_name,
collation: field.collation_name,
autoIncrement: false,
onUpdate: null,
onUpdate: null as null,
comment: field.column_comment
};
});
@@ -925,7 +928,7 @@ export class PostgreSQLClient extends BaseClient {
sql = `${sql} (${[...newColumns, ...newIndexes, ...newForeigns].join(', ')}); `;
if (manageIndexes.length) sql = `${sql} ${manageIndexes.join(';')}; `;
// TABLE COMMENT
if (options.comment) sql = `${sql} COMMENT ON TABLE "${schema}"."${options.name}" IS '${options.comment}'; `;
if (options.comment != null) sql = `${sql} COMMENT ON TABLE "${schema}"."${options.name}" IS '${options.comment}'; `;
// FIELDS COMMENT
if (modifyComment.length) sql = `${sql} ${modifyComment.join(';')}; `;
@@ -1070,7 +1073,7 @@ export class PostgreSQLClient extends BaseClient {
if (createSequences.length) sql = `${createSequences.join(';')}; ${sql}`;
if (manageIndexes.length) sql = `${manageIndexes.join(';')}; ${sql}`;
// TABLE COMMENT
if (options.comment) sql = `${sql} COMMENT ON TABLE ${schema}.${table} IS '${options.comment}'; `;
if (options.comment != null) sql = `${sql} COMMENT ON TABLE "${schema}"."${table}" IS '${options.comment}'; `;
// FIELDS COMMENT
if (modifyComment.length) sql = `${sql} ${modifyComment.join(';')}; `;
if (options.name) sql += `ALTER TABLE "${schema}"."${table}" RENAME TO "${options.name}"; `;
@@ -1249,9 +1252,9 @@ export class PostgreSQLClient extends BaseClient {
return results.rows.map(async row => {
if (!row.pg_get_functiondef) {
return {
definer: null,
definer: null as null,
sql: '',
parameters: [],
parameters: [] as null[],
name: routine,
comment: '',
security: 'DEFINER',
@@ -1300,8 +1303,8 @@ export class PostgreSQLClient extends BaseClient {
name: routine,
comment: '',
security: row.pg_get_functiondef.includes('SECURITY DEFINER') ? 'DEFINER' : 'INVOKER',
deterministic: null,
dataAccess: null,
deterministic: null as null,
dataAccess: null as null,
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0]
};
})[0];
@@ -1365,9 +1368,9 @@ export class PostgreSQLClient extends BaseClient {
return results.rows.map(async row => {
if (!row.pg_get_functiondef) {
return {
definer: null,
definer: null as null,
sql: '',
parameters: [],
parameters: [] as null[],
name: func,
comment: '',
security: 'DEFINER',
@@ -1415,8 +1418,8 @@ export class PostgreSQLClient extends BaseClient {
name: func,
comment: '',
security: row.pg_get_functiondef.includes('SECURITY DEFINER') ? 'DEFINER' : 'INVOKER',
deterministic: null,
dataAccess: null,
deterministic: null as null,
dataAccess: null as null,
language: row.pg_get_functiondef.match(/(?<=LANGUAGE )(.*)(?<=[\S+\n\r\s])/gm)[0],
returns: row.pg_get_functiondef.match(/(?<=RETURNS )(.*)(?<=[\S+\n\r\s])/gm)[0].replace('SETOF ', '').toUpperCase()
};
@@ -1645,7 +1648,7 @@ export class PostgreSQLClient extends BaseClient {
}
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
this._logger({ cUid: this._cUid, sql });
this._logger({ cUid: this._cUid, content: sql, level: 'query' });
args = {
nest: false,
@@ -1662,9 +1665,7 @@ export class PostgreSQLClient extends BaseClient {
const resultsArr: antares.QueryResult[] = [];
let paramsArr = [];
const queries = args.split
? sql.split(/(?!\B'[^']*);(?![^']*'\B)/gm)
.filter(Boolean)
.map(q => q.trim())
? this._querySplitter(sql, 'pg')
: [sql];
let connection: pg.Client | pg.PoolClient;

View File

@@ -124,10 +124,10 @@ export class SQLiteClient extends BaseClient {
name: db.name,
size: schemaSize,
tables: remappedTables,
functions: [],
procedures: [],
functions: [] as null[],
procedures: [] as null[],
triggers: remappedTriggers,
schedulers: []
schedulers: [] as null[]
};
}
else {
@@ -166,22 +166,22 @@ export class SQLiteClient extends BaseClient {
return {
name: field.name,
key: null,
key: null as null,
type: type.trim(),
schema: schema,
table: table,
numLength: [...NUMBER, ...FLOAT].includes(type) ? length : null,
datePrecision: null,
datePrecision: null as null,
charLength: ![...NUMBER, ...FLOAT].includes(type) ? length : null,
nullable: !field.notnull,
unsigned: null,
zerofill: null,
unsigned: null as null,
zerofill: null as null,
order: typeof field.cid === 'string' ? +field.cid + 1 : field.cid + 1,
default: field.dflt_value,
charset: null,
collation: null,
charset: null as null,
collation: null as null,
autoIncrement: false,
onUpdate: null,
onUpdate: null as null,
comment: ''
};
});
@@ -267,7 +267,7 @@ export class SQLiteClient extends BaseClient {
table: table,
field: field.from,
position: field.id + 1,
constraintPosition: null,
constraintPosition: null as null,
constraintName: field.id,
refSchema: schema,
refTable: field.table,
@@ -612,7 +612,7 @@ export class SQLiteClient extends BaseClient {
}
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
this._logger({ cUid: this._cUid, sql });// TODO: replace BLOB content with a placeholder
this._logger({ cUid: this._cUid, content: sql, level: 'query' });// TODO: replace BLOB content with a placeholder
args = {
nest: false,
@@ -629,9 +629,7 @@ export class SQLiteClient extends BaseClient {
const resultsArr = [];
let paramsArr = [];
const queries = args.split
? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm)
.filter(Boolean)
.map(q => q.trim())
? this._querySplitter(sql, 'sqlite')
: [sql];
let connection: sqlite.Database;

View File

@@ -0,0 +1,20 @@
export type LoggerLevel = 'query' | 'error'
export const ipcLogger = ({ content, cUid, level }: {content: string; cUid: string; level: LoggerLevel}) => {
if (level === 'error') {
if (process.type !== undefined) {
const mainWindow = require('electron').webContents.fromId(1);
mainWindow.send('non-blocking-exception', { cUid, message: content, date: new Date() });
}
if (process.env.NODE_ENV === 'development' && process.type === 'browser') console.log(content);
}
else if (level === 'query') {
// Remove comments, newlines and multiple spaces
const escapedSql = content.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '').replace(/\s\s+/g, ' ');
if (process.type !== undefined) {
const mainWindow = require('electron').webContents.fromId(1);
mainWindow.send('query-log', { cUid, sql: escapedSql, date: new Date() });
}
if (process.env.NODE_ENV === 'development' && process.type === 'browser') console.log(escapedSql);
}
};

View File

@@ -43,7 +43,8 @@ async function createMainWindow () {
spellcheck: false
},
autoHideMenuBar: true,
titleBarStyle: isLinux ? 'default' :'hidden',
frame: !isLinux,
titleBarStyle: 'hidden',
titleBarOverlay: isWindows
? {
color: appTheme === 'dark' ? '#3f3f3f' : '#fff',
@@ -127,15 +128,25 @@ app.on('ready', async () => {
if (isWindows)
mainWindow.show();
if (isDevelopment && !isWindows)// Because on Windows you can open devtools from title-bar
mainWindow.webContents.openDevTools();
// if (isDevelopment && !isWindows)
// mainWindow.webContents.openDevTools();
process.on('uncaughtException', error => {
mainWindow.webContents.send('unhandled-exception', error);
if (error instanceof AggregateError) {
for (const e of error.errors)
mainWindow.webContents.send('unhandled-exception', e);
}
else
mainWindow.webContents.send('unhandled-exception', error);
});
process.on('unhandledRejection', error => {
mainWindow.webContents.send('unhandled-exception', error);
if (error instanceof AggregateError) {
for (const e of error.errors)
mainWindow.webContents.send('unhandled-exception', e);
}
else
mainWindow.webContents.send('unhandled-exception', error);
});
});

View File

@@ -141,8 +141,11 @@ onMounted(() => {
while (node) {
if (node.nodeName.match(/^(input|textarea)$/i) || node.isContentEditable) {
InputMenu.popup({ window: getCurrentWindow() });
break;
if (!node.parentNode.className.split(' ').includes('editor-query')) {
InputMenu.popup({ window: getCurrentWindow() });
console.log(node.parentNode.className);
break;
}
}
node = node.parentNode;
}

View File

@@ -39,11 +39,11 @@ const props = defineProps({
default: () => 'mdi'
},
flip: {
type: String as PropType<'horizontal' | 'vertical' | 'both'>,
type: String as PropType<'horizontal' | 'vertical' | 'both' | null>,
default: () => null
},
rotate: {
type: Number,
type: Number as PropType<number | null>,
default: () => null
}
});
@@ -55,8 +55,7 @@ const iconPath = computed(() => {
const base64 = getIconByUid(props.iconName)?.base64;
const svgString = Buffer
.from(base64, 'base64')
.toString('utf-8')
.replaceAll(/width="[^"]*"|height="[^"]*"/g, '');
.toString('utf-8');
return svgString;
}

View File

@@ -21,7 +21,23 @@
<a class="tab-link" @click="selectedTab = 'debug'">{{ t('application.debugConsole') }}</a>
</li>
</ul>
<button class="btn btn-clear mr-1" @click="resizeConsole(0)" />
<div class="d-flex">
<div
v-if="isDevelopment"
class="c-hand mr-2"
@click="openDevTools()"
>
<BaseIcon icon-name="mdiBugPlayOutline" :size="22" />
</div>
<div
v-if="isDevelopment"
class="c-hand mr-2"
@click="reload()"
>
<BaseIcon icon-name="mdiRefresh" :size="22" />
</div>
<button class="btn btn-clear mr-1" @click="resizeConsole(0)" />
</div>
</div>
<div
v-show="selectedTab === 'query'"
@@ -71,6 +87,7 @@
</BaseContextMenu>
</template>
<script setup lang="ts">
import { getCurrentWindow } from '@electron/remote';
import * as moment from 'moment';
import { storeToRefs } from 'pinia';
import { highlight } from 'sql-highlight';
@@ -112,6 +129,8 @@ const isHover = ref(false);
const isContext = ref(false);
const contextContent: Ref<string> = ref(null);
const contextEvent: Ref<MouseEvent> = ref(null);
const w = ref(getCurrentWindow());
const isDevelopment = ref(process.env.NODE_ENV === 'development');
const resize = (e: MouseEvent) => {
const el = queryConsole.value;
@@ -142,6 +161,14 @@ const copyLog = () => {
isContext.value = false;
};
const openDevTools = () => {
w.value.webContents.openDevTools();
};
const reload = () => {
w.value.reload();
};
watch(workspaceQueryLogs, async () => {
if (!isHover.value) {
await nextTick();

View File

@@ -127,7 +127,7 @@ const fakerGroups = computed(() => {
localType.value = 'datetime';
else if (TIME.includes(props.type))
localType.value = 'time';
else if (UUID.includes(props.type))
else if (UUID.includes(props.type) || (BLOB.includes(props.type) && props.field.key === 'pri'))
localType.value = 'uuid';
else
localType.value = 'none';
@@ -177,7 +177,7 @@ const inputProps = () => {
return { type: 'text', mask: datetimeMask };
}
if (BLOB.includes(props.type))
if (BLOB.includes(props.type) && props.field.key !== 'pri')
return { type: 'file', mask: false };
if (BIT.includes(props.type))

View File

@@ -131,8 +131,10 @@ import Application from '@/ipc-api/Application';
import { camelize } from '@/libs/camelize';
import { unproxify } from '@/libs/unproxify';
import { SidebarElement, useConnectionsStore } from '@/stores/connections';
import { useNotificationsStore } from '@/stores/notifications';
const connectionsStore = useConnectionsStore();
const { addNotification } = useNotificationsStore();
const { addIcon, removeIcon, updateConnectionOrder, getConnectionName } = connectionsStore;
const { customIcons } = storeToRefs(connectionsStore);
@@ -225,12 +227,56 @@ const removeIconHandler = () => {
isContext.value = false;
};
const adjustSVGContent = (svgContent: string) => {
try {
const parser = new DOMParser();
const doc = parser.parseFromString(svgContent, 'image/svg+xml');
const parseError = doc.querySelector('parsererror');
if (parseError) {
addNotification({ status: 'error', message: parseError.textContent });
return null;
}
const svg = doc.documentElement;
if (svg.tagName.toLowerCase() !== 'svg') {
addNotification({ status: 'error', message: t('application.invalidFIle') });
return null;
}
if (!svg.hasAttribute('viewBox')) {
const width = svg.getAttribute('width') || '36';
const height = svg.getAttribute('height') || '36';
svg.setAttribute('viewBox', `0 0 ${width} ${height}`);
}
svg.removeAttribute('width');
svg.removeAttribute('height');
const serializer = new XMLSerializer();
return serializer.serializeToString(svg);
}
catch (error) {
addNotification({ status: 'error', message: error.stack });
return null;
}
};
const openFile = async () => {
const result = await Application.showOpenDialog({ properties: ['openFile'], filters: [{ name: '"SVG"', extensions: ['svg'] }] });
const result = await Application.showOpenDialog({
properties: ['openFile'],
filters: [{ name: '"SVG"', extensions: ['svg'] }]
});
if (result && !result.canceled) {
const file = result.filePaths[0];
const content = await Application.readFile({ filePath: file, encoding: 'base64url' });
addIcon(content);
let content = await Application.readFile({ filePath: file, encoding: 'utf-8' });
content = adjustSVGContent(content);
const base64Content = Buffer.from(content).toString('base64');
addIcon(base64Content);
}
};

View File

@@ -339,6 +339,8 @@ onMounted(() => {
for (const field of props.fields) {
if (typeof props.rowToDuplicate[field.name] !== 'object')
rowObj[field.name] = { value: props.rowToDuplicate[field.name] };
else if (field.type === 'JSON')
rowObj[field.name] = { value: JSON.stringify(props.rowToDuplicate[field.name]) };
if (field.autoIncrement || !!field.onUpdate)// Disable by default auto increment or "on update" fields
fieldsToExclude.value = [...fieldsToExclude.value, field.name];

View File

@@ -612,7 +612,7 @@ const otherContributors = computed(() => {
return contributors
.split(',')
.filter(c => !c.includes(appAuthor))
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
.sort((a, b) => a.toLowerCase().trim().localeCompare(b.toLowerCase()));
});
const selectTab = (tab: string) => {

View File

@@ -42,7 +42,7 @@
tabindex="0"
>
<div class="td py-1">
{{ t(shortcutEvents[shortcut.event].l18n, {param: shortcutEvents[shortcut.event].l18nParam}) }}
{{ t(shortcutEvents[shortcut.event].i18n, {param: shortcutEvents[shortcut.event].i18nParam}) }}
</div>
<div
class="td py-1"
@@ -167,7 +167,7 @@
</template>
<template #body>
<div class="mb-2">
{{ t('general.deleteConfirm') }} <b>{{ t(shortcutEvents[shortcutToDelete.event].l18n, {param: shortcutEvents[shortcutToDelete.event].l18nParam}) }} (<span v-html="parseKeys(shortcutToDelete.keys)" />)</b>?
{{ t('general.deleteConfirm') }} <b>{{ t(shortcutEvents[shortcutToDelete.event].i18n, {param: shortcutEvents[shortcutToDelete.event].i18nParam}) }} (<span v-html="parseKeys(shortcutToDelete.keys)" />)</b>?
</div>
</template>
</ConfirmModal>
@@ -233,7 +233,7 @@ const { shortcuts } = storeToRefs(settingsStore);
const eventOptions = computed(() => {
return Object.keys(shortcutEvents)
.map(key => {
return { value: key, label: t(shortcutEvents[key].l18n, { param: shortcutEvents[key].l18nParam }) };
return { value: key, label: t(shortcutEvents[key].i18n, { param: shortcutEvents[key].i18nParam }) };
})
.sort((a, b) => {
if (a.label < b.label) return -1;

View File

@@ -3,6 +3,7 @@
<div
:id="`editor-${id}`"
class="editor"
:class="editorClasses"
:style="{height: `${height}px`}"
/>
</div>
@@ -54,7 +55,8 @@ const props = defineProps({
schema: { type: String, default: '' },
autoFocus: { type: Boolean, default: false },
readOnly: { type: Boolean, default: false },
height: { type: Number, default: 200 }
height: { type: Number, default: 200 },
editorClasses: { type: String, default: '' }
});
const emit = defineEmits(['update:modelValue']);
@@ -405,18 +407,17 @@ defineExpose({ editor });
.ace_gutter-cell.ace_breakpoint {
&::before {
content: '\F0403';
content: '';
position: absolute;
left: 3px;
top: 2px;
color: var(--primary-color);
left: 0px;
top: 8px;
display: inline-block;
font: normal normal normal 24px/1 "Material Design Icons", sans-serif;
font-size: inherit;
text-rendering: auto;
line-height: inherit;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
width: 0;
height: 0;
border-left: 8px solid transparent;
border-top: 8px solid transparent;
border-right: 8px solid var(--primary-color);
transform: rotate(-45deg);
}
}
</style>

View File

@@ -47,65 +47,50 @@
<div class="tile-history-buttons">
<button
v-if="note.type === 'todo' && !note.isArchived"
class="btn btn-link pl-1"
class="btn btn-dark tooltip tooltip-left"
:data-tooltip="t('general.archive')"
@click.stop="$emit('archive-note', note.uid)"
>
<BaseIcon
icon-name="mdiCheck"
class="pr-1"
:size="22"
/> {{ t('general.archive') }}
<BaseIcon icon-name="mdiCheck" :size="22" />
</button>
<button
v-if="note.type === 'todo' && note.isArchived"
class="btn btn-link pl-1"
class="btn btn-dark tooltip tooltip-left"
:data-tooltip="t('general.undo')"
@click.stop="$emit('restore-note', note.uid)"
>
<BaseIcon
icon-name="mdiRestore"
class="pr-1"
:size="22"
/> {{ t('general.undo') }}
<BaseIcon icon-name="mdiRestore" :size="22" />
</button>
<button
v-if="note.type === 'query'"
class="btn btn-link pl-1"
class="btn btn-dark tooltip tooltip-left"
:data-tooltip="t('general.select')"
@click.stop="$emit('select-query', note.note)"
>
<BaseIcon
icon-name="mdiOpenInApp"
class="pr-1"
:size="22"
/> {{ t('general.select') }}
<BaseIcon icon-name="mdiOpenInApp" :size="22" />
</button>
<button
v-if="note.type === 'query'"
class="btn btn-link pl-1"
class="btn btn-dark tooltip tooltip-left"
:data-tooltip="t('general.copy')"
@click.stop="copyText(note.note)"
>
<BaseIcon
icon-name="mdiContentCopy"
class="pr-1"
:size="22"
/> {{ t('general.copy') }}
<BaseIcon icon-name="mdiContentCopy" :size="18" />
</button>
<button
v-if=" !note.isArchived"
class="btn btn-link pl-1"
class="btn btn-dark tooltip tooltip-left"
:data-tooltip="t('general.edit')"
@click.stop="$emit('edit-note')"
>
<BaseIcon
icon-name="mdiPencil"
class="pr-1"
:size="22"
/> {{ t('general.edit') }}
<BaseIcon icon-name="mdiPencil" :size="22" />
</button>
<button class="btn btn-link pl-1" @click.stop="$emit('delete-note', note.uid)">
<BaseIcon
icon-name="mdiDeleteForever"
class="pr-1"
:size="22"
/> {{ t('general.delete') }}
<button
class="btn btn-dark tooltip tooltip-left"
:data-tooltip="t('general.delete')"
@click.stop="$emit('delete-note', note.uid)"
>
<BaseIcon icon-name="mdiDeleteForever" :size="22" />
</button>
</div>
</div>
@@ -278,11 +263,14 @@ const highlightWord = (string: string) => {
button {
font-size: 0.7rem;
height: 1rem;
line-height: 1rem;
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0 5px;
padding: 0;
height: 24px;
width: 24px;
}
}
}

View File

@@ -1,6 +1,5 @@
<template>
<div
v-if="!isLinux"
id="titlebar"
@dblclick="toggleFullScreen"
>
@@ -21,16 +20,27 @@
class="titlebar-element"
@click="openDevTools"
>
<BaseIcon icon-name="mdiBugPlayOutline" :size="24" />
<BaseIcon icon-name="mdiBugPlayOutline" :size="18" />
</div>
<div
v-if="isDevelopment"
class="titlebar-element"
@click="reload"
>
<BaseIcon icon-name="mdiRefresh" :size="24" />
<BaseIcon icon-name="mdiRefresh" :size="18" />
</div>
<div v-if="isWindows" :style="'width: 140px;'" />
<div v-if="isLinux" class="d-flex">
<div class="titlebar-element" @click="minimize">
<BaseIcon icon-name="mdiWindowMinimize" :size="18" />
</div>
<div class="titlebar-element" @click="toggleFullScreen">
<BaseIcon :icon-name="isMaximized ? 'mdiWindowRestore' : 'mdiWindowMaximize'" :size="18" />
</div>
<div class="titlebar-element" @click="closeApp">
<BaseIcon icon-name="mdiClose" :size="18" />
</div>
</div>
</div>
</div>
</template>
@@ -74,6 +84,18 @@ const windowTitle = computed(() => {
return [connectionName, ...breadcrumbs].join(' • ');
});
const openDevTools = () => {
w.value.webContents.openDevTools();
};
const reload = () => {
w.value.reload();
};
const minimize = () => {
w.value.minimize();
};
const toggleFullScreen = () => {
if (isMaximized.value)
w.value.unmaximize();
@@ -81,12 +103,8 @@ const toggleFullScreen = () => {
w.value.maximize();
};
const openDevTools = () => {
w.value.webContents.openDevTools();
};
const reload = () => {
w.value.reload();
const closeApp = () => {
ipcRenderer.send('close-app');
};
const onResize = () => {

View File

@@ -64,7 +64,7 @@
>
<BaseIcon
class="mt-1 mr-1"
:icon-name="['view', 'materializedview'].includes(element.elementType) ? 'mdiTableEye' : 'mdiTable'"
:icon-name="['view', 'materializedView'].includes(element.elementType) ? 'mdiTableEye' : 'mdiTable'"
:size="18"
/>
<span :title="`${t('general.data').toUpperCase()}: ${t(`database.${element.elementType}`)}`">
@@ -81,7 +81,7 @@
<a v-else-if="element.type === 'data'" class="tab-link">
<BaseIcon
class="mt-1 mr-1"
:icon-name="['view', 'materializedview'].includes(element.elementType) ? 'mdiTableEye' : 'mdiTable'"
:icon-name="['view', 'materializedView'].includes(element.elementType) ? 'mdiTableEye' : 'mdiTable'"
:size="18"
/>
<span :title="`${t('general.data').toUpperCase()}: ${t(`database.${element.elementType}`)}`">

View File

@@ -67,7 +67,7 @@
<div class="column col-7 col-sm-12">
<input
ref="pgString"
v-model="connection.pgConnString"
v-model="connection.connString"
class="form-input"
type="text"
>
@@ -502,8 +502,8 @@ const connection = ref({
sshKey: '',
sshPort: 22,
sshKeepAliveInterval: 1800,
pgConnString: ''
}) as Ref<ConnectionParams & { pgConnString: string }>;
connString: ''
}) as Ref<ConnectionParams & { connString: string }>;
const firstInput: Ref<HTMLInputElement> = ref(null);
const isConnecting = ref(false);

View File

@@ -68,7 +68,7 @@
<div class="column col-7 col-sm-12">
<input
ref="pgString"
v-model="localConnection.pgConnString"
v-model="localConnection.connString"
class="form-input"
type="text"
>
@@ -502,7 +502,7 @@ const clients = [
];
const firstInput: Ref<HTMLInputElement> = ref(null);
const localConnection: Ref<ConnectionParams & { pgConnString: string }> = ref(null);
const localConnection: Ref<ConnectionParams & { connString: string }> = ref(null);
const isConnecting = ref(false);
const isTesting = ref(false);
const isAsking = ref(false);

View File

@@ -143,7 +143,7 @@
:selected-schema="selectedSchema"
:context-event="miscContextEvent"
@open-create-view-tab="openCreateElementTab('view')"
@open-create-materializedview-tab="openCreateElementTab('materialized-view')"
@open-create-materializedView-tab="openCreateElementTab('materialized-view')"
@open-create-trigger-tab="openCreateElementTab('trigger')"
@open-create-trigger-function-tab="openCreateElementTab('trigger-function')"
@open-create-routine-tab="openCreateElementTab('routine')"

View File

@@ -16,9 +16,9 @@
/> {{ t('database.createNewView') }}</span>
</div>
<div
v-if="props.selectedMisc === 'materializedview'"
v-if="props.selectedMisc === 'materializedView'"
class="context-element"
@click="emit('open-create-materializedview-tab')"
@click="emit('open-create-materializedView-tab')"
>
<span class="d-flex">
<BaseIcon
@@ -106,7 +106,7 @@ const props = defineProps({
const emit = defineEmits([
'open-create-view-tab',
'open-create-materializedview-tab',
'open-create-materializedView-tab',
'open-create-trigger-tab',
'open-create-routine-tab',
'open-create-function-tab',

View File

@@ -121,7 +121,7 @@
<summary
class="accordion-header misc-name"
:class="{'text-bold': breadcrumbs.schema === database.name && breadcrumbs.trigger}"
@contextmenu.prevent="showMiscFolderContext($event, 'materializedview')"
@contextmenu.prevent="showMiscFolderContext($event, 'materializedView')"
>
<BaseIcon
class="misc-icon mr-1"
@@ -133,7 +133,7 @@
icon-name="mdiFolderOpen"
:size="18"
/>
{{ t('database.materializedview', 2) }}
{{ t('database.materializedView', 2) }}
</summary>
<div class="accordion-body">
<div>
@@ -477,8 +477,12 @@ const searchTerm = computed(() => {
});
const filteredTables = computed(() => {
if (props.searchMethod === 'elements')
return props.database.tables.filter(table => table.name.search(searchTerm.value) >= 0 && table.type === 'table');
if (props.searchMethod === 'elements') {
const searchTermLower = searchTerm.value.toLowerCase();
return props.database.tables.filter(table =>
table.name.toLowerCase().includes(searchTermLower) && table.type === 'table'
);
}
else
return props.database.tables;
});
@@ -492,9 +496,9 @@ const filteredViews = computed(() => {
const filteredMatViews = computed(() => {
if (props.searchMethod === 'elements')
return props.database.tables.filter(table => table.name.search(searchTerm.value) >= 0 && table.type === 'materializedview');
return props.database.tables.filter(table => table.name.search(searchTerm.value) >= 0 && table.type === 'materializedView');
else
return props.database.tables.filter(table => table.type === 'materializedview');
return props.database.tables.filter(table => table.type === 'materializedView');
});
const filteredTriggers = computed(() => {

View File

@@ -50,7 +50,7 @@
class="text-light mt-1 mr-1"
icon-name="mdiTableEye"
:size="18"
/> {{ t('database.materializedview') }}</span>
/> {{ t('database.materializedView') }}</span>
</div>
<div
v-if="workspace.customizations.triggerAdd"

View File

@@ -48,7 +48,7 @@
/> {{ t('application.settings') }}</span>
</div>
<div
v-if="selectedTable && selectedTable.type === 'materializedview' && customizations.materializedViewSettings"
v-if="selectedTable && selectedTable.type === 'materializedView' && customizations.materializedViewSettings"
class="context-element"
@click="openMaterializedViewSettingTab"
>

View File

@@ -195,7 +195,7 @@ const saveChanges = async () => {
uid: props.connection.uid,
schema: props.schema,
elementName: localView.value.name,
elementType: 'materializedview',
elementType: 'materializedView',
type: 'materialized-view-props'
});

View File

@@ -72,6 +72,20 @@
/>
<span>{{ t('database.foreignKeys') }}</span>
</button>
<button
v-if="workspace.customizations.tableCheck"
class="btn btn-dark btn-sm ml-2 mr-0"
:disabled="isSaving || !localFields.length"
:title="t('database.manageTableChecks')"
@click="showTableChecksModal"
>
<BaseIcon
class="mr-1"
icon-name="mdiTableCheck"
:size="24"
/>
<span>{{ t('database.tableChecks') }}</span>
</button>
</div>
<div class="workspace-query-info">
<div class="d-flex" :title="t('database.schema')">
@@ -183,11 +197,19 @@
@hide="hideForeignModal"
@foreigns-update="foreignsUpdate"
/>
<WorkspaceTabPropsTableChecksModal
v-if="isTableChecksModal"
:local-checks="localTableChecks"
table="new"
:workspace="workspace"
@hide="hideTableChecksModal"
@checks-update="checksUpdate"
/>
</div>
</template>
<script setup lang="ts">
import { ConnectionParams, TableField, TableForeign, TableIndex, TableOptions } from 'common/interfaces/antares';
import { ConnectionParams, TableCheck, TableField, TableForeign, TableIndex, TableOptions } from 'common/interfaces/antares';
import { uidGen } from 'common/libs/uidGen';
import { ipcRenderer } from 'electron';
import { storeToRefs } from 'pinia';
@@ -198,6 +220,7 @@ import BaseIcon from '@/components/BaseIcon.vue';
import BaseLoader from '@/components/BaseLoader.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import WorkspaceTabNewTableEmptyState from '@/components/WorkspaceTabNewTableEmptyState.vue';
import WorkspaceTabPropsTableChecksModal from '@/components/WorkspaceTabPropsTableChecksModal.vue';
import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue';
import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue';
import WorkspaceTabPropsTableIndexesModal from '@/components/WorkspaceTabPropsTableIndexesModal.vue';
@@ -236,12 +259,16 @@ const isLoading = ref(false);
const isSaving = ref(false);
const isIndexesModal = ref(false);
const isForeignModal = ref(false);
const isTableChecksModal = ref(false);
const originalFields: Ref<TableField[]> = ref([]);
const localFields: Ref<TableField[]> = ref([]);
const originalKeyUsage: Ref<TableForeign[]> = ref([]);
const localKeyUsage: Ref<TableForeign[]> = ref([]);
const originalIndexes: Ref<TableIndex[]> = ref([]);
const localIndexes: Ref<TableIndex[]> = ref([]);
const originalTableChecks: Ref<TableCheck[]> = ref([]);
const localTableChecks: Ref<TableCheck[]> = ref([]);
const tableOptions: Ref<TableOptions> = ref(null);
const localOptions: Ref<TableOptions> = ref(null);
const newFieldsCounter = ref(0);
@@ -274,6 +301,7 @@ const isChanged = computed(() => {
return JSON.stringify(originalFields.value) !== JSON.stringify(localFields.value) ||
JSON.stringify(originalKeyUsage.value) !== JSON.stringify(localKeyUsage.value) ||
JSON.stringify(originalIndexes.value) !== JSON.stringify(localIndexes.value) ||
JSON.stringify(originalTableChecks.value) !== JSON.stringify(localTableChecks.value) ||
JSON.stringify(tableOptions.value) !== JSON.stringify(localOptions.value);
});
@@ -291,6 +319,7 @@ const saveChanges = async () => {
fields: localFields.value,
foreigns: localKeyUsage.value,
indexes: localIndexes.value,
checks: localTableChecks.value,
options: localOptions.value
};
@@ -326,6 +355,7 @@ const clearChanges = () => {
localFields.value = JSON.parse(JSON.stringify(originalFields.value));
localIndexes.value = JSON.parse(JSON.stringify(originalIndexes.value));
localKeyUsage.value = JSON.parse(JSON.stringify(originalKeyUsage.value));
localTableChecks.value = JSON.parse(JSON.stringify(originalTableChecks.value));
tableOptions.value = {
name: '',
@@ -446,10 +476,22 @@ const hideForeignModal = () => {
isForeignModal.value = false;
};
const showTableChecksModal = () => {
isTableChecksModal.value = true;
};
const hideTableChecksModal = () => {
isTableChecksModal.value = false;
};
const foreignsUpdate = (foreigns: TableForeign[]) => {
localKeyUsage.value = foreigns;
};
const checksUpdate = (checks: TableCheck[]) => {
localTableChecks.value = checks;
};
const saveContentListener = () => {
const hasModalOpen = !!document.querySelectorAll('.modal.active').length;
if (props.isSelected && !hasModalOpen && isChanged.value)

View File

@@ -227,7 +227,7 @@ const saveChanges = async () => {
schema: props.schema,
elementName: oldName,
elementNewName: localView.value.name,
elementType: 'materializedview'
elementType: 'materializedView'
});
changeBreadcrumbs({ schema: props.schema, view: localView.value.name });

View File

@@ -62,7 +62,7 @@
<button
class="btn btn-dark btn-sm mr-0"
:disabled="isSaving"
:title="t('database.manageIndexes')"
:title="t('database.manageForeignKeys')"
@click="showForeignModal"
>
<BaseIcon
@@ -72,6 +72,20 @@
/>
<span>{{ t('database.foreignKeys') }}</span>
</button>
<button
v-if="workspace.customizations.tableCheck"
class="btn btn-dark btn-sm ml-2 mr-0"
:disabled="isSaving"
:title="t('database.manageTableChecks')"
@click="showTableChecksModal"
>
<BaseIcon
class="mr-1"
icon-name="mdiTableCheck"
:size="24"
/>
<span>{{ t('database.tableChecks') }}</span>
</button>
<div class="divider-vert py-3" />
@@ -218,11 +232,19 @@
:workspace="workspace"
@hide="hideDdlModal"
/>
<WorkspaceTabPropsTableChecksModal
v-if="isTableChecksModal"
:local-checks="localTableChecks"
:table="table"
:workspace="workspace"
@hide="hideTableChecksModal"
@checks-update="checksUpdate"
/>
</div>
</template>
<script setup lang="ts">
import { AlterTableParams, TableField, TableForeign, TableIndex, TableInfos, TableOptions } from 'common/interfaces/antares';
import { AlterTableParams, TableCheck, TableField, TableForeign, TableIndex, TableInfos, TableOptions } from 'common/interfaces/antares';
import { uidGen } from 'common/libs/uidGen';
import { ipcRenderer } from 'electron';
import { storeToRefs } from 'pinia';
@@ -232,6 +254,7 @@ import { useI18n } from 'vue-i18n';
import BaseIcon from '@/components/BaseIcon.vue';
import BaseLoader from '@/components/BaseLoader.vue';
import BaseSelect from '@/components/BaseSelect.vue';
import WorkspaceTabPropsTableChecksModal from '@/components/WorkspaceTabPropsTableChecksModal.vue';
import WorkspaceTabPropsTableDdlModal from '@/components/WorkspaceTabPropsTableDdlModal.vue';
import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue';
import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue';
@@ -273,13 +296,17 @@ const isLoading = ref(false);
const isSaving = ref(false);
const isIndexesModal = ref(false);
const isForeignModal = ref(false);
const isTableChecksModal = ref(false);
const isDdlModal = ref(false);
const originalFields: Ref<TableField[]> = ref([]);
const localFields: Ref<TableField[]> = ref([]);
const originalKeyUsage: Ref<TableForeign[]> = ref([]);
const localKeyUsage: Ref<TableForeign[]> = ref([]);
const originalIndexes: Ref<TableIndex[]> = ref([]);
const localIndexes: Ref<TableIndex[]> = ref([]);
const originalTableChecks: Ref<TableCheck[]> = ref([]);
const localTableChecks: Ref<TableCheck[]> = ref([]);
const tableOptions: Ref<TableOptions> = ref(null);
const localOptions: Ref<TableOptions> = ref({} as TableOptions);
const lastTable = ref(null);
@@ -307,6 +334,7 @@ const isChanged = computed(() => {
return JSON.stringify(originalFields.value) !== JSON.stringify(localFields.value) ||
JSON.stringify(originalKeyUsage.value) !== JSON.stringify(localKeyUsage.value) ||
JSON.stringify(originalIndexes.value) !== JSON.stringify(localIndexes.value) ||
JSON.stringify(originalTableChecks.value) !== JSON.stringify(localTableChecks.value) ||
JSON.stringify(tableOptions.value) !== JSON.stringify(localOptions.value);
});
@@ -431,6 +459,27 @@ const getFieldsData = async () => {
}
isLoading.value = false;
if (workspace.value.customizations.tableCheck) {
try { // Table checks
const { status, response } = await Tables.getTableChecks(params);
if (status === 'success') {
originalTableChecks.value = response.map((check: TableCheck) => {
return {
_antares_id: uidGen(),
...check
};
});
localTableChecks.value = JSON.parse(JSON.stringify(originalTableChecks.value));
}
else
addNotification({ status: 'error', message: response });
}
catch (err) {
addNotification({ status: 'error', message: err.stack });
}
}
};
const saveChanges = async () => {
@@ -527,6 +576,33 @@ const saveChanges = async () => {
// Foreigns Deletions
foreignChanges.deletions = originalKeyUsage.value.filter(foreign => !localForeignIDs.includes(foreign._antares_id));
// CHECKS
const checkChanges = {
additions: [] as TableCheck[],
changes: [] as TableCheck[],
deletions: [] as TableCheck[]
};
const originalCheckIDs = originalTableChecks.value.reduce((acc, curr) => [...acc, curr._antares_id], []);
const localCheckIDs = localTableChecks.value.reduce((acc, curr) => [...acc, curr._antares_id], []);
// Check Additions
checkChanges.additions = localTableChecks.value.filter(check => !originalCheckIDs.includes(check._antares_id));
// Check Changes
originalTableChecks.value.forEach(originalCheck => {
const lI = localTableChecks.value.findIndex(localCheck => localCheck._antares_id === originalCheck._antares_id);
if (JSON.stringify(originalCheck) !== JSON.stringify(localTableChecks.value[lI])) {
if (localTableChecks.value[lI]) {
checkChanges.changes.push({
...localTableChecks.value[lI]
});
}
}
});
// Check Deletions
checkChanges.deletions = originalTableChecks.value.filter(check => !localCheckIDs.includes(check._antares_id));
// ALTER
const params = {
uid: props.connection.uid,
@@ -543,6 +619,7 @@ const saveChanges = async () => {
deletions,
indexChanges,
foreignChanges,
checkChanges,
options
} as unknown as AlterTableParams;
@@ -583,6 +660,7 @@ const clearChanges = () => {
localFields.value = JSON.parse(JSON.stringify(originalFields.value));
localIndexes.value = JSON.parse(JSON.stringify(originalIndexes.value));
localKeyUsage.value = JSON.parse(JSON.stringify(originalKeyUsage.value));
localTableChecks.value = JSON.parse(JSON.stringify(originalTableChecks.value));
localOptions.value = JSON.parse(JSON.stringify(tableOptions.value));
newFieldsCounter.value = 0;
};
@@ -702,6 +780,14 @@ const hideForeignModal = () => {
isForeignModal.value = false;
};
const showTableChecksModal = () => {
isTableChecksModal.value = true;
};
const hideTableChecksModal = () => {
isTableChecksModal.value = false;
};
const showDdlModal = () => {
isDdlModal.value = true;
};
@@ -714,6 +800,10 @@ const foreignsUpdate = (foreigns: TableForeign[]) => {
localKeyUsage.value = foreigns;
};
const checksUpdate = (checks: TableCheck[]) => {
localTableChecks.value = checks;
};
const saveContentListener = () => {
const hasModalOpen = !!document.querySelectorAll('.modal.active').length;
if (props.isSelected && !hasModalOpen && isChanged.value)

View File

@@ -0,0 +1,268 @@
<template>
<ConfirmModal
:confirm-text="t('general.confirm')"
size="medium"
class="options-modal"
@confirm="confirmChecksChange"
@hide="$emit('hide')"
>
<template #header>
<div class="d-flex">
<BaseIcon
class="mr-1"
icon-name="mdiTableCheck"
:size="24"
/>
<span class="cut-text">{{ t('database.tableChecks') }} "{{ table }}"</span>
</div>
</template>
<template #body>
<div class="columns col-gapless">
<div class="column col-5">
<div class="panel" :style="{ height: modalInnerHeight + 'px'}">
<div class="panel-header pt-0 pl-0">
<div class="d-flex">
<button class="btn btn-dark btn-sm d-flex" @click="addCheck">
<BaseIcon
class="mr-1"
icon-name="mdiCheckboxMarkedCirclePlusOutline"
:size="24"
/>
<span>{{ t('general.add') }}</span>
</button>
<button
class="btn btn-dark btn-sm d-flex ml-2 mr-0"
:title="t('database.clearChanges')"
:disabled="!isChanged"
@click.prevent="clearChanges"
>
<BaseIcon
class="mr-1"
icon-name="mdiDeleteSweep"
:size="24"
/>
<span>{{ t('general.clear') }}</span>
</button>
</div>
</div>
<div ref="checksPanel" class="panel-body p-0 pr-1">
<div
v-for="check in checksProxy"
:key="check._antares_id"
class="tile tile-centered c-hand mb-1 p-1"
:class="{'selected-element': selectedCheckID === check._antares_id}"
@click="selectCheck($event, check._antares_id)"
>
<div class="tile-icon">
<div>
<BaseIcon
class="mt-2 column-key"
icon-name="mdiCheckboxMarkedCircleOutline"
:size="24"
/>
</div>
</div>
<div class="tile-content">
<div class="tile-title">
{{ check.name }}
</div>
<small class="tile-subtitle text-gray d-inline-block cut-text" style="width: 100%;">{{ check.clause }}</small>
</div>
<div class="tile-action">
<button
class="btn btn-link remove-field p-0 mr-2"
:title="t('general.delete')"
@click.prevent="removeCheck(check._antares_id)"
>
<BaseIcon
icon-name="mdiClose"
:size="18"
class="mt-2"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="column col-7 pl-2 editor-col">
<form
v-if="selectedCheckObj"
:style="{ height: modalInnerHeight + 'px'}"
class="form-horizontal"
>
<div class="form-group">
<label class="form-label col-3">
{{ t('general.name') }}
</label>
<div class="column">
<input
v-model="selectedCheckObj.name"
class="form-input"
type="text"
>
</div>
</div>
<div class="form-group">
<label class="form-label col-3">
{{ t('database.checkClause') }}
</label>
<div class="column">
<textarea
v-model="selectedCheckObj.clause"
class="form-input"
style="resize: vertical;"
rows="5"
/>
</div>
</div>
</form>
<div v-if="!checksProxy.length" class="empty">
<div class="empty-icon">
<BaseIcon
class="mr-1"
icon-name="mdiCheckboxMarkedCircleOutline"
:size="48"
/>
</div>
<p class="empty-title h5">
{{ t('database.thereAreNoTableChecks') }}
</p>
<div class="empty-action">
<button class="btn btn-primary" @click="addCheck">
{{ t('database.createNewCheck') }}
</button>
</div>
</div>
</div>
</div>
</template>
</ConfirmModal>
</template>
<script setup lang="ts">
import { TableCheck } from 'common/interfaces/antares';
import { uidGen } from 'common/libs/uidGen';
import { computed, onMounted, onUnmounted, Ref, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import ConfirmModal from '@/components/BaseConfirmModal.vue';
import BaseIcon from '@/components/BaseIcon.vue';
const { t } = useI18n();
const props = defineProps({
localChecks: Array,
table: String,
workspace: Object
});
const emit = defineEmits(['hide', 'checks-update']);
const checksPanel: Ref<HTMLDivElement> = ref(null);
const checksProxy: Ref<TableCheck[]> = ref([]);
const selectedCheckID = ref('');
const modalInnerHeight = ref(400);
const selectedCheckObj = computed(() => checksProxy.value.find(index => index._antares_id === selectedCheckID.value));
const isChanged = computed(() => JSON.stringify(props.localChecks) !== JSON.stringify(checksProxy.value));
const confirmChecksChange = () => {
const filteredChecks = checksProxy.value.filter(check => check.clause.trim().length);
emit('checks-update', filteredChecks);
};
const selectCheck = (event: MouseEvent, id: string) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (selectedCheckID.value !== id && !(event.target as any).classList.contains('remove-field'))
selectedCheckID.value = id;
};
const getModalInnerHeight = () => {
const modalBody = document.querySelector('.modal-body');
if (modalBody)
modalInnerHeight.value = modalBody.clientHeight - (parseFloat(getComputedStyle(modalBody).paddingTop) + parseFloat(getComputedStyle(modalBody).paddingBottom));
};
const addCheck = () => {
const uid = uidGen();
checksProxy.value = [...checksProxy.value, {
_antares_id: uid,
name: `CHK_${uid.substring(0, 4)}`,
clause: ''
}];
if (checksProxy.value.length === 1)
resetSelectedID();
setTimeout(() => {
checksPanel.value.scrollTop = checksPanel.value.scrollHeight + 60;
selectedCheckID.value = uid;
}, 20);
};
const removeCheck = (id: string) => {
checksProxy.value = checksProxy.value.filter(index => index._antares_id !== id);
if (selectedCheckID.value === id && checksProxy.value.length)
resetSelectedID();
};
const clearChanges = () => {
checksProxy.value = JSON.parse(JSON.stringify(props.localChecks));
if (!checksProxy.value.some(index => index._antares_id === selectedCheckID.value))
resetSelectedID();
};
const resetSelectedID = () => {
selectedCheckID.value = checksProxy.value.length ? checksProxy.value[0]._antares_id : '';
};
onMounted(() => {
checksProxy.value = JSON.parse(JSON.stringify(props.localChecks));
if (checksProxy.value.length)
resetSelectedID();
getModalInnerHeight();
window.addEventListener('resize', getModalInnerHeight);
});
onUnmounted(() => {
window.removeEventListener('resize', getModalInnerHeight);
});
</script>
<style lang="scss" scoped>
.tile {
border-radius: $border-radius;
opacity: 0.5;
transition: background 0.2s;
transition: opacity 0.2s;
.tile-action {
opacity: 0;
transition: opacity 0.2s;
}
&:hover {
.tile-action {
opacity: 1;
}
}
&.selected-element {
opacity: 1;
}
}
.fields-list {
max-height: 300px;
overflow: auto;
}
.remove-field svg {
pointer-events: none;
}
</style>

View File

@@ -15,6 +15,7 @@
:schema="breadcrumbsSchema"
:is-selected="isSelected"
:height="editorHeight"
editor-classes="editor-query"
/>
<div ref="resizer" class="query-area-resizer" />
<div ref="queryAreaFooter" class="workspace-query-runner-footer">
@@ -273,6 +274,7 @@
</template>
<script setup lang="ts">
import { getCurrentWindow, Menu } from '@electron/remote';
import { Ace } from 'ace-builds';
import { ConnectionParams } from 'common/interfaces/antares';
import { uidGen } from 'common/libs/uidGen';
@@ -475,6 +477,8 @@ const runQuery = async (query: string) => {
saveHistory(params);
if (!autocommit.value)
setUnsavedChanges({ uid: props.connection.uid, tUid: props.tabUid, isChanged: true });
queryEditor.value.editor.focus();
}
else
addNotification({ status: 'error', message: response });
@@ -739,7 +743,11 @@ const openFile = async () => {
const saveFileAs = async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result: any = await Application.showSaveDialog({ filters: [{ name: 'SQL', extensions: ['sql'] }], defaultPath: `${queryName.value || 'query'}.sql` });
const result: any = await Application.showSaveDialog({
filters: [{ name: 'SQL', extensions: ['sql'] }],
defaultPath: (queryName.value !== undefined && !queryName.value.includes('.sql') ? `${queryName.value}.sql` : queryName.value) || 'query.sql'
});
if (result && !result.canceled) {
await Application.writeFile(result.filePath, query.value);
addNotification({ status: 'success', message: t('general.actionSuccessful', { action: t('application.saveFile') }) });
@@ -750,9 +758,13 @@ const saveFileAs = async () => {
};
const saveFile = async () => {
await Application.writeFile(filePath.value, query.value);
addNotification({ status: 'success', message: t('general.actionSuccessful', { action: t('application.saveFile') }) });
lastSavedQuery.value = toRaw(query.value);
if (filePath.value) {
await Application.writeFile(filePath.value, query.value);
addNotification({ status: 'success', message: t('general.actionSuccessful', { action: t('application.saveFile') }) });
lastSavedQuery.value = toRaw(query.value);
}
else
saveFileAs();
};
const loadFileContent = async (file: string) => {
@@ -785,6 +797,67 @@ onMounted(() => {
if (props.tab.filePath)
loadFileContent(props.tab.filePath);
queryEditor.value.editor.container.addEventListener('contextmenu', (e) => {
const InputMenu = Menu.buildFromTemplate([
{
label: t('general.run'),
click: () => runQuery(query.value)
},
{
label: t('general.clear'),
click: () => clear()
},
{
type: 'separator'
},
{
label: t('application.saveFile'),
click: () => saveFile()
},
{
label: t('application.saveFileAs'),
click: () => saveFileAs()
},
{
label: t('application.openFile'),
click: () => openFile()
},
{
type: 'separator'
},
{
label: t('general.cut'),
role: 'cut'
},
{
label: t('general.copy'),
role: 'copy'
},
{
label: t('general.paste'),
role: 'paste'
},
{
type: 'separator'
},
{
label: t('general.selectAll'),
role: 'selectAll'
}
]);
e.preventDefault();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let node: any = e.target;
while (node) {
if (node.nodeName.match(/^(input|textarea)$/i) || node.isContentEditable) {
InputMenu.popup({ window: getCurrentWindow() });
break;
}
node = node.parentNode;
}
});
});
onBeforeUnmount(() => {

View File

@@ -7,7 +7,7 @@
:key="i"
class="mb-4"
>
{{ t(shortcutEvents[shortcut.event].l18n, {param: shortcutEvents[shortcut.event].l18nParam}) }}
{{ t(shortcutEvents[shortcut.event].i18n, {param: shortcutEvents[shortcut.event].i18nParam}) }}
</div>
</div>
<div class="column col-16">

View File

@@ -284,7 +284,7 @@ const settingsStore = useSettingsStore();
const consoleStore = useConsoleStore();
const { getWorkspace } = useWorkspacesStore();
const { dataTabLimit: pageSize, defaultCopyType } = storeToRefs(settingsStore);
const { /* dataTabLimit: pageSize, */ defaultCopyType } = storeToRefs(settingsStore);
const { consoleHeight } = storeToRefs(consoleStore);
@@ -357,28 +357,37 @@ const isSortable = computed(() => {
return fields.value.every(field => field.name);
});
const isHardSort = computed(() => {
return props.mode === 'table' && localResults.value.length === pageSize.value;
});
// const isHardSort = computed(() => {
// return props.mode === 'table' && localResults.value.length === pageSize.value;
// });
const sortedResults = computed(() => {
if (currentSort.value[resultsetIndex.value] && !isHardSort.value) {
const sortObj = currentSort.value[resultsetIndex.value];
// if (currentSort.value[resultsetIndex.value] && !isHardSort.value) {
// const sortObj = currentSort.value[resultsetIndex.value];
return [...localResults.value].sort((a: any, b: any) => {
let modifier = 1;
let valA = typeof a[sortObj.field] === 'string' ? a[sortObj.field].toLowerCase() : a[sortObj.field];
if (!isNaN(valA)) valA = Number(valA);
let valB = typeof b[sortObj.field] === 'string' ? b[sortObj.field].toLowerCase() : b[sortObj.field];
if (!isNaN(valB)) valB = Number(valB);
if (sortObj.dir === 'desc') modifier = -1;
if (valA < valB) return -1 * modifier;
if (valA > valB) return 1 * modifier;
return 0;
});
}
else
return localResults.value;
// return [...localResults.value].sort((a: any, b: any) => {
// const modifier = sortObj.dir === 'desc' ? -1 : 1;
// let valA = a[sortObj.field];
// let valB = b[sortObj.field];
// // Handle null values
// if (valA === null && valB !== null) return sortObj.dir === 'asc' ? -1 : 1;
// if (valA !== null && valB === null) return sortObj.dir === 'asc' ? 1 : -1;
// if (valA === null && valB === null) return 0;
// valA = typeof valA === 'string' ? valA.toLowerCase() : valA;
// valB = typeof valB === 'string' ? valB.toLowerCase() : valB;
// if (typeof valA !== 'number' && !isNaN(valA)) valA = String(Number(valA));
// if (typeof valB !== 'number' && !isNaN(valB)) valB = String(Number(valB));
// if (valA < valB) return -1 * modifier;
// if (valA > valB) return 1 * modifier;
// return 0;
// });
// }
// else
return localResults.value;
});
const resultsWithRows = computed(() => props.results.filter(result => result.rows.length));
@@ -529,6 +538,7 @@ const closeContext = () => {
};
const showDeleteConfirmModal = (e: any) => {
if (e && e.code !== 'Delete') return;
if (e && e.path && ['INPUT', 'TEXTAREA', 'SELECT'].includes(e.path[0].tagName))
return;
if (selectedRows.value.length === 0) return;
@@ -553,6 +563,7 @@ const deleteSelected = () => {
table: getTable(resultsetIndex.value),
rows
};
console.log(params);
emit('delete-selected', params);
};
@@ -686,15 +697,15 @@ const fillCell = (event: { name: string; group: string; type: string }) => {
}
fakeValue = (fakerCustom as any)[event.group][event.name]();
if (['string', 'number'].includes(typeof fakeValue)) {
const isDateType = [...DATE, ...DATETIME].includes(selectedCell.value.type);
if (isDateType)
fakeValue = moment(fakeValue).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
else if (['string', 'number'].includes(typeof fakeValue)) {
if (typeof fakeValue === 'number')
fakeValue = String(fakeValue);
if (selectedCell.value.length)
fakeValue = fakeValue.substring(0, selectedCell.value.length < 1024 ? Number(selectedCell.value.length) : 1024);
}
else if ([...DATE, ...DATETIME].includes(selectedCell.value.type))
fakeValue = moment(fakeValue).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
else if (TIME.includes(selectedCell.value.type))
fakeValue = moment(fakeValue).format(`HH:mm:ss${datePrecision}`);
@@ -818,12 +829,12 @@ const sort = (field: TableField) => {
};
}
if (isHardSort.value) {
emit('hard-sort', {
field: currentSort.value[resultsetIndex.value].field,
dir: currentSort.value[resultsetIndex.value].dir
});
}
// if (isHardSort.value) {
emit('hard-sort', {
field: currentSort.value[resultsetIndex.value].field,
dir: currentSort.value[resultsetIndex.value].dir
});
// }
};
const resetSort = () => {

View File

@@ -440,7 +440,7 @@ const editON = async (field: string) => {
return;
}
if (BLOB.includes(type)) {
if (BLOB.includes(type) && props.fields[field].key !== 'pri') {
isBlobEditor.value = true;
editingContent.value = content || '';
fileToUpload.value = null;
@@ -458,9 +458,12 @@ const editON = async (field: string) => {
};
}
}
emit('start-editing', field);
return;
}
else if (BLOB.includes(type) && props.fields[field].key === 'pri')// Disable edit on BLOB primary until we are sure it's not problematic
return;
// Inline editable fields
editingContent.value = originalContent.value;

View File

@@ -56,10 +56,10 @@ export function useResultTables (uid: string, reloadTable: () => void) {
if (status === 'success')
reloadTable();
else
this.addNotification({ status: 'error', message: response });
addNotification({ status: 'error', message: response });
}
catch (err) {
this.addNotification({ status: 'error', message: err.stack });
addNotification({ status: 'error', message: err.stack });
isQuering.value = false;
}
}

View File

@@ -141,7 +141,7 @@ export const csCZ = {
total: 'Celkem',
table: 'Tabulka | Tabulky',
view: 'Pohled | Pohledy',
materializedview: 'Materializovaný pohled',
materializedView: 'Materializovaný pohled',
definer: 'Definér',
algorithm: 'Algoritmus',
trigger: 'Trigger | Triggery',

View File

@@ -126,6 +126,7 @@ export const enUS = {
insert: 'Insert',
indexes: 'Indexes',
foreignKeys: 'Foreign keys',
tableChecks: 'Table checks',
length: 'Length',
unsigned: 'Unsigned',
default: 'Default',
@@ -140,7 +141,7 @@ export const enUS = {
total: 'Total',
table: 'Table | Tables',
view: 'View | Views',
materializedview: 'Materialized view | Materialized views',
materializedView: 'Materialized view | Materialized views',
definer: 'Definer',
algorithm: 'Algorithm',
trigger: 'Trigger | Triggers',
@@ -190,12 +191,15 @@ export const enUS = {
addNewField: 'Add new field',
manageIndexes: 'Manage indexes',
manageForeignKeys: 'Manage foreign keys',
manageTableChecks: 'Manage table checks',
allowNull: 'Allow NULL',
zeroFill: 'Zero fill',
customValue: 'Custom value',
onUpdate: 'On update',
deleteField: 'Delete field',
createNewIndex: 'Create new index',
createNewCheck: 'Create new check',
checkClause: 'Check clause',
addToIndex: 'Add to index',
createNewTable: 'Create new table',
emptyTable: 'Empty table',
@@ -205,6 +209,7 @@ export const enUS = {
emptyConfirm: 'Do you confirm to empty',
thereAreNoIndexes: 'There are no indexes',
thereAreNoForeign: 'There are no foreign keys',
thereAreNoTableChecks: 'There are no table checks',
createNewForeign: 'Create new foreign key',
referenceTable: 'Ref. table',
referenceField: 'Ref. field',
@@ -396,6 +401,7 @@ export const enUS = {
ignoreDuplicates: 'Ignore duplicates',
wrongImportPassword: 'Wrong import password',
wrongFileFormat: 'Wrong file format',
invalidFile: 'Invalid file',
dataImportSuccess: 'Data successfully imported',
note: 'Note | Notes',
thereAreNoNotesYet: 'There are no notes yet',
@@ -411,7 +417,11 @@ export const enUS = {
openNotes: 'Open notes',
debugConsole: 'Debug console', // <- console tab name
executedQueries: 'Executed queries', // <- console tab name
sizeLimitError: 'Maximum size of {size} exceeded'
sizeLimitError: 'Maximum size of {size} exceeded',
fullScreen: 'Full screen',
zoomIn: 'Zoom in',
zoomOut: 'Zoom out',
zoomReset: 'Reset zoom'
},
faker: { // Faker.js methods, used in random generated content
address: 'Address',

View File

@@ -1,5 +1,14 @@
/**
* [TRANSLATION UPDATE HELPER]
* - Open a terminal in antares folder and run `npm run translation:check short-code` replacing short-code with the one you are updating.
* - The command will output which terms are missing or not translated from english.
* - Open antares folder with your editor of choice.
* - Go to antares/src/renderer/i18n/ and open the locale file you want to translate.
* - Add and translate missing terms and consider whether to translate untranslated terms.
*/
export const esES = {
general: {
general: { // General purpose terms
edit: 'Editar',
save: 'Guardar',
close: 'Cerrar',
@@ -8,6 +17,7 @@ export const esES = {
cancel: 'Cancelar',
send: 'Enviar',
refresh: 'Refrescar',
autoRefresh: 'Auto refresco',
version: 'Versión',
donate: 'Donar',
run: 'Ejecutar',
@@ -18,12 +28,62 @@ export const esES = {
add: 'Añadir',
data: 'Datos',
properties: 'Propiedades',
name: 'Nombre',
clear: 'Limpiar',
options: 'Opciones',
insert: 'Insertar',
discard: 'Descartar',
stay: 'Mantener',
author: 'Autor',
upload: 'Subir',
browse: 'Navegar',
content: 'Contenido',
cut: 'Cortar',
copy: 'Copiar',
paste: 'Pegar',
duplicate: 'Duplicar',
tools: 'Herramientas',
seconds: 'Segundos',
deleteConfirm: 'Confirmas la cancelación de',
uploadFile: 'Cargar fichero'
all: 'Todos',
new: 'Nuevo',
select: 'Seleccionar',
change: 'Cambiar',
include: 'Agregar',
includes: 'Agregados',
completed: 'Completado',
aborted: 'Cancelado',
disabled: 'Deshabilitado',
enable: 'Habilitar',
disable: 'Desabilitar',
contributors: 'Colaboradores',
pin: 'Fijar',
unpin: 'Desfijar',
folder: 'Carpeta | Carpetas',
none: 'Ninguno',
singleQuote: 'Comillas simples',
doubleQuote: 'Comillas dobles',
deleteConfirm: 'Confirmar la cancelación de',
uploadFile: 'Cargar fichero',
format: 'Formato', // Format code
history: 'Histórico',
filter: 'Filtro',
manualValue: 'Valor manual',
selectAll: 'Seleccionar todo',
pageNumber: 'Número de página',
directoryPath: 'Ruta de directorio',
actionSuccessful: '{action} exitoso',
outputFormat: 'Formato de salida',
singleFile: 'Fichero {ext} único',
zipCompressedFile: 'Fichero ZIP {ext} comprimido',
copyName: 'Copiar nombre',
search: 'Búsqueda',
title: 'Título',
archive: 'Archivo', // verb
undo: 'Deshacer',
moveTo: 'Mover a'
},
connection: {
connection: { // Database connection
connection: 'Conexión',
connectionName: 'Nombre de la conexión',
client: 'Cliente',
hostName: 'Servidor',
@@ -35,6 +95,17 @@ export const esES = {
connected: 'Conectado',
disconnect: 'Desconectar',
disconnected: 'Desconectado',
ssl: 'SSL',
enableSsl: 'Habilitar SSL',
privateKey: 'Clave privada',
certificate: 'Certificado',
caCertificate: 'Certificado CA',
ciphers: 'Cifrado',
untrustedConnection: 'Conexión no confiable',
passphrase: 'Frase de paso',
sshTunnel: 'Túnel SSH',
enableSsh: 'Habilitar SSH',
connectionString: 'Cadena de conexión',
addConnection: 'Añadir conexión',
createConnection: 'Crear conexión',
createNewConnection: 'Crear nueva conexión',
@@ -42,26 +113,216 @@ export const esES = {
testConnection: 'Comprobar conexión',
editConnection: 'Editar conexión',
deleteConnection: 'Eliminar conexión',
connectionSuccessfullyMade: 'Conexión realizada correctamente!'
connectionSuccessfullyMade: 'Conexión realizada correctamente!',
readOnlyMode: 'Solo lectura',
allConnections: 'Todas las conexiones',
searchForConnections: 'Buscar por conexiones',
keepAliveInterval: 'Tiempo de mantenimiento de conexión',
singleConnection: 'Conexión única'
},
database: {
database: { // Database related terms
schema: 'Esquema',
type: 'Tipo',
unableEditFieldWithoutPrimary: 'No se puede editar una campo sin Llave Primaria en el registro',
editCell: 'Editar celda',
insert: 'Insertar',
indexes: 'Índices',
foreignKeys: 'Claves Foráneas',
tablaChecks: 'Validación de tabla',
length: 'Longitud',
unsigned: 'Sin signo',
default: 'Por defecto',
comment: 'Comentario',
key: 'Clave | Claves',
order: 'Orden',
expression: 'Expresión',
autoIncrement: 'Autoincremental',
engine: 'Motor',
field: 'Campo | Campos',
approximately: 'Aproximadamente',
total: 'Total',
table: 'Tabla | Tablas',
view: 'Vista | Vistas',
materializedView: 'Vista Materializada | Vistas Materializadas',
definer: 'Definidor',
algorithm: 'Algoritmo',
trigger: 'Disparador | Disparadores',
storedRoutine: 'Procedimiento almacenado | Procedimientos almacenados',
scheduler: 'Planificador | Planificadores',
event: 'Evento',
parameters: 'Parámetros',
function: 'Función | Funciones',
deterministic: 'Determinístico',
context: 'Contexto',
export: 'Exportar',
import: 'Importar',
returns: 'Retorno',
timing: 'Timing',
state: 'Estado',
execution: 'Ejecución',
starts: 'Inicio',
ends: 'Final',
variables: 'Variables',
processes: 'Procesos',
database: 'Base de Datos',
array: 'Tupla',
structure: 'Estructura',
row: 'Fila | Filas',
cell: 'Celda | Celdas',
triggerFunction: 'Función disparadora | Funciones disparadoras',
routine: 'Rutina | Rutinas',
drop: 'Abandonar',
commit: 'Commit',
rollback: 'Marcha atrás',
ddl: 'DDL',
collation: 'Colación',
resultsTable: 'Tabla de resultados',
unableEditFieldWithoutPrimary: 'No es posible modificar un campo sin una clave primaria en el set de resultados',
editCell: 'Modificar celda',
deleteRows: 'Eliminar fila | Eliminar {count} filas',
confirmToDeleteRows: '¿Quiere realmente eliminar una fila? | ¿Quiere realmente eliminar {count} filas?',
addNewRow: 'Añadir nueva fila',
numberOfInserts: 'Numero de inserciones',
affectedRows: 'Filas afectadas'
numberOfInserts: 'Número de inserciones',
affectedRows: 'Líneas afectadas',
createNewDatabase: 'Crear nueva Base de Datos',
databaseName: 'Nombre de Base de Datos',
serverDefault: 'Servidor por defecto',
deleteDatabase: 'Eliminar Base de Datos',
editDatabase: 'Modificar Base de Datos',
clearChanges: 'Deshacer cambios',
addNewField: 'Añadir nuevo campo',
manageIndexes: 'Administrar índices',
manageForeignKeys: 'Administrar claves foráneas',
manageTableChecks: 'Administrar validaciones de tabla',
allowNull: 'Permitir NULL',
zeroFill: 'Rellenar con ceros',
customValue: 'Valor predeterminado',
onUpdate: 'On UPDATE',
deleteField: 'Eliminar campo',
createNewIndex: 'Crear nuevo índice',
createNewCheck: 'Crear nueva verificación',
checkClause: 'Comprobar cláusula',
addToIndex: 'Añadir al índice',
createNewTable: 'Crear nueva tabla',
emptyTable: 'Tabla vacía',
duplicateTable: 'Duplicar tabla',
deleteTable: 'Eliminar tabla',
exportTable: 'Exportar tabla',
emptyConfirm: 'Confirmar vaciado',
thereAreNoIndexes: 'No hay índices',
thereAreNoForeign: 'No hay claves foráneas',
thereAreNoTableChecks: 'No hay validaciones de tabla',
createNewForeign: 'Crear nueva clave foránea',
referenceTable: 'Ref. tabla',
referenceField: 'Ref. campo',
foreignFields: 'Campos foráneos',
invalidDefault: 'Valor por defecto no válido',
onDelete: 'On DELETE',
selectStatement: 'Declaración SELECT',
triggerStatement: 'Declaración TRIGGER',
sqlSecurity: 'Seguridad SQL',
updateOption: 'Opción UPDATE',
deleteView: 'Eliminar vista',
createNewView: 'Crear nueva vista',
createNewMaterializedView: 'Crear nueva vista materializada',
deleteTrigger: 'Eliminar disparador',
createNewTrigger: 'Crear nuevo disparador',
currentUser: 'Usuario actual',
routineBody: 'Cuerpo de rutina',
dataAccess: 'Acceso a datos',
thereAreNoParameters: 'No hay parámetros',
createNewParameter: 'Crear nuevo parámetro',
createNewRoutine: 'Crear nuevo procedimiento almacenado',
deleteRoutine: 'Eliminar procedimiento almacenado',
functionBody: 'Cuerpo de función',
createNewFunction: 'Crear nueva función',
deleteFunction: 'Eliminar función',
schedulerBody: 'Cuerpo de planificador',
createNewScheduler: 'Crear nuevo planificador',
deleteScheduler: 'Eliminar planificador',
preserveOnCompletion: 'Mantener al finalizar',
tableFiller: 'Rellenador de tabla',
fakeDataLanguage: 'Lenguaje de datos dummy',
queryDuration: 'Duración de la consulta',
setNull: 'Establecer a NULL',
processesList: 'Lista de procesos',
processInfo: 'Información de proceso',
manageUsers: 'Administrar usuarios',
createNewSchema: 'Crear nuevo esquema',
schemaName: 'Nombre de esquema',
editSchema: 'Modificar esquema',
deleteSchema: 'Eliminar esquema',
noSchema: 'No hay esquemas',
runQuery: 'Ejecutar consulta',
thereAreNoTableFields: 'No hay campos en la tabla',
newTable: 'Nueva tabla',
newView: 'Nueva vista',
newMaterializedView: 'Nueva vista materializada',
newTrigger: 'Nuevo disparador',
newRoutine: 'Nueva rutina',
newFunction: 'Nueva función',
newScheduler: 'Nuevo planificador',
newTriggerFunction: 'Nueva función de disparador',
thereAreNoQueriesYet: 'No quedan mas consultas',
searchForQueries: 'Buscar consultas',
killProcess: 'Matar proceso',
exportSchema: 'Exportar esquema',
importSchema: 'Importar esquema',
newInsertStmtEvery: 'Nueva declaración INSERT',
processingTableExport: 'Procesando {table}',
fetchingTableExport: 'Obteniendo datos de {table}',
writingTableExport: 'Escribiendo datos de {table}',
checkAllTables: 'Verificar todas las tablas',
uncheckAllTables: 'Desmarcar todas las tablas',
killQuery: 'Matar consulta',
insertRow: 'Añadir fila | Añadir filas',
commitMode: 'Modo de Commit',
autoCommit: 'Automático',
manualCommit: 'Manual',
importQueryErrors: 'Atención: {n} de error encontrado | Atención: {n} errores encontrados',
executedQueries: '{n} consulta ejecutada | {n} consultas ejecutadas',
disableFKChecks: 'Deshabilitar comprobación de claves foráneas',
formatQuery: 'Formato de consulta',
queryHistory: 'Histórico de consultas',
clearQuery: 'Limpiar consulta',
fillCell: 'Rellenar celda',
executeSelectedQuery: 'Ejecutar consulta seleccionada',
noResultsPresent: 'No se obtuvieron resultados',
sqlExportOptions: 'Opciones de exportación de SQL',
targetTable: 'Tabla objetivo',
switchDatabase: 'Cambiar de Base de datos',
searchForElements: 'Buscar por elementos',
searchForSchemas: 'Buscar por esquemas',
savedQueries: 'Consultas almacenadas'
},
application: {
settings: 'Configuración',
console: 'Consola',
general: 'General',
themes: 'Temas',
update: 'Actualizar',
about: 'Sobre',
language: 'Idioma',
shortcuts: 'Atajos',
key: 'Tecla | Teclas', // Keyboard key
event: 'Evento',
light: 'Claro',
dark: 'Oscuro',
autoCompletion: 'Autocompletado',
application: 'Aplicación',
editor: 'Editor',
changelog: 'Histórico de cambios',
small: 'Pequeño',
medium: 'Mediano',
large: 'Grande',
appearance: 'Apariencia',
color: 'Color',
label: 'Etiqueta',
icon: 'Icono',
customIcon: 'Icono personalizado',
fileName: 'Nombre de fichero',
choseFile: 'Elegir fichero',
data: 'Datos',
password: 'Contraseña',
required: 'Requerido',
madeWithJS: 'Hecho con 💛 y JavaScript!',
checkForUpdates: 'Comprobar actualizaciones',
noUpdatesAvailable: 'No hay actualizaciones',
@@ -71,7 +332,255 @@ export const esES = {
downloadingUpdate: 'Descargando actualización',
updateDownloaded: 'Descargada actualización',
restartToInstall: 'Reiniciar Antares para instalar',
includeBetaUpdates: 'Incluir actualizaciones en fase beta',
notificationsTimeout: 'Tiempo de espera',
openNewTab: 'Abrir nueva pestaña'
openNewTab: 'Abrir nueva pestaña',
unsavedChanges: 'Cambios sin guardar',
discardUnsavedChanges: 'Tiene algunos cambios sin guardar. Al cerrar esta pestaña, serán descartados.',
applicationTheme: 'Tema de la Aplicación',
editorTheme: 'Editor de Tema',
wrapLongLines: 'Mantener lineas largas',
markdownSupported: 'Markdown soportado',
plantATree: 'Planta un arbol',
dataTabPageSize: 'Resultados por página',
noOpenTabs: 'No hay pestañas abiertas. Navega por la barra de la izquierda o:',
restorePreviousSession: 'Restablecer la sesión anterior',
closeTab: 'Cerrar pestaña',
goToDownloadPage: 'Ir a la página de descargas',
disableBlur: 'Deshabilitar opacidad',
missingOrIncompleteTranslation: '¿No hay traducción o hay algo incorrecto?',
findOutHowToContribute: 'Mira como puedes contribuir',
reportABug: 'Informar de un problema',
nextTab: 'Siguiente pestaña',
previousTab: 'Anterior pestaña',
selectTabNumber: 'Selecciona numero de pestaña {param}',
toggleConsole: 'Alternar vista de consola',
addShortcut: 'Añadir atajo',
editShortcut: 'Modificar atajo',
deleteShortcut: 'Eliminar atajo',
restoreDefaults: 'Restablecer valores por defecto',
restoreDefaultsQuestion: '¿Está seguro que quiere establecer los valores por defecto?',
registerAShortcut: 'Registrar un atajo',
invalidShortcutMessage: 'Combinación no válida, por favor intente otra',
shortcutAlreadyExists: 'El atajo ya existe',
saveContent: 'Guardar contenido',
openAllConnections: 'Abrir todas las conexiones',
openSettings: 'Abrir configuración',
runOrReload: 'Ejecutar o recargar',
openFilter: 'Abrir filtro',
nextResultsPage: 'Siguiente pagina de resultados',
previousResultsPage: 'Anterior página de resultados',
editFolder: 'Modificar carpeta',
folderName: 'Nombre de carpeta',
deleteFolder: 'Eliminar carpeta',
newFolder: 'Crear nueva carpeta',
outOfFolder: 'Fuera de la carpeta',
editConnectionAppearance: 'Modificar apariencia de conexión',
defaultCopyType: 'Default copy type',
showTableSize: 'Mostrar tamaño de tabla en la barra lateral',
showTableSizeDescription: 'Solo para MySQL/MariaDB. Habilitar esta opción puede afectar al rendimiento en esquemas con muchas tablas.',
switchSearchMethod: 'Switch search method',
phpArray: 'Array de PHP',
closeAllTabs: 'Cerrar todas las pestañas',
closeOtherTabs: 'Cerrar las otras pestañas',
closeTabsToLeft: 'Cerrar las pestañas a la izquierda',
closeTabsToRight: 'Cerrar las pestañas a la derecha',
csvFieldDelimiter: 'Delimitador de campos',
csvLinesTerminator: 'Terminador de líneas',
csvStringDelimiter: 'Delimitador de cadenas',
csvIncludeHeader: 'Incluir cabecera',
csvExportOptions: 'Opciones de exportación de CSV',
exportData: 'Exportar datos',
exportDataExplanation: 'Exportar conexiones guardadas en Antares. Se le preguntará por una contraseña para encriptar el fichero exportado.',
importData: 'Importar datos',
importDataExplanation: 'Importará un fichero con extensión .antares que contiene conexiones. Necesitará la contraseña con la que se encriptó el mismo.',
includeConnectionPasswords: 'Incluir contraseñas de conexión',
includeFolders: 'Incluir carpetas',
encryptionPassword: 'Encryption password',
encryptionPasswordError: 'The encryption password must be at least 8 characters long.',
ignoreDuplicates: 'Ignore duplicates',
wrongImportPassword: 'Wrong import password',
wrongFileFormat: 'Wrong file format',
dataImportSuccess: 'Data successfully imported',
note: 'Note | Notes',
thereAreNoNotesYet: 'There are no notes yet',
addNote: 'Add note',
editNote: 'Edit note',
saveAsNote: 'Save as note',
showArchivedNotes: 'Show archived notes',
hideArchivedNotes: 'Hide archived notes',
tag: 'Tag', // Note tag,
saveFile: 'Save file',
saveFileAs: 'Save file as',
openFile: 'Open file',
openNotes: 'Open notes',
debugConsole: 'Debug console', // <- console tab name
executedQueries: 'Executed queries', // <- console tab name
sizeLimitError: 'Maximum size of {size} exceeded'
},
faker: { // Faker.js methods, used in random generated content
address: 'Dirección',
commerce: 'Comercio',
company: 'Compañía',
database: 'Base de datos',
date: 'Fecha',
finance: 'Finanzas',
git: 'Git',
hacker: 'Hacker',
internet: 'Internet',
lorem: 'Lorem',
name: 'Nombre',
music: 'Música',
phone: 'Teléfono',
random: 'Aleatorio',
system: 'Sistema',
time: 'Hora',
vehicle: 'Vehículo',
zipCode: 'Código Postal',
zipCodeByState: 'Código Postal por Estado',
city: 'Ciudad',
cityPrefix: 'Prefijo de ciudad',
citySuffix: 'Sufijo de ciudad',
streetName: 'Nombre de calle',
streetAddress: 'Dirección',
streetSuffix: 'Sufijo de calle',
streetPrefix: 'Prefijo de calle',
secondaryAddress: 'Dirección secundaria',
county: 'Condado',
country: 'País',
countryCode: 'Código de país',
state: 'Estado',
stateAbbr: 'Abreviatura de Estado',
latitude: 'Latitud',
longitude: 'Longitud',
direction: 'Dirección',
cardinalDirection: 'Dirección cardinal',
ordinalDirection: 'Dirección ordinal',
nearbyGPSCoordinate: 'Coordenadas GPS',
timeZone: 'Zona horaria',
color: 'Color',
department: 'Departmento',
productName: 'Nombre de producto',
price: 'Precio',
productAdjective: 'Adjetivo de producto',
productMaterial: 'Material de producto',
product: 'Producto',
productDescription: 'Descripción de producto',
suffixes: 'Sufijos',
companyName: 'Nombre de compañía',
companySuffix: 'Sufijo de compañía',
catchPhrase: 'Catch phrase',
bs: 'BS',
catchPhraseAdjective: 'Catch phrase adjective',
catchPhraseDescriptor: 'Catch phrase descriptor',
catchPhraseNoun: 'Catch phrase noun',
bsAdjective: 'BS adjective',
bsBuzz: 'BS buzz',
bsNoun: 'BS noun',
column: 'Columna',
type: 'Tipo',
collation: 'Colación',
engine: 'Motor',
past: 'Pasado',
now: 'Ahora',
future: 'Futuro',
between: 'Entre',
recent: 'Reciente',
soon: 'Pronto',
month: 'Mes',
weekday: 'Día de la semana',
account: 'Cuenta',
accountName: 'Nombre de cuenta',
routingNumber: 'Número de enrutamiento',
mask: 'Máscara',
amount: 'Cantidad',
transactionType: 'Tipo de transacción',
currencyCode: 'Código de Moneda',
currencyName: 'Nombre de Moneda',
currencySymbol: 'Símbolo de Moneda',
bitcoinAddress: 'Dirección Bitcoin',
litecoinAddress: 'Dirección Litecoin',
creditCardNumber: 'Número de tarjeta',
creditCardCVV: 'CVV',
ethereumAddress: 'Dirección Ethereum',
iban: 'IBAN',
bic: 'BIC',
transactionDescription: 'Descripción de transacción',
branch: 'Rama',
commitEntry: 'Entrada de Commit',
commitMessage: 'Mensaje de Commit',
commitSha: 'SHA de Commit',
shortSha: 'SHA corto',
abbreviation: 'Abreviatura',
adjective: 'Adjetivo',
noun: 'Sustantivo',
verb: 'Verbo',
ingverb: 'Adverbio',
phrase: 'Frase',
avatar: 'Avatar',
email: 'Email',
exampleEmail: 'Email de ejemplo',
userName: 'Nombre de usuario',
protocol: 'Protocolo',
url: 'URL',
domainName: 'Dominio',
domainSuffix: 'Prefijo de dominio',
domainWord: 'Palabra de dominio',
ip: 'IP',
ipv6: 'IPv6',
userAgent: 'Agente de Usuario',
mac: 'MAC',
password: 'Contraseña',
word: 'Palabra',
words: 'Palabras',
sentence: 'Sentencia',
slug: 'Slug',
sentences: 'Sentencias',
paragraph: 'Frase',
paragraphs: 'Frases',
text: 'Texto',
lines: 'Lineas',
genre: 'Género',
firstName: 'Nombre',
lastName: 'Apellido',
middleName: 'Apellido',
findName: 'Nombre completo',
jobTitle: 'Ocupación',
gender: 'Género',
prefix: 'Prefijo',
suffix: 'Sufijo',
title: 'Título',
jobDescriptor: 'Descripción de trabajo',
jobArea: 'Area de trabajo',
jobType: 'Tipo de trabajo',
phoneNumber: 'Número de teléfono',
phoneNumberFormat: 'Formato de número de teléfono',
phoneFormats: 'Formatos de teléfono',
number: 'Número',
float: 'Decimal',
arrayElement: 'Elemento Array',
arrayElements: 'Elementos de Array',
objectElement: 'Elemento Objeto',
uuid: 'UUID',
boolean: 'Booleano',
image: 'Imagen',
locale: 'Conf. regional',
alpha: 'Alpha',
alphaNumeric: 'Alfanumérico',
hexaDecimal: 'Hexadecimal',
fileName: 'Nombre de fichero',
commonFileName: 'Common file name',
mimeType: 'Mime-Type',
commonFileType: 'Common file type',
commonFileExt: 'Common file extension',
fileType: 'Tipo de fichero',
fileExt: 'Extension de fichero',
directoryPath: 'Ruta de directorio',
filePath: 'Ruta de fichero',
semver: 'SemVer',
manufacturer: 'Fabricante',
model: 'Modelo',
fuel: 'Combustible',
vin: 'VIN'
}
};

582
src/renderer/i18n/he-IL.ts Normal file
View File

@@ -0,0 +1,582 @@
/**
* [TRANSLATION UPDATE HELPER]
* - Open a terminal in antares folder and run `npm run translation:check short-code` replacing short-code with the one you are updating.
* - The command will output which terms are missing or not translated from english.
* - Open antares folder with your editor of choice.
* - Go to antares/src/renderer/i18n/ and open the locale file you want to translate.
* - Add and translate missing terms and consider whether to translate untranslated terms.
*/
export const heIL = {
general: { // General purpose terms
edit: 'עריכה',
save: 'שמירה',
close: 'סגירה',
delete: 'מחיקה',
confirm: 'אישור',
cancel: 'ביטול',
send: 'שליחה',
refresh: 'רענון',
autoRefresh: 'רענון אוטומטי',
version: 'גרסה',
donate: 'תרומה',
run: 'הרצה',
results: 'תוצאות',
size: 'גודל',
mimeType: 'סוג MIME',
download: 'הורדה',
add: 'הוספה',
data: 'נתונים',
properties: 'מאפיינים',
name: 'שם',
clear: 'ניקוי',
options: 'אפשרויות',
insert: 'הכנסה',
discard: 'ביטול',
stay: 'הישאר',
author: 'מחבר',
upload: 'העלאה',
browse: 'עיון',
content: 'תוכן',
cut: 'גזירה',
copy: 'העתקה',
paste: 'הדבקה',
duplicate: 'שכפול',
tools: 'כלים',
seconds: 'שניות',
all: 'הכל',
new: 'חדש',
select: 'בחירה',
change: 'שינוי',
include: 'כלול',
includes: 'כולל',
completed: 'הושלם',
aborted: 'בוטל',
disabled: 'מושבת',
enable: 'הפעל',
disable: 'השבת',
contributors: 'תורמים',
pin: 'נעץ',
unpin: 'בטל נעיצה',
folder: 'תיקייה | תיקיות',
none: 'אין',
singleQuote: 'מרכאה בודדת',
doubleQuote: 'מרכאות כפולות',
deleteConfirm: 'האם אתה מאשר את הביטול של',
uploadFile: 'העלאת קובץ',
format: 'פורמט', // Format code
history: 'היסטוריה',
filter: 'סינון',
manualValue: 'ערך ידני',
selectAll: 'בחר הכל',
pageNumber: 'מספר עמוד',
directoryPath: 'נתיב תיקייה',
actionSuccessful: '{action} בוצעה בהצלחה',
outputFormat: 'פורמט פלט',
singleFile: 'קובץ {ext} בודד',
zipCompressedFile: 'קובץ {ext} דחוס ב-ZIP',
copyName: 'העתק שם',
search: 'חיפוש',
title: 'כותרת',
archive: 'ארכיון', // verb
undo: 'ביטול פעולה',
moveTo: 'העבר אל'
},
connection: { // Database connection
connection: 'חיבור',
connectionName: 'שם החיבור',
hostName: 'שם המארח',
client: 'לקוח',
port: 'פורט',
user: 'משתמש',
password: 'סיסמה',
credentials: 'אישורים',
connect: 'התחבר',
connected: 'מחובר',
disconnect: 'התנתק',
disconnected: 'מנותק',
ssl: 'SSL',
enableSsl: 'הפעל SSL',
privateKey: 'מפתח פרטי',
certificate: 'תעודה',
caCertificate: 'תעודת CA',
ciphers: 'צפנים',
untrustedConnection: 'חיבור לא מהימן',
passphrase: 'ביטוי סיסמה',
sshTunnel: 'מנהרת SSH',
enableSsh: 'הפעל SSH',
connectionString: 'מחרוזת חיבור',
addConnection: 'הוסף חיבור',
createConnection: 'צור חיבור',
createNewConnection: 'צור חיבור חדש',
askCredentials: 'בקש אישורים',
testConnection: 'בדוק חיבור',
editConnection: 'ערוך חיבור',
deleteConnection: 'מחק חיבור',
connectionSuccessfullyMade: 'החיבור בוצע בהצלחה!',
readOnlyMode: 'מצב קריאה בלבד',
allConnections: 'כל החיבורים',
searchForConnections: 'חפש חיבורים',
keepAliveInterval: 'מרווח שמירת חיבור',
singleConnection: 'חיבור בודד'
},
database: { // Database related terms
schema: 'סכימה',
type: 'סוג',
insert: 'הכנס',
indexes: 'אינדקסים',
foreignKeys: 'מפתחות זרים',
length: 'אורך',
unsigned: 'ללא סימן',
default: 'ברירת מחדל',
comment: 'הערה',
key: 'מפתח | מפתחות',
order: 'סדר',
expression: 'ביטוי',
autoIncrement: 'מספור אוטומטי',
engine: 'מנוע',
field: 'שדה | שדות',
approximately: 'בקירוב',
total: 'סך הכל',
table: 'טבלה | טבלאות',
view: 'תצוגה | תצוגות',
materializedView: 'תצוגה ממומשת | תצוגות ממומשות',
definer: 'מגדיר',
algorithm: 'אלגוריתם',
trigger: 'טריגר | טריגרים',
storedRoutine: 'שגרה שמורה | שגרות שמורות',
scheduler: 'מתזמן | מתזמנים',
event: 'אירוע',
parameters: 'פרמטרים',
function: 'פונקציה | פונקציות',
deterministic: 'דטרמיניסטי',
context: 'הקשר',
export: 'ייצוא',
import: 'ייבוא',
returns: 'מחזיר',
timing: 'תזמון',
state: 'מצב',
execution: 'ביצוע',
starts: 'מתחיל',
ends: 'מסתיים',
variables: 'משתנים',
processes: 'תהליכים',
database: 'מסד נתונים',
array: 'מערך',
structure: 'מבנה',
row: 'שורה | שורות',
cell: 'תא | תאים',
triggerFunction: 'פונקציית טריגר | פונקציות טריגר',
routine: 'שגרה | שגרות',
drop: 'הסר',
commit: 'בצע',
rollback: 'שחזר',
ddl: 'DDL',
collation: 'אוסף',
resultsTable: 'טבלת תוצאות',
unableEditFieldWithoutPrimary: 'לא ניתן לערוך שדה ללא מפתח ראשי בתוצאות',
editCell: 'ערוך תא',
deleteRows: 'מחק שורה | מחק {count} שורות',
confirmToDeleteRows: 'האם אתה מאשר למחוק שורה אחת? | האם אתה מאשר למחוק {count} שורות?',
addNewRow: 'הוסף שורה חדשה',
numberOfInserts: 'מספר הכנסות',
affectedRows: 'שורות מושפעות',
createNewDatabase: 'צור מסד נתונים חדש',
databaseName: 'שם מסד הנתונים',
serverDefault: 'ברירת מחדל של השרת',
deleteDatabase: 'מחק מסד נתונים',
editDatabase: 'ערוך מסד נתונים',
clearChanges: 'נקה שינויים',
addNewField: 'הוסף שדה חדש',
manageIndexes: 'נהל אינדקסים',
manageForeignKeys: 'נהל מפתחות זרים',
allowNull: 'אפשר NULL',
zeroFill: 'מילוי אפסים',
customValue: 'ערך מותאם אישית',
onUpdate: 'בעת עדכון',
deleteField: 'מחק שדה',
createNewIndex: 'צור אינדקס חדש',
addToIndex: 'הוסף לאינדקס',
createNewTable: 'צור טבלה חדשה',
emptyTable: 'רוקן טבלה',
duplicateTable: 'שכפל טבלה',
deleteTable: 'מחק טבלה',
exportTable: 'ייצא טבלה',
emptyConfirm: 'האם אתה מאשר לרוקן',
thereAreNoIndexes: 'אין אינדקסים',
thereAreNoForeign: 'אין מפתחות זרים',
createNewForeign: 'צור מפתח זר חדש',
referenceTable: 'טבלת התייחסות',
referenceField: 'שדה התייחסות',
foreignFields: 'שדות זרים',
invalidDefault: 'ברירת מחדל לא חוקית',
onDelete: 'בעת מחיקה',
selectStatement: 'הצהרת SELECT',
triggerStatement: 'הצהרת טריגר',
sqlSecurity: 'אבטחת SQL',
updateOption: 'אפשרות עדכון',
deleteView: 'מחק תצוגה',
createNewView: 'צור תצוגה חדשה',
createNewMaterializedView: 'צור תצוגה ממומשת חדשה',
deleteTrigger: 'מחק טריגר',
createNewTrigger: 'צור טריגר חדש',
currentUser: 'משתמש נוכחי',
routineBody: 'גוף השגרה',
dataAccess: 'גישה לנתונים',
thereAreNoParameters: 'אין פרמטרים',
createNewParameter: 'צור פרמטר חדש',
createNewRoutine: 'צור שגרה שמורה חדשה',
deleteRoutine: 'מחק שגרה שמורה',
functionBody: 'גוף הפונקציה',
createNewFunction: 'צור פונקציה חדשה',
deleteFunction: 'מחק פונקציה',
schedulerBody: 'גוף המתזמן',
createNewScheduler: 'צור מתזמן חדש',
deleteScheduler: 'מחק מתזמן',
preserveOnCompletion: 'שמור בסיום',
tableFiller: 'ממלא טבלאות',
fakeDataLanguage: 'שפת נתונים מזויפים',
queryDuration: 'משך השאילתה',
setNull: 'הגדר NULL',
processesList: 'רשימת תהליכים',
processInfo: 'מידע על תהליך',
manageUsers: 'נהל משתמשים',
createNewSchema: 'צור סכימה חדשה',
schemaName: 'שם הסכימה',
editSchema: 'ערוך סכימה',
deleteSchema: 'מחק סכימה',
noSchema: 'אין סכימה',
runQuery: 'הרץ שאילתה',
thereAreNoTableFields: 'אין שדות בטבלה',
newTable: 'טבלה חדשה',
newView: 'תצוגה חדשה',
newMaterializedView: 'תצוגה ממומשת חדשה',
newTrigger: 'טריגר חדש',
newRoutine: 'שגרה חדשה',
newFunction: 'פונקציה חדשה',
newScheduler: 'מתזמן חדש',
newTriggerFunction: 'פונקציית טריגר חדשה',
thereAreNoQueriesYet: 'אין עדיין שאילתות',
searchForQueries: 'חפש שאילתות',
killProcess: 'סיים תהליך',
exportSchema: 'ייצא סכ',
importSchema: 'ייבא סכימה',
newInsertStmtEvery: 'הצהרת INSERT חדשה כל',
processingTableExport: 'מעבד {table}',
fetchingTableExport: 'מביא נתוני {table}',
writingTableExport: 'כותב נתוני {table}',
checkAllTables: 'סמן את כל הטבלאות',
uncheckAllTables: 'בטל סימון כל הטבלאות',
killQuery: 'הרוג שאילתה',
insertRow: 'הכנס שורה | הכנס שורות',
commitMode: 'מצב ביצוע',
autoCommit: 'ביצוע אוטומטי',
manualCommit: 'ביצוע ידני',
importQueryErrors: 'אזהרה: אירעה {n} שגיאה | אזהרה: אירעו {n} שגיאות',
executedQueries: 'בוצעה {n} שאילתה | בוצעו {n} שאילתות',
disableFKChecks: 'בטל בדיקות מפתח זר',
formatQuery: 'עצב שאילתה',
queryHistory: 'היסטוריית שאילתות',
clearQuery: 'נקה שאילתה',
fillCell: 'מלא תא',
executeSelectedQuery: 'בצע שאילתה נבחרת',
noResultsPresent: 'אין תוצאות',
sqlExportOptions: 'אפשרויות ייצוא SQL',
targetTable: 'טבלת יעד',
switchDatabase: 'החלף מסד נתונים',
searchForElements: 'חפש אלמנטים',
searchForSchemas: 'חפש סכימות',
savedQueries: 'שאילתות שמורות'
},
application: { // Application related terms
settings: 'הגדרות',
console: 'קונסולה',
general: 'כללי',
themes: 'ערכות נושא',
update: 'עדכון',
about: 'אודות',
language: 'שפה',
shortcuts: 'קיצורי דרך',
key: 'מקש | מקשים', // Keyboard key
event: 'אירוע',
light: 'בהיר',
dark: 'כהה',
autoCompletion: 'השלמה אוטומטית',
application: 'יישום',
editor: 'עורך',
changelog: 'יומן שינויים',
small: 'קטן',
medium: 'בינוני',
large: 'גדול',
appearance: 'מראה',
color: 'צבע',
label: 'תווית',
icon: 'סמל',
customIcon: 'סמל מותאם אישית',
fileName: 'שם קובץ',
choseFile: 'בחר קובץ',
data: 'נתונים',
password: 'סיסמה',
required: 'נדרש',
madeWithJS: 'נוצר עם 💛 ו-JavaScript!',
checkForUpdates: 'בדוק עדכונים',
noUpdatesAvailable: 'אין עדכונים זמינים',
checkingForUpdate: 'בודק עדכונים',
checkFailure: 'הבדיקה נכשלה, נסה שוב מאוחר יותר',
updateAvailable: 'עדכון זמין',
downloadingUpdate: 'מוריד עדכון',
updateDownloaded: 'העדכון הורד',
restartToInstall: 'הפעל מחדש את Antares כדי להתקין',
includeBetaUpdates: 'כלול עדכוני בטא',
notificationsTimeout: 'זמן התראות',
openNewTab: 'פתח כרטיסייה חדשה',
unsavedChanges: 'שינויים שלא נשמרו',
discardUnsavedChanges: 'יש לך שינויים שלא נשמרו. סגירת כרטיסייה זו תגרום לאובדן השינויים.',
applicationTheme: 'ערכת נושא ליישום',
editorTheme: 'ערכת נושא לעורך',
wrapLongLines: 'גלישת שורות ארוכות',
markdownSupported: 'תמיכה ב-Markdown',
plantATree: 'נטע עץ',
dataTabPageSize: 'תוצאות לעמוד',
noOpenTabs: 'אין כרטיסיות פתוחות, נווט בסרגל השמאלי או:',
restorePreviousSession: 'שחזר הפעלה קודמת',
closeTab: 'סגור כרטיסייה',
goToDownloadPage: 'עבור לדף ההורדה',
disableBlur: 'בטל טשטוש',
missingOrIncompleteTranslation: 'תרגום חסר או לא שלם?',
findOutHowToContribute: 'גלה כיצד לתרום',
reportABug: 'דווח על באג',
nextTab: 'כרטיסייה הבאה',
previousTab: 'כרטיסייה קודמת',
selectTabNumber: 'בחר כרטיסייה מספר {param}',
toggleConsole: 'הצג/הסתר קונסולה',
addShortcut: 'הוסף קיצור דרך',
editShortcut: 'ערוך קיצור דרך',
deleteShortcut: 'מחק קיצור דרך',
restoreDefaults: 'שחזר ברירות מחדל',
restoreDefaultsQuestion: 'האם אתה מאשר לשחזר את ערכי ברירת המחדל?',
registerAShortcut: 'רשום קיצור דרך',
invalidShortcutMessage: 'שילוב לא חוקי, המשך להקליד',
shortcutAlreadyExists: 'קיצור הדרך כבר קיים',
saveContent: 'שמור תוכן',
openAllConnections: 'פתח את כל החיבורים',
openSettings: 'פתח הגדרות',
runOrReload: 'הרץ או טען מחדש',
openFilter: 'פתח מסנן',
nextResultsPage: 'עמוד תוצאות הבא',
previousResultsPage: 'עמוד תוצאות קודם',
editFolder: 'ערוך תיקייה',
folderName: 'שם תיקייה',
deleteFolder: 'מחק תיקייה',
newFolder: 'תיקייה חדשה',
outOfFolder: 'מחוץ לתיקייה',
editConnectionAppearance: 'ערוך מראה חיבור',
defaultCopyType: 'סוג העתקה ברירת מחדל',
showTableSize: 'הצג גודל טבלה בסרגל הצד',
showTableSizeDescription: 'MySQL/MariaDB בלבד. הפעלת אפשרות זו עלולה להשפיע על הביצועים בסכימה עם טבלאות רבות.',
switchSearchMethod: 'החלף שיטת חיפוש',
phpArray: 'מערך PHP',
closeAllTabs: 'סגור את כל הכרטיסיות',
closeOtherTabs: 'סגור כרטיסיות אחרות',
closeTabsToLeft: 'סגור כרטיסיות משמאל',
closeTabsToRight: 'סגור כרטיסיות מימין',
csvFieldDelimiter: 'מפריד שדות',
csvLinesTerminator: 'מסיים שורות',
csvStringDelimiter: 'מפריד מחרוזות',
csvIncludeHeader: 'כלול כותרת',
csvExportOptions: 'אפשרויות ייצוא CSV',
exportData: 'ייצא נתונים',
exportDataExplanation: 'ייצא חיבורים שמורים ל-Antares. תתבקש להזין סיסמה להצפנת הקובץ המיוצא.',
importData: 'ייבא נתונים',
importDataExplanation: 'מייבא קובץ .antares המכיל חיבורים. תצטרך להזין את הסיסמה שהוגדרה בזמן הייצוא.',
includeConnectionPasswords: 'כלול סיסמאות חיבור',
includeFolders: 'כלול תיקיות',
encryptionPassword: 'סיסמת הצפנה',
encryptionPasswordError: 'סיסמת ההצפנה חייבת להיות באורך של 8 תווים לפחות.',
ignoreDuplicates: 'התעלם מכפילויות',
wrongImportPassword: 'סיסמת ייבוא שגויה',
wrongFileFormat: 'פורמט קובץ שגוי',
dataImportSuccess: 'הנתונים יובאו בהצלחה',
note: 'הערה | הערות',
thereAreNoNotesYet: 'אין עדיין הערות',
addNote: 'הוסף הערה',
editNote: 'ערוך הערה',
saveAsNote: 'שמור כהערה',
showArchivedNotes: 'הצג הערות בארכיון',
hideArchivedNotes: 'הסתר הערות בארכיון',
tag: 'תג', // Note tag
saveFile: 'שמור קובץ',
saveFileAs: 'שמור קובץ בשם',
openFile: 'פתח קובץ',
openNotes: 'פתח הערות',
debugConsole: 'קונסולת ניפוי', // <- console tab name
executedQueries: 'שאילתות שבוצעו', // <- console tab name
sizeLimitError: 'חריגה מהגודל המקסימלי של {size}'
},
faker: { // Faker.js methods, used in random generated content
address: 'כתובת',
commerce: 'מסחר',
company: 'חברה',
database: 'מסד נתונים',
date: 'תאריך',
finance: 'פיננסים',
git: 'Git',
hacker: 'האקר',
internet: 'אינטרנט',
lorem: 'לורם',
name: 'שם',
music: 'מוזיקה',
phone: 'טלפון',
random: 'אקראי',
system: 'מערכת',
time: 'זמן',
vehicle: 'רכב',
zipCode: 'מיקוד',
zipCodeByState: 'מיקוד לפי מדינה',
city: 'עיר',
cityPrefix: 'קידומת עיר',
citySuffix: 'סיומת עיר',
streetName: 'שם רחוב',
streetAddress: 'כתובת רחוב',
streetSuffix: 'סיומת רחוב',
streetPrefix: 'קידומת רחוב',
secondaryAddress: 'כתובת משנית',
county: 'מחוז',
country: 'מדינה',
countryCode: 'קוד מדינה',
state: 'מדינה',
stateAbbr: 'קיצור מדינה',
latitude: 'קו רוחב',
longitude: 'קו אורך',
direction: 'כיוון',
cardinalDirection: 'כיוון קרדינלי',
ordinalDirection: 'כיוון אורדינלי',
nearbyGPSCoordinate: 'קואורדינטת GPS קרובה',
timeZone: 'אזור זמן',
color: 'צבע',
department: 'מחלקה',
productName: 'שם מוצר',
price: 'מחיר',
productAdjective: 'תואר מוצר',
productMaterial: 'חומר מוצר',
product: 'מוצר',
productDescription: 'תיאור מוצר',
suffixes: 'סיומות',
companyName: 'שם חברה',
companySuffix: 'סיומת חברה',
catchPhrase: 'סיסמה',
bs: 'BS',
catchPhraseAdjective: 'תואר סיסמה',
catchPhraseDescriptor: 'מתאר סיסמה',
catchPhraseNoun: 'שם עצם סיסמה',
bsAdjective: 'תואר BS',
bsBuzz: 'באז BS',
bsNoun: 'שם עצם BS',
column: 'עמודה',
type: 'סוג',
collation: 'קולציה',
engine: 'מנוע',
past: 'עבר',
now: 'עכשיו',
future: 'עתיד',
between: 'בין',
recent: 'לאחרונה',
soon: 'בקרוב',
month: 'חודש',
weekday: 'יום בשבוע',
account: 'חשבון',
accountName: 'שם החשבון',
routingNumber: 'מספר ניתוב',
mask: 'מסכה',
amount: 'סכום',
transactionType: 'סוג העסקה',
currencyCode: 'קוד מטבע',
currencyName: 'שם המטבע',
currencySymbol: 'סמל המטבע',
bitcoinAddress: 'כתובת ביטקוין',
litecoinAddress: 'כתובת לייטקוין',
creditCardNumber: 'מספר כרטיס אשראי',
creditCardCVV: 'CVV של כרטיס אשראי',
ethereumAddress: 'כתובת אתריום',
iban: 'איבן',
bic: 'BIC',
transactionDescription: 'תיאור העסקה',
branch: 'סניף',
commitEntry: 'ערך קומיט',
commitMessage: 'הודעת קומיט',
commitSha: 'SHA של קומיט',
shortSha: 'SHA קצר',
abbreviation: 'קיצור',
adjective: 'שם תואר',
noun: 'שם עצם',
verb: 'פועל',
ingverb: 'פועל בצורת -ing',
phrase: 'ביטוי',
avatar: 'אווטאר',
email: 'אימייל',
exampleEmail: 'דוגמת אימייל',
userName: 'שם משתמש',
protocol: 'פרוטוקול',
url: 'כתובת URL',
domainName: 'שם דומיין',
domainSuffix: 'סיומת דומיין',
domainWord: 'מילת דומיין',
ip: 'IP',
ipv6: 'IPv6',
userAgent: 'User Agent',
mac: 'כתובת MAC',
password: 'סיסמה',
word: 'מילה',
words: 'מילים',
sentence: 'משפט',
slug: 'סלאג',
sentences: 'משפטים',
paragraph: 'פסקה',
paragraphs: 'פסקאות',
text: 'טקסט',
lines: 'שורות',
genre: 'ז\'אנר',
firstName: 'שם פרטי',
lastName: 'שם משפחה',
middleName: 'שם אמצעי',
findName: 'שם מלא',
jobTitle: 'תפקיד',
gender: 'מין',
prefix: 'תחילית',
suffix: 'סיומת',
title: 'כותרת',
jobDescriptor: 'תיאור תפקיד',
jobArea: 'תחום תפקיד',
jobType: 'סוג תפקיד',
phoneNumber: 'מספר טלפון',
phoneNumberFormat: 'פורמט מספר טלפון',
phoneFormats: 'פורמטים של מספר טלפון',
number: 'מספר',
float: 'מספר עשרוני',
arrayElement: 'אלמנט במערך',
arrayElements: 'אלמנטים במערך',
objectElement: 'אלמנט באובייקט',
uuid: 'UUID',
boolean: 'בוליאני',
image: 'תמונה',
locale: 'לוקאל',
alpha: 'אלפא',
alphaNumeric: 'אלפאנומרי',
hexaDecimal: 'הקסדצימלי',
fileName: 'שם קובץ',
commonFileName: 'שם קובץ נפוץ',
mimeType: 'סוג MIME',
commonFileType: 'סוג קובץ נפוץ',
commonFileExt: 'סיומת קובץ נפוצה',
fileType: 'סוג קובץ',
fileExt: 'סיומת קובץ',
directoryPath: 'נתיב תיקייה',
filePath: 'נתיב קובץ',
semver: 'גרסת Semver',
manufacturer: 'יצרן',
model: 'דגם',
fuel: 'דלק',
vin: 'מספר רכב (VIN)'
}
};

View File

@@ -7,6 +7,7 @@ import { deDE } from './de-DE';
import { enUS } from './en-US';
import { esES } from './es-ES';
import { frFR } from './fr-FR';
import { heIL } from './he-IL';
import { idID } from './id-ID';
import { itIT } from './it-IT';
import { jaJP } from './ja-JP';
@@ -15,6 +16,7 @@ import { nlNL } from './nl-NL';
import { ptBR } from './pt-BR';
import { ruRU } from './ru-RU';
import { ukUA } from './uk-UA';
import { uzUZ } from './uz-UZ';
import { viVN } from './vi-VN';
import { zhCN } from './zh-CN';
import { zhTW } from './zh-TW';
@@ -37,7 +39,9 @@ const messages = {
'ca-ES': caES,
'cs-CZ': csCZ,
'uk-UA': ukUA,
'zh-TW': zhTW
'zh-TW': zhTW,
'he-IL': heIL,
'uz-UZ': uzUZ
};
type NestedPartial<T> = {

View File

@@ -275,7 +275,7 @@ export const nlNL = {
savedQueries: 'Opgeslagen queries',
searchForElements: 'Zoek naar elementen',
searchForSchemas: 'Zoek naar schema\'s',
materializedview: 'Materialized view | Materialized views',
materializedView: 'Materialized view | Materialized views',
createNewMaterializedView: 'Materialized view maken',
newMaterializedView: 'Nieuwe materialized view'
},

View File

@@ -61,7 +61,17 @@ export const ruRU = {
actionSuccessful: '{action} успешно',
outputFormat: 'Формат вывода',
singleFile: 'Один {ext} файл',
zipCompressedFile: 'ZIP сжатие {ext} файла'
zipCompressedFile: 'ZIP сжатие {ext} файла',
include: 'Включая',
none: 'Нет',
singleQuote: 'Одинарная кавычка',
doubleQuote: 'Двойная кавычка',
copyName: 'Скопировать имя',
search: 'Поиск',
title: 'Название',
archive: 'Архив',
undo: 'Отменить',
moveTo: 'Переместить в'
},
connection: {
connectionName: 'Название соединения',
@@ -96,7 +106,10 @@ export const ruRU = {
readOnlyMode: 'Режим только чтение',
untrustedConnection: 'Ненадежное соединение',
allConnections: 'Все соединения',
searchForConnections: 'Поиск соединений'
searchForConnections: 'Поиск соединений',
keepAliveInterval: 'Интервал поддержания соединения',
singleConnection: 'Одно соединение',
connection: 'Соединение'
},
database: {
schema: 'Схема',
@@ -255,7 +268,16 @@ export const ruRU = {
sqlExportOptions: 'Опции SQL экспорта',
targetTable: 'Целевая таблица',
importQueryErrors: 'Внимание: {n} ошибка возникла | Внимание: {n} ошибок произошло',
executedQueries: '{n} запрос выполнен | {n} запросов выполнено'
executedQueries: '{n} запрос выполнен | {n} запросов выполнено',
insert: 'Вставить',
materializedView: 'Материализованное представление | Материализованные представления',
exportTable: 'Экспорт таблицы',
createNewMaterializedView: 'Создать новое материализованное представление',
newMaterializedView: 'Новое материализованное представление',
switchDatabase: 'Переключить базу данных',
searchForElements: 'Поиск элементов',
searchForSchemas: 'Поиск схем',
savedQueries: 'Сохранённые запросы'
},
application: {
settings: 'Настройки',
@@ -313,9 +335,9 @@ export const ruRU = {
previousTab: 'Предыдущая вкладка',
selectTabNumber: 'Выбрать вкладку под номером {param}',
toggleConsole: 'Переключиться на консоль',
addShortcut: 'Добавить горячие клавиши',
editShortcut: 'Изменить горячие клавиши',
deleteShortcut: 'Удалить горячие клавиши',
addShortcut: 'Добавить горячую клавишу',
editShortcut: 'Изменить горячую клавишу',
deleteShortcut: 'Удалить горячую клавишу',
restoreDefaults: 'Восстановить по-умолчанию',
restoreDefaultsQuestion: 'Вы подтверждаете восстановление значений по-умолчанию?',
registerAShortcut: 'Зарегистрировать горячие клавиши',
@@ -329,13 +351,14 @@ export const ruRU = {
openFilter: 'Открыть фильтр',
nextResultsPage: 'Следующая страница',
previousResultsPage: 'Предыдущая страница',
editFolder: 'Изменить директорию',
folderName: 'Название директории',
deleteFolder: 'Удалить директорию',
editFolder: 'Изменить папку',
folderName: 'Название папки',
deleteFolder: 'Удалить папки',
editConnectionAppearance: 'Изменить внешний вид соединения',
defaultCopyType: 'Тип копирования по-умолчанию',
showTableSize: 'Показывать размер таблицы в сайдбаре',
showTableSizeDescription: 'Только MySQL/MariaDB. Включение этого параметра может повлиять на производительность схемы с большим количеством таблиц.',
showTableSizeDescription:
'Только MySQL/MariaDB. Включение этого параметра может повлиять на производительность схемы с большим количеством таблиц.',
searchForSchemas: 'Поиск схем',
searchForElements: 'Поиск элементов',
switchSearchMethod: 'Переключить способ поиска',
@@ -343,7 +366,49 @@ export const ruRU = {
closeOtherTabs: 'Закрыть остальные вкладки',
closeTabsToLeft: 'Закрыть вкладки слева',
closeTabsToRight: 'Закрыть вкладки справа',
phpArray: 'PHP массив'
phpArray: 'PHP массив',
event: 'Событие',
customIcon: 'Пользовательская иконка',
fileName: 'Имя файла',
choseFile: 'Выбрать файл',
data: 'Данные',
password: 'Пароль',
required: 'Обязательный',
newFolder: 'Новая папка',
outOfFolder: 'Вне папки',
csvFieldDelimiter: 'Разделитель полей CSV',
csvLinesTerminator: 'Терминатор строк CSV',
csvStringDelimiter: 'Разделитель строк CSV',
csvIncludeHeader: 'Включить заголовок',
csvExportOptions: 'Опции экспорта CSV',
exportData: 'Экспорт данных',
exportDataExplanation:
'Экспорт сохранённых соединений в Antares. Вам будет предложено ввести пароль для шифрования экспортируемого файла.',
importData: 'Импорт данных',
importDataExplanation: 'Импортирует файл .antares, содержащий соединения. Вам нужно будет ввести пароль, заданный во время экспорта.',
includeConnectionPasswords: 'Включить пароли соединений',
includeFolders: 'Включить папки',
encryptionPassword: 'Пароль шифрования',
encryptionPasswordError: 'Пароль шифрования должен содержать не менее 8 символов.',
ignoreDuplicates: 'Игнорировать дубликаты',
wrongImportPassword: 'Неверный пароль импорта',
wrongFileFormat: 'Неверный формат файла',
dataImportSuccess: 'Данные успешно импортированы',
note: 'Заметка | Заметки',
thereAreNoNotesYet: 'Заметок пока нет',
addNote: 'Добавить заметку',
editNote: 'Редактировать заметку',
saveAsNote: 'Сохранить как заметку',
showArchivedNotes: 'Показать архивированные заметки',
hideArchivedNotes: 'Скрыть архивированные заметки',
tag: 'Тег',
saveFile: 'Сохранить файл',
saveFileAs: 'Сохранить файл как',
openFile: 'Открыть файл',
openNotes: 'Открыть заметки',
debugConsole: 'Отладочная консоль',
executedQueries: 'Выполненные запросы',
sizeLimitError: 'Превышен максимальный размер {size}'
},
faker: {
address: 'Адрес',

View File

@@ -9,12 +9,14 @@ export const localesNames: Record<string, string> = {
'vi-VN': 'Tiếng Việt',
'ja-JP': '日本語',
'zh-CN': '简体中文',
'zh-TW': '體中文',
'zh-TW': '體中文',
'ru-RU': 'Русский',
'id-ID': 'Bahasa Indonesia',
'ko-KR': '한국어',
'nl-NL': 'Nederlands',
'ca-ES': 'Català',
'cs-CZ': 'Čeština',
'uk-UA': 'Українська'
'uk-UA': 'Українська',
'uz-UZ': 'O`zbek',
'he-IL': 'עברית'
};

576
src/renderer/i18n/uz-UZ.ts Normal file
View File

@@ -0,0 +1,576 @@
export const uzUZ = {
general: {
edit: 'Tahrirlash',
save: 'Saqlash',
close: 'Yopish',
delete: 'Oʻchirish',
confirm: 'Tasdiqlash',
cancel: 'Bekor qilish',
send: 'Yuborish',
refresh: 'Yangilash',
autoRefresh: 'Avto yangilash',
version: 'Versiya',
donate: 'Donat',
run: 'Bajarish',
results: 'Korsatildi',
size: 'Hajmi',
mimeType: 'Mime-Turi',
download: 'Yuklab olish',
add: 'Qoʻshish',
data: 'Maʼlumotlar',
properties: 'Xususiyatlar',
insert: 'Kiritish',
name: 'Nomi',
clear: 'Tozalash',
seconds: 'Soniyalar',
options: 'Parametrlar',
discard: 'Bekor qilish',
stay: 'Qolish',
author: 'Muallif',
upload: 'Yuklash',
browse: 'Koʻrish',
content: 'Mazmun',
cut: 'Kesish',
copy: 'Nusxalash',
paste: 'Qoʻyish',
tools: 'Asboblar',
format: 'Formatlash',
all: 'Hammasi',
duplicate: 'Nusxa kochirish',
new: 'Yangi',
history: 'Tarix',
select: 'Tanlash',
filter: 'Filtr',
change: 'Oʻzgartirish',
includes: 'Oʻz ichiga oladi',
completed: 'Tugallandi',
aborted: 'Bekor qilindi',
disabled: 'Oʻchirib qoʻyilgan',
enable: 'Yoqish',
disable: 'Oʻchirish',
contributors: 'Hissa qoʻshuvchilar',
pin: 'Biriktirish',
unpin: 'Ajratish',
folder: 'Papka | Papkalar',
deleteConfirm: 'Oʻchirib tashlashni tasdiqlaysizmi',
uploadFile: 'Fayl yuklash',
manualValue: 'Qiymatni qoʻlda kiritish',
selectAll: 'Hammasini tanlash',
pageNumber: 'Sahifa raqami',
directoryPath: 'Papka yoʻli',
actionSuccessful: '{action} muvaffaqiyatli bajarildi',
outputFormat: 'Chiqarish formati',
singleFile: 'Bitta {ext} fayl',
zipCompressedFile: 'ZIP siqilgan {ext} fayl',
include: 'Qoʻshish',
none: 'Yoʻq',
singleQuote: 'Yagona qoʻshtirnoq',
doubleQuote: 'Ikkilik qoʻshtirnoq',
copyName: 'Nomi nusxalash',
search: 'Qidirish',
title: 'Sarlavha',
archive: 'Arxiv',
undo: 'Bekor qilish',
moveTo: 'Koʻchirish'
},
connection: {
connectionName: 'Ulanish nomi',
client: 'Mijoz',
hostName: 'Xost nomi',
port: 'Port',
user: 'Foydalanuvchi',
password: 'Parol',
credentials: 'Vakolatlar',
connect: 'Ulanish',
connected: 'Ulangan',
disconnect: 'Uzish',
disconnected: 'Uzilgan',
ssl: 'SSL',
privateKey: 'Yopiq kalit',
certificate: 'Sertifikat',
caCertificate: 'CA sertifikat',
ciphers: 'Shifrlar',
sshTunnel: 'SSH tunnel',
passphrase: 'Parol frazasi',
connectionString: 'Ulanish qatori',
addConnection: 'Ulanish qoʻshish',
createConnection: 'Ulanish yaratish',
createNewConnection: 'Yangi ulanish yaratish',
askCredentials: 'Hisob maʼlumotlarini soʻrash',
testConnection: 'Ulanishni sinash',
editConnection: 'Ulanishni tahrirlash',
deleteConnection: 'Ulanishni oʻchirish',
connectionSuccessfullyMade: 'Ulanish muvaffaqiyatli amalga oshirildi!',
enableSsl: 'SSL ni yoqish',
enableSsh: 'SSH ni yoqish',
readOnlyMode: 'Faqat oʻqish rejimi',
untrustedConnection: 'Ishonchsiz ulanish',
allConnections: 'Barcha ulanishlar',
searchForConnections: 'Ulanishlarni qidirish',
keepAliveInterval: 'Ulanishni saqlash oraliq vaqti',
singleConnection: 'Bitta ulanish',
connection: 'Ulanish'
},
database: {
schema: 'Shema',
type: 'Tur',
foreignKeys: 'Tashqi kalitlar',
length: 'Uzunlik',
unsigned: 'Imzosiz',
default: 'Standart',
comment: 'Izoh',
collation: 'Moslash',
key: 'Kalit | Kalitlar',
order: 'Tartib',
expression: 'Ifoda',
autoIncrement: 'Avtomatik oshirish',
engine: 'Dvigatel',
field: 'Maydon | Maydonlar',
approximately: 'Taxminan',
total: 'Jami',
table: 'Jadval',
view: 'Korinish',
indexes: 'Indekslar',
definer: 'Belgilar',
algorithm: 'Algoritm',
trigger: 'Trigge | Triggeler',
storedRoutine: 'Saqlangan protsedura | Saqlangan protseduralar',
scheduler: 'Rejalashtiruvchi | Rejalashtiruvchilar',
event: 'Voqea',
parameters: 'Parametrlar',
function: 'Funktsiya | Funktsiyalar',
deterministic: 'Deterministik',
context: 'Kontekst',
export: 'Eksport',
import: 'Import',
returns: 'Qaytaradi',
timing: 'Vaqt',
state: 'Holat',
execution: 'Bajarish',
starts: 'Boshlanishi',
ends: 'Tugashi',
variables: 'Ozgaruvchilar',
processes: 'Jarayonlar',
database: 'Maʼlumotlar bazasi',
array: 'Massiv',
structure: 'Tuzilish',
row: 'Qator | Qatorlar',
cell: 'Yacheyka | Yacheykalar',
triggerFunction: 'Trigger funktsiyasi | Trigger funktsiyalari',
routine: 'Protsedura',
commit: 'Tasdiqlash',
rollback: 'Bekor qilish',
resultsTable: 'Natija jadvali',
ddl: 'DDL',
drop: 'Oʻchirish',
unableEditFieldWithoutPrimary: 'Birlamchi kalit bolmasa, maydonni tahrirlash mumkin emas',
editCell: 'Yacheykani tahrirlash',
deleteRows: 'Qatorni oʻchirish | {count} qatorni oʻchirish',
confirmToDeleteRows: 'Qatorni oʻchirishni tasdiqlaysizmi? | {count} qatorni oʻchirishni tasdiqlaysizmi?',
addNewRow: 'Yangi qator qoʻshish',
numberOfInserts: 'Qoʻshilganlar soni',
affectedRows: 'Taqsir qilingan qatorlar',
createNewDatabase: 'Yangi maʼlumotlar bazasi yaratish',
databaseName: 'Maʼlumotlar bazasi nomi',
serverDefault: 'Server standartlari boyicha',
deleteDatabase: 'Maʼlumotlar bazasini oʻchirish',
editDatabase: 'Maʼlumotlar bazasini tahrirlash',
clearChanges: 'Oʻzgarishlarni oʻchirish',
addNewField: 'Yangi maydon qoshish',
manageIndexes: 'Indekslarni boshqarish',
manageForeignKeys: 'Tashqi kalitlarni boshqarish',
allowNull: 'NULL ga ruxsat berish',
zeroFill: 'Nol bilan toʻldirish',
customValue: 'Foydalanuvchi qiymati',
onUpdate: 'Yangilanishda',
deleteField: 'Maydonni oʻchirish',
createNewIndex: 'Yangi indeks yaratish',
addToIndex: 'Indeksga qoʻshish',
createNewTable: 'Yangi jadval yaratish',
emptyTable: 'Jadvalni tozalash',
deleteTable: 'Jadvalni oʻchirish',
emptyConfirm: 'Tozalashni tasdiqlaysizmi?',
thereAreNoIndexes: 'Indekslar mavjud emas',
thereAreNoForeign: 'Tashqi kalitlar mavjud emas',
createNewForeign: 'Yangi tashqi kalit yaratish',
referenceTable: 'Jadvalga murojaat',
referenceField: 'Maydonga murojaat',
foreignFields: 'Tashqi maydonlar',
invalidDefault: 'Notogri qiymat',
onDelete: 'Oʻchirishda',
selectStatement: 'Tanlash operatori',
triggerStatement: 'Trigger operatori',
sqlSecurity: 'SQL xavfsizligi',
updateOption: 'Yangilash parametrlari',
deleteView: 'Korinishni oʻchirish',
createNewView: 'Yangi korinish yaratish',
deleteTrigger: 'Trigerni oʻchirish',
createNewTrigger: 'Yangi trigger yaratish',
currentUser: 'Hozirgi foydalanuvchi',
routineBody: 'Protsedura matni',
dataAccess: 'Maʼlumotlarga kirish',
thereAreNoParameters: 'Parametrlar yoʻq',
createNewParameter: 'Yangi parametr yaratish',
createNewRoutine: 'Yangi protsedura yaratish',
deleteRoutine: 'Protsedurani oʻchirish',
functionBody: 'Funktsiya matni',
createNewFunction: 'Yangi funktsiya yaratish',
deleteFunction: 'Funktsiyani oʻchirish',
schedulerBody: 'Rejalashtiruvchi matni',
createNewScheduler: 'Yangi rejalashtiruvchi yaratish',
deleteScheduler: 'Rejalashtiruvchini oʻchirish',
preserveOnCompletion: 'Yakunlangandan soʻng saqlash',
tableFiller: 'Jadval toʻldiruvchisi',
fakeDataLanguage: 'Soxta maʼlumotlar tili',
queryDuration: 'Soʻrov davomiyligi',
setNull: 'NULL qiymatni oʻrnatish',
processesList: 'Jarayonlar roʻyxati',
processInfo: 'Jarayon maʼlumotlari',
manageUsers: 'Foydalanuvchilarni boshqarish',
createNewSchema: 'Yangi shema yaratish',
schemaName: 'Shema nomi',
editSchema: 'Shemaga ozgartirish kiritish',
deleteSchema: 'Shemadan oʻchirish',
duplicateTable: 'Jadvalni dublikat qilish',
noSchema: 'Shemalar mavjud emas',
runQuery: 'Soʻrovni bajarish',
thereAreNoTableFields: 'Jadvalda maydonlar yoʻq',
newTable: 'Yangi jadval',
newView: 'Yangi korinish',
newTrigger: 'Yangi trigger',
newRoutine: 'Yangi protsedura',
newFunction: 'Yangi funktsiya',
newScheduler: 'Yangi rejalashtiruvchi',
newTriggerFunction: 'Yangi trigger funktsiyasi',
thereAreNoQueriesYet: 'Soʻrovlar hali mavjud emas',
searchForQueries: 'Soʻrovlarni qidirish',
killProcess: 'Jarayonni toʻxtatish',
exportSchema: 'Shemadan eksport qilish',
importSchema: 'Shemaga import qilish',
newInsertStmtEvery: 'Har bir uchun yangi INSERT operator',
processingTableExport: '{table} ni qayta ishlash',
fetchingTableExport: '{table} maʼlumotlarini olish',
writingTableExport: '{table} ga yozish',
checkAllTables: 'Barcha jadvallarni belgilash',
uncheckAllTables: 'Barcha jadvallardan belgilashni olib tashlash',
killQuery: 'Soʻrovni toʻxtatish',
insertRow: 'Qator kiritish | Qatorlarni kiritish',
commitMode: 'Tranzaksiya tasdiqlash rejimi',
autoCommit: 'Avtomatik tasdiqlash',
manualCommit: 'Qoʻlda tasdiqlash',
disableFKChecks: 'Tashqi kalitlarni tekshirishni oʻchirish',
formatQuery: 'Soʻrovni formatlash',
queryHistory: 'Soʻrovlar tarixi',
clearQuery: 'Soʻrovni tozalash',
fillCell: 'Yacheykani toʻldirish',
executeSelectedQuery: 'Tanlangan soʻrovni bajarish',
noResultsPresent: 'Natijalar yoʻq',
sqlExportOptions: 'SQL eksport parametrlari',
targetTable: 'Maqsad jadvali',
importQueryErrors: 'Diqqat: {n} xato yuz berdi | Diqqat: {n} xatolar yuz berdi',
executedQueries: '{n} soʻrov bajarildi | {n} soʻrovlar bajarildi',
insert: 'Kiritish',
materializedView: 'Materializatsiya qilingan korinish | Materializatsiya qilingan korinishlar',
exportTable: 'Jadvalni eksport qilish',
createNewMaterializedView: 'Yangi materializatsiya qilingan korinish yaratish',
newMaterializedView: 'Yangi materializatsiya qilingan korinish',
switchDatabase: 'Maʼlumotlar bazasini almashtirish',
searchForElements: 'Elementlarni qidirish',
searchForSchemas: 'Shemalarni qidirish',
savedQueries: 'Saqlangan soʻrovlar'
},
application: {
settings: 'Sozlamalar',
general: 'Umumiy',
themes: 'Mavzular',
update: 'Yangilash',
about: 'Dastur haqida',
language: 'Til',
light: 'Yorugʻ',
dark: 'Qorongʻi',
autoCompletion: 'Avto-tugallash',
application: 'Ilova',
editor: 'Tahrirchi',
scratchpad: 'Eslatmalar',
changelog: 'Oʻzgarishlar jurnali',
small: 'Kichik',
medium: 'Oʻrta',
large: 'Katta',
console: 'Konsol',
shortcuts: 'Qisqa tugmalar',
appearance: 'Tashqi koʻrinish',
color: 'Rang',
label: 'Yorliq',
icon: 'Belgi',
madeWithJS: '💛 va JavaScript bilan yaratilgan!',
checkForUpdates: 'Yangilanishlarni tekshirish',
noUpdatesAvailable: 'Yangilanishlar topilmadi',
checkingForUpdate: 'Yangilanishlarni qidirish',
checkFailure: 'Yangilanishlarni tekshirib boʻlmadi, iltimos keyinroq urinib koʻring',
updateAvailable: 'Yangilanish mavjud',
downloadingUpdate: 'Yangilanishni yuklab olish',
updateDownloaded: 'Yangilanish yuklab olindi',
restartToInstall: 'Oʻrnatish uchun Antares-ni qayta ishga tushiring',
notificationsTimeout: 'Bildirishnoma vaqti',
openNewTab: 'Yangi tab ochish',
unsavedChanges: 'Saqlanmagan oʻzgarishlar',
discardUnsavedChanges: 'Saqlanmagan maʼlumotlaringiz mavjud. Ushbu oynani yopish ularni bekor qiladi.',
applicationTheme: 'Ilova mavzusi',
editorTheme: 'Tahrirchi mavzusi',
wrapLongLines: 'Uzun satrlarni oʻrash',
includeBetaUpdates: 'Beta yangilanishlarni olish',
markdownSupported: 'Markdown qoʻllab-quvvatlanadi',
plantATree: 'Daraxt ekish',
dataTabPageSize: 'MAʼLUMOTLAR yorligʻi sahifa oʻlchami',
noOpenTabs: 'Ochiq yorliqlar yoʻq, chap paneldan foydalaning yoki:',
restorePreviousSession: 'Avvalgi sessiyani tiklash',
closeTab: 'Yorliqni yopish',
goToDownloadPage: 'Yuklash sahifasiga oʻtish',
disableBlur: 'Bulutni oʻchirish',
missingOrIncompleteTranslation: 'Yetishmayotgan yoki toʻliq boʻlmagan tarjima?',
findOutHowToContribute: 'Qanday hissa qoʻshishni bilib oling',
disableScratchpad: 'Eslatmalarni oʻchirish',
reportABug: 'Xato haqida xabar berish',
nextTab: 'Keyingi yorliq',
previousTab: 'Oldingi yorliq',
selectTabNumber: '{param} raqamli yorliqni tanlash',
toggleConsole: 'Konsolni almashtirish',
addShortcut: 'Qisqa tugma qoʻshish',
editShortcut: 'Qisqa tugmani tahrirlash',
deleteShortcut: 'Qisqa tugmani oʻchirish',
restoreDefaults: 'Standartlarga qaytarish',
restoreDefaultsQuestion: 'Standart qiymatlarni tiklashga rozimisiz?',
registerAShortcut: 'Qisqa tugma roʻyxatdan oʻtkazish',
invalidShortcutMessage: 'Bu kombinatsiyani ishlatib boʻlmaydi, boshqa birini sinab koʻring',
shortcutAlreadyExists: 'Bunday kombinatsiya allaqachon mavjud',
saveContent: 'Mazmunni saqlash',
openAllConnections: 'Barcha ulanishlarni ochish',
openSettings: 'Sozlamalarni ochish',
openScratchpad: 'Eslatmalarni ochish',
runOrReload: 'Bajaring yoki qayta yuklang',
openFilter: 'Filtrni ochish',
nextResultsPage: 'Keyingi sahifa',
previousResultsPage: 'Oldingi sahifa',
editFolder: 'Papkani tahrirlash',
folderName: 'Papkalar nomi',
deleteFolder: 'Papkani oʻchirish',
editConnectionAppearance: 'Ulanish tashqi koʻrinishini oʻzgartirish',
defaultCopyType: 'Odatiy nusxa koʻchirish turi',
showTableSize: 'Yon panelda jadval oʻlchamini koʻrsatish',
showTableSizeDescription: 'Faqat MySQL/MariaDB. Ushbu parametrni yoqish koʻp jadvalli sxemalarda ishlash tezligiga taʼsir qilishi mumkin.',
searchForSchemas: 'Sxemalarni qidirish',
searchForElements: 'Elementlarni qidirish',
switchSearchMethod: 'Qidiruv usulini almashtirish',
closeAllTabs: 'Barcha yorliqlarni yopish',
closeOtherTabs: 'Boshqa yorliqlarni yopish',
closeTabsToLeft: 'Chapdagi yorliqlarni yopish',
closeTabsToRight: 'Oʻngdagi yorliqlarni yopish',
phpArray: 'PHP massiv',
event: 'Hodisa',
customIcon: 'Maxsus belgi',
fileName: 'Fayl nomi',
choseFile: 'Faylni tanlash',
data: 'Maʼlumotlar',
password: 'Parol',
required: 'Majburiy',
newFolder: 'Yangi papka',
outOfFolder: 'Papkadan tashqari',
csvFieldDelimiter: 'CSV maydon ajratgichi',
csvLinesTerminator: 'CSV satr terminatori',
csvStringDelimiter: 'CSV satr ajratgichi',
csvIncludeHeader: 'Sarlavhani kiritish',
csvExportOptions: 'CSV eksport imkoniyatlari',
exportData: 'Maʼlumotlarni eksport qilish',
exportDataExplanation: 'Antares-dagi saqlangan ulanishlarni eksport qilish. Shifrlangan fayl uchun parol kiritishingiz soʻraladi.',
importData: 'Maʼlumotlarni import qilish',
importDataExplanation: '.antares faylini import qiladi, unda ulanishlar mavjud. Eksport paytida kiritilgan parolni kiritishingiz kerak.',
includeConnectionPasswords: 'Ulanish parollarini kiritish',
includeFolders: 'Papkalarni kiritish',
encryptionPassword: 'Shifrlash paroli',
encryptionPasswordError: 'Shifrlash paroli kamida 8 ta belgi boʻlishi kerak.',
ignoreDuplicates: 'Nusxalarni inkor qilish',
wrongImportPassword: 'Import paroli notoʻgʻri',
wrongFileFormat: 'Fayl formati notoʻgʻri',
dataImportSuccess: 'Maʼlumotlar muvaffaqiyatli import qilindi',
note: 'Eslatma | Eslatmalar',
thereAreNoNotesYet: 'Hali eslatmalar yoʻq',
addNote: 'Eslatma qoʻshish',
editNote: 'Eslatmani tahrirlash',
saveAsNote: 'Eslatma sifatida saqlash',
showArchivedNotes: 'Arxivlangan eslatmalarni koʻrsatish',
hideArchivedNotes: 'Arxivlangan eslatmalarni yashirish',
tag: 'Teg',
saveFile: 'Faylni saqlash',
saveFileAs: 'Faylni sifatida saqlash',
openFile: 'Faylni ochish',
openNotes: 'Eslatmalarni ochish',
debugConsole: 'Nosozliklarni tuzatish konsoli',
executedQueries: 'Bajarilgan soʻrovlar',
sizeLimitError: 'Maksimal oʻlcham {size} dan oshib ketdi'
},
faker: {
address: 'Manzil',
commerce: 'Tijorat',
company: 'Kompaniya',
database: 'Ma`lumotlar bazasi',
date: 'Sana',
finance: 'Moliyaviy',
git: 'Git',
hacker: 'Xaker',
internet: 'Internet',
lorem: 'Lorem',
name: 'Ism',
music: 'Musiqa',
phone: 'Telefon',
random: 'Tasodifiy',
system: 'Tizim',
time: 'Vaqt',
vehicle: 'Transport vositasi',
zipCode: 'Pochta kodi',
zipCodeByState: 'Shahar pochta kodi',
city: 'Shahar',
cityPrefix: 'Shahar prefiksi',
citySuffix: 'Shahar sufixi',
streetName: 'Ko`cha nomi',
streetAddress: 'Ko`cha manzili',
streetSuffix: 'Ko`cha sufixi',
streetPrefix: 'Ko`cha prefiksi',
secondaryAddress: 'Ikkinchi manzil',
county: 'Okrug',
country: 'Davlat',
countryCode: 'Davlat kodi',
state: 'Viloyat',
stateAbbr: 'Viloyat qisqartmasi',
latitude: 'Kenglik',
longitude: 'Uzunlik',
direction: 'Yo`nalish',
cardinalDirection: 'Kardinal yo`nalish',
ordinalDirection: 'Tartibiy yo`nalish',
nearbyGPSCoordinate: 'Yaqin GPS koordinatasi',
timeZone: 'Vaqt zonasі',
color: 'Rang',
department: 'Bo`lim',
productName: 'Mahsulot nomi',
price: 'Narx',
productAdjective: 'Mahsulotga oid sifat',
productMaterial: 'Mahsulot materiali',
product: 'Mahsulot',
productDescription: 'Mahsulot ta`rifi',
suffixes: 'Sufikslari',
companyName: 'Kompaniya nomi',
companySuffix: 'Kompaniya sufixi',
catchPhrase: 'Slogan',
bs: 'BS',
catchPhraseAdjective: 'Slogan sifat',
catchPhraseDescriptor: 'Slogan tavsifi',
catchPhraseNoun: 'Slogan ot',
bsAdjective: 'BS sifat',
bsBuzz: 'BS shovqin',
bsNoun: 'BS ot',
column: 'Ustun',
type: 'Tur',
collation: 'Taqqoslash',
engine: 'Dvigatel',
past: 'O`tgan',
now: 'Hozir',
future: 'Kelajak',
between: 'Orasida',
recent: 'Yaqinda',
soon: 'Tez orada',
month: 'Oy',
weekday: 'Hafta kuni',
account: 'Hisob',
accountName: 'Hisob nomi',
routingNumber: 'Yo`nalish raqami',
mask: 'Maska',
amount: 'Miqdor',
transactionType: 'Transaksiya turi',
currencyCode: 'Valyuta kodi',
currencyName: 'Valyuta nomi',
currencySymbol: 'Valyuta belgilari',
bitcoinAddress: 'Bitcoin hamyoni',
litecoinAddress: 'Litecoin hamyoni',
creditCardNumber: 'Kredit karta raqami',
creditCardCVV: 'CVV kodi',
ethereumAddress: 'Ethereum hamyoni',
iban: 'Iban',
bic: 'Bic',
transactionDescription: 'Transaksiya ta`rifi',
branch: 'Filial',
commitEntry: 'Kommit',
commitMessage: 'Kommit xabari',
commitSha: 'SHA kommit',
shortSha: 'Qisqa SHA',
abbreviation: 'Qisqartma',
adjective: 'Sifat',
noun: 'Ot',
verb: 'Fe`l',
ingverb: 'Ildiz fe`l',
phrase: 'Ibora',
avatar: 'Avatar',
email: 'Elektron pochta',
exampleEmail: 'Elektron pochta misoli',
userName: 'Login',
protocol: 'Protokol',
url: 'Url',
domainName: 'Domen nomi',
domainSuffix: 'Domen sufixi',
domainWord: 'Domen so`zi',
ip: 'Ip',
ipv6: 'Ipv6',
userAgent: 'User agent',
mac: 'MAC-manzil',
password: 'Parol',
word: 'So`z',
words: 'So`zlar',
sentence: 'Gap',
slug: 'Slug',
sentences: 'Gaplar',
paragraph: 'Paragraf',
paragraphs: 'Paragraflar',
text: 'Matn',
lines: 'Chiziqlar',
genre: 'Janr',
firstName: 'Ism',
lastName: 'Familiya',
middleName: 'Otasining ismi',
findName: 'To`liq ism',
jobTitle: 'Lavozim',
gender: 'Jins',
prefix: 'Prefiks',
suffix: 'Sufiks',
title: 'Sarlavha',
jobDescriptor: 'Lavozim ta`rifi',
jobArea: 'Lavozim sohasi',
jobType: 'Lavozim turi',
phoneNumber: 'Telefon raqami',
phoneNumberFormat: 'Telefon raqami formati',
phoneFormats: 'Telefon raqami formatlari',
number: 'Raqam',
float: 'O`nlik son',
arrayElement: 'Massiv elementi',
arrayElements: 'Massiv elementlari',
objectElement: 'Obyekt elementi',
uuid: 'Uuid',
boolean: 'Mantiqiy',
image: 'Rasm',
locale: 'Mahalliy',
alpha: 'Harflar',
alphaNumeric: 'Alfavitli-sonli',
hexaDecimal: 'O`n oltilik',
fileName: 'Fayl nomi',
commonFileName: 'Ommaviy fayl nomi',
mimeType: 'Mime-turi',
commonFileType: 'Ommaviy fayl turi',
commonFileExt: 'Ommaviy fayl kengaytmasi',
fileType: 'Fayl turi',
fileExt: 'Fayl kengaytmasi',
directoryPath: 'Katalog yo`li',
filePath: 'Fayl yo`li',
semver: 'Semver',
manufacturer: 'Ishlab chiqaruvchi',
model: 'Model',
fuel: 'Yoqilg`i',
vin: 'Vin'
}
};

View File

@@ -117,6 +117,7 @@ export const zhCN = {
insert: '插入',
indexes: '索引',
foreignKeys: '外键',
tableChecks: '表检查',
length: '长度',
unsigned: '无符号',
default: '默认',
@@ -131,6 +132,7 @@ export const zhCN = {
total: '总计',
table: '表 | 表',
view: '视图 | 视图',
materializedView: '实体化视图 | 实体化视图',
definer: '定义者',
algorithm: '算法',
trigger: '触发器 | 触发器',
@@ -180,12 +182,15 @@ export const zhCN = {
addNewField: '添加新字段',
manageIndexes: '管理索引',
manageForeignKeys: '管理外键',
manageTableChecks: '管理表 check 约束',
allowNull: '允许 NULL',
zeroFill: '零填充',
customValue: '自定义值',
onUpdate: '在更新',
deleteField: '删除字段',
createNewIndex: '创建新索引',
createNewCheck: '创建新 check 约束',
checkClause: 'Check 约束',
addToIndex: '添加到索引',
createNewTable: '创建新表',
emptyTable: '清空表',
@@ -195,6 +200,7 @@ export const zhCN = {
emptyConfirm: '您是否确认清空',
thereAreNoIndexes: '没有索引',
thereAreNoForeign: '没有外键',
thereAreNoTableChecks: '没有表 check 约束',
createNewForeign: '创建新外键',
referenceTable: '参考表',
referenceField: '参考字段',
@@ -207,6 +213,7 @@ export const zhCN = {
updateOption: '更新选项',
deleteView: '删除视图',
createNewView: '创建新视图',
createNewMaterializedView: '创建新实体化视图',
deleteTrigger: '删除触发器',
createNewTrigger: '创建新触发器',
currentUser: '当前用户',
@@ -239,6 +246,7 @@ export const zhCN = {
thereAreNoTableFields: '没有表的字段',
newTable: '新表',
newView: '新视图',
newMaterializedView: '新实体化视图',
newTrigger: '新触发器',
newRoutine: '新例程',
newFunction: '新函数',
@@ -300,6 +308,7 @@ export const zhCN = {
color: '颜色',
label: '标签',
icon: '图标',
customIcon: '定制图标',
fileName: '文件名称',
choseFile: '选择文件',
data: '数据',
@@ -324,7 +333,7 @@ export const zhCN = {
wrapLongLines: '将长行换行显示',
markdownSupported: '支持 Markdown',
plantATree: '种植一棵树',
dataTabPageSize: '数据标签的页面大小',
dataTabPageSize: '每页结果',
noOpenTabs: '没有打开的标签, 请在左侧栏上导航或:',
restorePreviousSession: '恢复上一个会话',
closeTab: '关闭标签',
@@ -348,7 +357,6 @@ export const zhCN = {
saveContent: '保存内容',
openAllConnections: '打开所有连接',
openSettings: '打开设置',
openScratchpad: '打开草稿栏',
runOrReload: '运行或重新加载',
openFilter: '打开过滤器',
nextResultsPage: '下一个结果页',
@@ -356,6 +364,8 @@ export const zhCN = {
editFolder: '编辑文件夹',
folderName: '文件夹名称',
deleteFolder: '删除文件夹',
newFolder: '新文件夹',
outOfFolder: '',
editConnectionAppearance: '编辑连接的外观',
defaultCopyType: '默认复制类型',
showTableSize: '在侧边栏显示表大小',
@@ -394,7 +404,10 @@ export const zhCN = {
saveFile: '保存文件',
saveFileAs: '将文件另存为',
openFile: '打开文件',
openNotes: '打开笔记'
openNotes: '打开笔记',
debugConsole: '调试控制台',
executedQueries: '执行的查询',
sizeLimitError: '超过 {size} 的最大大小'
},
faker: { // Faker.js 方法,用于随机生成的内容
address: '地址',

View File

@@ -44,6 +44,15 @@ ipcRenderer.on('unhandled-exception', (event, error) => {
date: new Date()
});
});
ipcRenderer.on('non-blocking-exception', (event, error) => {
useNotificationsStore().addNotification({ status: 'error', message: error.message });
useConsoleStore().putLog('debug', {
level: 'error',
process: 'main',
message: error.message,
date: new Date()
});
});
// IPC query logs
ipcRenderer.on('query-log', (event, logRecord: QueryLog) => {

View File

@@ -1,18 +1,15 @@
import { ConnectionParams, IpcResponse } from 'common/interfaces/antares';
import { ipcRenderer } from 'electron';
import connStringConstruct from '../libs/connStringDecode';
import { unproxify } from '../libs/unproxify';
export default class {
static makeTest (params: ConnectionParams & { pgConnString?: string }): Promise<IpcResponse> {
const newParams = connStringConstruct(params) as ConnectionParams;
return ipcRenderer.invoke('test-connection', unproxify(newParams));
static makeTest (params: ConnectionParams & { connString?: string }): Promise<IpcResponse> {
return ipcRenderer.invoke('test-connection', unproxify(params));
}
static connect (params: ConnectionParams & { pgConnString?: string }): Promise<IpcResponse> {
const newParams = connStringConstruct(params) as ConnectionParams;
return ipcRenderer.invoke('connect', unproxify(newParams));
static connect (params: ConnectionParams & { connString?: string }): Promise<IpcResponse> {
return ipcRenderer.invoke('connect', unproxify(params));
}
static abortConnection (uid: string): void {

View File

@@ -36,6 +36,10 @@ export default class {
return ipcRenderer.invoke('get-table-indexes', unproxify(params));
}
static getTableChecks (params: { uid: string; schema: string; table: string }): Promise<IpcResponse> {
return ipcRenderer.invoke('get-table-checks', unproxify(params));
}
static getTableDll (params: { uid: string; schema: string; table: string }): Promise<IpcResponse<string>> {
return ipcRenderer.invoke('get-table-ddl', unproxify(params));
}

View File

@@ -1,50 +0,0 @@
import { ConnectionParams } from 'common/interfaces/antares';
import * as formatter from 'pg-connection-string'; // parses a connection string
const formatHost = (host: string) => {
const results = host === 'localhost' ? '127.0.0.1' : host;
return results;
};
const checkForSSl = (conn: string) => {
return conn.includes('ssl=true');
};
const connStringConstruct = (args: ConnectionParams & { pgConnString?: string }): ConnectionParams => {
if (!args.pgConnString)
return args;
if (typeof args.pgConnString !== 'string')
return args;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const stringArgs: any = formatter.parse(args.pgConnString);
const client = args.client || 'pg';
args.client = client;
args.host = formatHost(stringArgs.host);
args.database = stringArgs.database;
args.port = stringArgs.port || '5432';
args.user = stringArgs.user;
args.password = stringArgs.password;
// ssh
args.ssh = stringArgs.ssh || args.ssh;
args.sshHost = stringArgs.sshHost;
args.sshUser = stringArgs.sshUser;
args.sshPass = stringArgs.sshPass;
args.sshKey = stringArgs.sshKey;
args.sshPort = stringArgs.sshPort;
// ssl mode
args.ssl = checkForSSl(args.pgConnString) || args.ssl;
args.cert = stringArgs.sslcert;
args.key = stringArgs.sslkey;
args.ca = stringArgs.sslrootcert;
args.ciphers = stringArgs.ciphers;
return args;
};
export default connStringConstruct;

View File

@@ -29,13 +29,7 @@ $explorebar-width: 14rem;
$footer-height: 1.5rem;
@function get-excluding-size() {
@if $platform == linux {
@return $footer-height;
}
@else {
@return $footer-height + $titlebar-height;
}
@return $footer-height + $titlebar-height;
}
/* stylelint-disable-next-line function-no-unknown */

View File

@@ -20,6 +20,7 @@
body {
user-select: none;
background-color: #000;
}
a {
@@ -256,6 +257,10 @@ option:checked {
}
&.active {
a {
border-bottom-color: transparent;
}
.tab-link {
border-color: transparent;
}

View File

@@ -255,6 +255,11 @@
}
}
&.result-tabs .tab-item {
background: transparent;
}
.workspace-query-runner .workspace-query-runner-footer .workspace-query-buttons .btn {
color: $body-font-color-dark;
}

View File

@@ -1,5 +1,7 @@
/* stylelint-disable function-no-unknown */
.theme-light {
background: $body-bg;
::-webkit-scrollbar-track {
background: #fff;
}

View File

@@ -25,12 +25,13 @@ export interface SidebarElement {
export interface CustomIcon {base64: string; uid: string}
if (!key) { // If no key in local storace
if (!key) { // If no key in local storage
const storedKey = ipcRenderer.sendSync('get-key');// Ask for key stored on disk
if (!storedKey) { // Of nop stored key on disk
if (!storedKey) { // If not stored key on disk
const newKey = crypto.randomBytes(16).toString('hex');
localStorage.setItem('key', newKey);
ipcRenderer.send('set-key', newKey);
key = newKey;
}
else {

View File

@@ -10,7 +10,7 @@ export interface QueryLog {
}
export interface DebugLog {
level: 'log' | 'info' | 'warn' | 'error';
level: 'log' | 'info' | 'warn' | 'error' | string;
process: 'renderer' | 'main' | 'worker';
message: string;
date: Date;

View File

@@ -1,6 +1,8 @@
import { uidGen } from 'common/libs/uidGen';
import { defineStore } from 'pinia';
import { useConsoleStore } from './console';
export interface Notification {
uid: string;
status: string;
@@ -15,6 +17,13 @@ export const useNotificationsStore = defineStore('notifications', {
addNotification (payload: { status: string; message: string }) {
const notification: Notification = { uid: uidGen('N'), ...payload };
this.notifications.unshift(notification);
useConsoleStore().putLog('debug', {
level: notification.status,
process: 'renderer',
message: notification.message,
date: new Date()
});
},
removeNotification (uid: string) {
this.notifications = (this.notifications as Notification[]).filter(item => item.uid !== uid);

View File

@@ -147,7 +147,7 @@ export const useWorkspacesStore = defineStore('workspaces', {
else
this.selectedWorkspace = uid;
},
async connectWorkspace (connection: ConnectionParams & { pgConnString?: string }, args?: {mode?: string; signal?: AbortSignal}) {
async connectWorkspace (connection: ConnectionParams & { connString?: string }, args?: {mode?: string; signal?: AbortSignal}) {
this.workspaces = (this.workspaces as Workspace[]).map(workspace => workspace.uid === connection.uid
? {
...workspace,
@@ -427,7 +427,7 @@ export const useWorkspacesStore = defineStore('workspaces', {
this.selectTab({ uid, tab: 0 });
},
async switchConnection (connection: ConnectionParams & { pgConnString?: string }) {
async switchConnection (connection: ConnectionParams & { connString?: string }) {
await Connection.disconnect(connection.uid);
return this.connectWorkspace(connection, { mode: 'switch' });
},

View File

@@ -3,6 +3,7 @@
declare module '@/App.vue';
declare module 'v-mask';
declare module 'json2php';
declare module '*/encoding_charset.js';
declare module 'vuedraggable' {// <- to export as default
const draggableComponent: import('vue').DefineComponent<{
list: {

View File

@@ -1,8 +1,7 @@
const path = require('path');
const webpack = require('webpack');
const ProgressPlugin = require('progress-webpack-plugin');
const { dependencies, devDependencies, version } = require('./package.json');
const { dependencies, devDependencies } = require('./package.json');
const externals = Object.keys(dependencies).concat(Object.keys(devDependencies));
const isDevMode = process.env.NODE_ENV === 'development';
@@ -48,13 +47,7 @@ module.exports = { // Main
}
},
plugins: [
new ProgressPlugin(true),
new webpack.DefinePlugin({
'process.env': {
PACKAGE_VERSION: `"${version}"`,
DISTRIBUTION: `"${process.env.DISTRIBUTION || 'none'}"`
}
})
new ProgressPlugin(true)
],
module: {
rules: [