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

Compare commits

...

37 Commits

Author SHA1 Message Date
e986f287c6 chore(release): 0.7.31-beta.0 2025-01-06 11:11:23 +01: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
37 changed files with 1969 additions and 149 deletions

View File

@@ -311,6 +311,33 @@
"contributions": [ "contributions": [
"code" "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"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

View File

@@ -3,3 +3,4 @@ assets
out out
dist dist
build build
misc

View File

@@ -2,6 +2,70 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [0.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) ### [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)

View File

@@ -1,13 +1,13 @@
<!-- markdownlint-disable --> <!-- markdownlint-disable -->
<p align="center"> <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> </p>
<!-- markdownlint-restore --> <!-- markdownlint-restore -->
# Antares SQL Client # 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. 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. 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. 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. 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). 👁 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. 🌟 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 ### 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 ### MacOS
@@ -99,8 +99,8 @@ On macOS you can run `.dmg` distribution following [this guide](https://support.
## How to contribute ## How to contribute
- 🌍 [Translate Antares](https://github.com/Fabio286/antares/wiki/Translate-Antares) - 🌍 [Translate Antares](https://github.com/antares-sql/antares/wiki/Translate-Antares)
- 📖 [Contributors Guide](https://github.com/Fabio286/antares/wiki/Contributors-Guide) - 📖 [Contributors Guide](https://github.com/antares-sql/antares/wiki/Contributors-Guide)
- 🚧 [Project Board](https://github.com/orgs/antares-sql/projects/3/views/2) - 🚧 [Project Board](https://github.com/orgs/antares-sql/projects/3/views/2)
## Contributors ✨ ## Contributors ✨
@@ -154,6 +154,11 @@ 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://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/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/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>
</tr> </tr>
</tbody> </tbody>
</table> </table>

12
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "antares", "name": "antares",
"version": "0.7.29-beta.2", "version": "0.7.31-beta.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "antares", "name": "antares",
"version": "0.7.29-beta.2", "version": "0.7.31-beta.0",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -42,7 +42,6 @@
"node-firebird": "~1.1.8", "node-firebird": "~1.1.8",
"node-loader": "~2.0.0", "node-loader": "~2.0.0",
"pg": "~8.11.5", "pg": "~8.11.5",
"pg-connection-string": "~2.5.0",
"pg-query-stream": "~4.2.3", "pg-query-stream": "~4.2.3",
"pgsql-ast-parser": "~7.2.1", "pgsql-ast-parser": "~7.2.1",
"pinia": "~2.1.7", "pinia": "~2.1.7",
@@ -12142,10 +12141,6 @@
"license": "MIT", "license": "MIT",
"optional": true "optional": true
}, },
"node_modules/pg-connection-string": {
"version": "2.5.0",
"license": "MIT"
},
"node_modules/pg-cursor": { "node_modules/pg-cursor": {
"version": "2.10.3", "version": "2.10.3",
"license": "MIT", "license": "MIT",
@@ -24507,9 +24502,6 @@
"version": "1.1.1", "version": "1.1.1",
"optional": true "optional": true
}, },
"pg-connection-string": {
"version": "2.5.0"
},
"pg-cursor": { "pg-cursor": {
"version": "2.10.3", "version": "2.10.3",
"requires": {} "requires": {}

View File

@@ -1,7 +1,7 @@
{ {
"name": "antares", "name": "antares",
"productName": "Antares", "productName": "Antares",
"version": "0.7.29-beta.2", "version": "0.7.31-beta.0",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.", "description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT", "license": "MIT",
"repository": "https://github.com/antares-sql/antares.git", "repository": "https://github.com/antares-sql/antares.git",
@@ -151,7 +151,6 @@
"node-firebird": "~1.1.8", "node-firebird": "~1.1.8",
"node-loader": "~2.0.0", "node-loader": "~2.0.0",
"pg": "~8.11.5", "pg": "~8.11.5",
"pg-connection-string": "~2.5.0",
"pg-query-stream": "~4.2.3", "pg-query-stream": "~4.2.3",
"pgsql-ast-parser": "~7.2.1", "pgsql-ast-parser": "~7.2.1",
"pinia": "~2.1.7", "pinia": "~2.1.7",

View File

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

View File

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

View File

@@ -57,6 +57,7 @@ export interface ConnectionParams {
cert?: string; cert?: string;
key?: string; key?: string;
ca?: string; ca?: string;
connString?: string;
untrustedConnection: boolean; untrustedConnection: boolean;
ciphers?: string; ciphers?: string;
ssh: boolean; ssh: boolean;
@@ -159,6 +160,13 @@ export interface TableForeign {
oldName?: string; oldName?: string;
} }
export interface TableCheck {
// eslint-disable-next-line camelcase
_antares_id?: string;
name: string;
clause: string;
}
export interface CreateTableParams { export interface CreateTableParams {
/** Connection UID */ /** Connection UID */
uid?: string; uid?: string;
@@ -166,6 +174,7 @@ export interface CreateTableParams {
fields: TableField[]; fields: TableField[];
foreigns: TableForeign[]; foreigns: TableForeign[];
indexes: TableIndex[]; indexes: TableIndex[];
checks?: TableCheck[];
options: TableOptions; options: TableOptions;
} }
@@ -193,6 +202,11 @@ export interface AlterTableParams {
changes: TableForeign[]; changes: TableForeign[];
deletions: TableForeign[]; deletions: TableForeign[];
}; };
checkChanges?: {
additions: TableCheck[];
changes: TableCheck[];
deletions: TableCheck[];
};
options: TableOptions; options: TableOptions;
} }

View File

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

View File

@@ -26,6 +26,7 @@ export default (connections: Record<string, antares.Client>) => {
user: conn.user, user: conn.user,
password: conn.password, password: conn.password,
readonly: conn.readonly, readonly: conn.readonly,
connectionString: conn.connString,
database: '', database: '',
schema: '', schema: '',
databasePath: '', databasePath: '',
@@ -122,6 +123,7 @@ export default (connections: Record<string, antares.Client>) => {
password: conn.password, password: conn.password,
application_name: 'Antares SQL', application_name: 'Antares SQL',
readonly: conn.readonly, readonly: conn.readonly,
connectionString: conn.connString,
database: '', database: '',
schema: '', schema: '',
databasePath: '', databasePath: '',

View File

@@ -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) => { ipcMain.handle('get-table-ddl', async (event, params) => {
if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' }; if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' };

View File

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

View File

@@ -1024,7 +1024,7 @@ export class FirebirdSQLClient extends BaseClient {
alias: string; alias: string;
} }
this._logger({ cUid: this._cUid, sql }); this._logger({ cUid: this._cUid, content: sql, level: 'query' });
args = { args = {
nest: false, nest: false,

View File

@@ -161,6 +161,8 @@ export class MySQLClient extends BaseClient {
this._ssh = new SSH2Promise({ this._ssh = new SSH2Promise({
...this._params.ssh, ...this._params.ssh,
reconnect: true,
reconnectTries: 3,
debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null
}); });
@@ -354,10 +356,21 @@ export class MySQLClient extends BaseClient {
if (this._params.schema) if (this._params.schema)
filteredDatabases = filteredDatabases.filter(db => db.Database === this._params.schema); filteredDatabases = filteredDatabases.filter(db => db.Database === this._params.schema);
const { rows: functions } = await this.raw('SHOW FUNCTION STATUS'); /* eslint-disable @typescript-eslint/no-explicit-any */
const { rows: procedures } = await this.raw('SHOW PROCEDURE STATUS'); let functions: any[] = [];
// eslint-disable-next-line @typescript-eslint/no-explicit-any let procedures: any[] = [];
let schedulers: 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 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`'); const { rows } = await this.raw('SELECT *, EVENT_SCHEMA AS `Db`, EVENT_NAME AS `Name` FROM information_schema.`EVENTS`');
@@ -678,6 +691,34 @@ export class MySQLClient extends BaseClient {
return rows.length ? rows[0].count : 0; 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 }) { async getTableOptions ({ schema, table }: { schema: string; table: string }) {
/* eslint-disable camelcase */ /* eslint-disable camelcase */
interface TableOptionsResult { interface TableOptionsResult {
@@ -854,11 +895,13 @@ export class MySQLClient extends BaseClient {
fields, fields,
foreigns, foreigns,
indexes, indexes,
checks,
options options
} = params; } = params;
const newColumns: string[] = []; const newColumns: string[] = [];
const newIndexes: string[] = []; const newIndexes: string[] = [];
const newForeigns: string[] = []; const newForeigns: string[] = [];
const newChecks: string[] = [];
let sql = `CREATE TABLE \`${schema}\`.\`${options.name}\``; let sql = `CREATE TABLE \`${schema}\`.\`${options.name}\``;
@@ -899,7 +942,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}`); 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); return await this.raw(sql);
} }
@@ -913,6 +962,7 @@ export class MySQLClient extends BaseClient {
changes, changes,
indexChanges, indexChanges,
foreignChanges, foreignChanges,
checkChanges,
options options
} = params; } = params;
@@ -920,6 +970,7 @@ export class MySQLClient extends BaseClient {
const alterColumnsAdd: string[] = []; const alterColumnsAdd: string[] = [];
const alterColumnsChange: string[] = []; const alterColumnsChange: string[] = [];
const alterColumnsDrop: string[] = []; const alterColumnsDrop: string[] = [];
const alterQueryes: string[] = [];
// OPTIONS // OPTIONS
if ('comment' in options) alterColumnsChange.push(`COMMENT='${options.comment}'`); if ('comment' in options) alterColumnsChange.push(`COMMENT='${options.comment}'`);
@@ -965,6 +1016,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}`); 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 // CHANGE FIELDS
changes.forEach(change => { changes.forEach(change => {
const typeInfo = this.getTypeInfo(change.type); const typeInfo = this.getTypeInfo(change.type);
@@ -976,9 +1033,9 @@ export class MySQLClient extends BaseClient {
${change.zerofill ? 'ZEROFILL' : ''} ${change.zerofill ? 'ZEROFILL' : ''}
${change.nullable ? 'NULL' : 'NOT NULL'} ${change.nullable ? 'NULL' : 'NOT NULL'}
${change.autoIncrement ? 'AUTO_INCREMENT' : ''} ${change.autoIncrement ? 'AUTO_INCREMENT' : ''}
${change.collation ? `COLLATE ${change.collation}` : ''}
${change.default !== null ? `DEFAULT ${change.default || '\'\''}` : ''} ${change.default !== null ? `DEFAULT ${change.default || '\'\''}` : ''}
${change.comment ? `COMMENT '${change.comment}'` : ''} ${change.comment ? `COMMENT '${change.comment}'` : ''}
${change.collation ? `COLLATE ${change.collation}` : ''}
${change.onUpdate ? `ON UPDATE ${change.onUpdate}` : ''} ${change.onUpdate ? `ON UPDATE ${change.onUpdate}` : ''}
${change.after ? `AFTER \`${change.after}\`` : 'FIRST'}`); ${change.after ? `AFTER \`${change.after}\`` : 'FIRST'}`);
}); });
@@ -1009,6 +1066,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}`); 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 // DROP FIELDS
deletions.forEach(deletion => { deletions.forEach(deletion => {
alterColumnsDrop.push(`DROP COLUMN \`${deletion.name}\``); alterColumnsDrop.push(`DROP COLUMN \`${deletion.name}\``);
@@ -1027,7 +1091,11 @@ export class MySQLClient extends BaseClient {
alterColumnsDrop.push(`DROP FOREIGN KEY \`${deletion.constraintName}\``); 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 (alterColumnsAdd.length) alterQueryes.push(sql+alterColumnsAdd.join(', '));
if (alterColumnsChange.length) alterQueryes.push(sql+alterColumnsChange.join(', ')); if (alterColumnsChange.length) alterQueryes.push(sql+alterColumnsChange.join(', '));
if (alterColumnsDrop.length) alterQueryes.push(sql+alterColumnsDrop.join(', ')); if (alterColumnsDrop.length) alterQueryes.push(sql+alterColumnsDrop.join(', '));
@@ -1667,7 +1735,7 @@ export class MySQLClient extends BaseClient {
} }
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) { 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 = { args = {
nest: false, nest: false,
@@ -1703,9 +1771,10 @@ export class MySQLClient extends BaseClient {
connection.query({ sql: query, nestTables }).then(async ([response, fields]) => { connection.query({ sql: query, nestTables }).then(async ([response, fields]) => {
timeStop = new Date(); timeStop = new Date();
const queryResult = response; 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 let remappedFields = fieldsArr
? fields.map(field => { ? fieldsArr.map(field => {
if (!field || Array.isArray(field)) if (!field || Array.isArray(field))
return undefined; return undefined;
@@ -1774,7 +1843,7 @@ export class MySQLClient extends BaseClient {
resolve({ resolve({
duration: timeStop.getTime() - timeStart.getTime(), 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, report: !Array.isArray(queryResult) ? queryResult : false,
fields: remappedFields, fields: remappedFields,
keys: keysArr keys: keysArr

View File

@@ -155,6 +155,7 @@ export class PostgreSQLClient extends BaseClient {
host: this._params.host, host: this._params.host,
port: this._params.port, port: this._params.port,
user: this._params.user, user: this._params.user,
connectionString: this._params.connectionString,
database: 'postgres' as string, database: 'postgres' as string,
password: this._params.password, password: this._params.password,
ssl: null as ConnectionOptions ssl: null as ConnectionOptions
@@ -168,6 +169,8 @@ export class PostgreSQLClient extends BaseClient {
try { try {
this._ssh = new SSH2Promise({ this._ssh = new SSH2Promise({
...this._params.ssh, ...this._params.ssh,
reconnect: true,
reconnectTries: 3,
debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null
}); });
@@ -1645,7 +1648,7 @@ export class PostgreSQLClient extends BaseClient {
} }
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) { 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 = { args = {
nest: false, nest: false,

View File

@@ -612,7 +612,7 @@ export class SQLiteClient extends BaseClient {
} }
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) { 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 = { args = {
nest: false, nest: false,

View File

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

View File

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

View File

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

View File

@@ -62,7 +62,7 @@
<button <button
class="btn btn-dark btn-sm mr-0" class="btn btn-dark btn-sm mr-0"
:disabled="isSaving" :disabled="isSaving"
:title="t('database.manageIndexes')" :title="t('database.manageForeignKeys')"
@click="showForeignModal" @click="showForeignModal"
> >
<BaseIcon <BaseIcon
@@ -72,6 +72,20 @@
/> />
<span>{{ t('database.foreignKeys') }}</span> <span>{{ t('database.foreignKeys') }}</span>
</button> </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" /> <div class="divider-vert py-3" />
@@ -218,11 +232,19 @@
:workspace="workspace" :workspace="workspace"
@hide="hideDdlModal" @hide="hideDdlModal"
/> />
<WorkspaceTabPropsTableChecksModal
v-if="isTableChecksModal"
:local-checks="localTableChecks"
:table="table"
:workspace="workspace"
@hide="hideTableChecksModal"
@checks-update="checksUpdate"
/>
</div> </div>
</template> </template>
<script setup lang="ts"> <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 { uidGen } from 'common/libs/uidGen';
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -232,6 +254,7 @@ import { useI18n } from 'vue-i18n';
import BaseIcon from '@/components/BaseIcon.vue'; import BaseIcon from '@/components/BaseIcon.vue';
import BaseLoader from '@/components/BaseLoader.vue'; import BaseLoader from '@/components/BaseLoader.vue';
import BaseSelect from '@/components/BaseSelect.vue'; import BaseSelect from '@/components/BaseSelect.vue';
import WorkspaceTabPropsTableChecksModal from '@/components/WorkspaceTabPropsTableChecksModal.vue';
import WorkspaceTabPropsTableDdlModal from '@/components/WorkspaceTabPropsTableDdlModal.vue'; import WorkspaceTabPropsTableDdlModal from '@/components/WorkspaceTabPropsTableDdlModal.vue';
import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue'; import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue';
import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue'; import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue';
@@ -273,13 +296,17 @@ const isLoading = ref(false);
const isSaving = ref(false); const isSaving = ref(false);
const isIndexesModal = ref(false); const isIndexesModal = ref(false);
const isForeignModal = ref(false); const isForeignModal = ref(false);
const isTableChecksModal = ref(false);
const isDdlModal = ref(false); const isDdlModal = ref(false);
const originalFields: Ref<TableField[]> = ref([]); const originalFields: Ref<TableField[]> = ref([]);
const localFields: Ref<TableField[]> = ref([]); const localFields: Ref<TableField[]> = ref([]);
const originalKeyUsage: Ref<TableForeign[]> = ref([]); const originalKeyUsage: Ref<TableForeign[]> = ref([]);
const localKeyUsage: Ref<TableForeign[]> = ref([]); const localKeyUsage: Ref<TableForeign[]> = ref([]);
const originalIndexes: Ref<TableIndex[]> = ref([]); const originalIndexes: Ref<TableIndex[]> = ref([]);
const localIndexes: 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 tableOptions: Ref<TableOptions> = ref(null);
const localOptions: Ref<TableOptions> = ref({} as TableOptions); const localOptions: Ref<TableOptions> = ref({} as TableOptions);
const lastTable = ref(null); const lastTable = ref(null);
@@ -307,6 +334,7 @@ const isChanged = computed(() => {
return JSON.stringify(originalFields.value) !== JSON.stringify(localFields.value) || return JSON.stringify(originalFields.value) !== JSON.stringify(localFields.value) ||
JSON.stringify(originalKeyUsage.value) !== JSON.stringify(localKeyUsage.value) || JSON.stringify(originalKeyUsage.value) !== JSON.stringify(localKeyUsage.value) ||
JSON.stringify(originalIndexes.value) !== JSON.stringify(localIndexes.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); JSON.stringify(tableOptions.value) !== JSON.stringify(localOptions.value);
}); });
@@ -430,6 +458,27 @@ const getFieldsData = async () => {
addNotification({ status: 'error', message: err.stack }); addNotification({ status: 'error', message: err.stack });
} }
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 });
}
}
isLoading.value = false; isLoading.value = false;
}; };
@@ -527,6 +576,33 @@ const saveChanges = async () => {
// Foreigns Deletions // Foreigns Deletions
foreignChanges.deletions = originalKeyUsage.value.filter(foreign => !localForeignIDs.includes(foreign._antares_id)); 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 // ALTER
const params = { const params = {
uid: props.connection.uid, uid: props.connection.uid,
@@ -543,6 +619,7 @@ const saveChanges = async () => {
deletions, deletions,
indexChanges, indexChanges,
foreignChanges, foreignChanges,
checkChanges,
options options
} as unknown as AlterTableParams; } as unknown as AlterTableParams;
@@ -583,6 +660,7 @@ const clearChanges = () => {
localFields.value = JSON.parse(JSON.stringify(originalFields.value)); localFields.value = JSON.parse(JSON.stringify(originalFields.value));
localIndexes.value = JSON.parse(JSON.stringify(originalIndexes.value)); localIndexes.value = JSON.parse(JSON.stringify(originalIndexes.value));
localKeyUsage.value = JSON.parse(JSON.stringify(originalKeyUsage.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)); localOptions.value = JSON.parse(JSON.stringify(tableOptions.value));
newFieldsCounter.value = 0; newFieldsCounter.value = 0;
}; };
@@ -702,6 +780,14 @@ const hideForeignModal = () => {
isForeignModal.value = false; isForeignModal.value = false;
}; };
const showTableChecksModal = () => {
isTableChecksModal.value = true;
};
const hideTableChecksModal = () => {
isTableChecksModal.value = false;
};
const showDdlModal = () => { const showDdlModal = () => {
isDdlModal.value = true; isDdlModal.value = true;
}; };
@@ -714,6 +800,10 @@ const foreignsUpdate = (foreigns: TableForeign[]) => {
localKeyUsage.value = foreigns; localKeyUsage.value = foreigns;
}; };
const checksUpdate = (checks: TableCheck[]) => {
localTableChecks.value = checks;
};
const saveContentListener = () => { const saveContentListener = () => {
const hasModalOpen = !!document.querySelectorAll('.modal.active').length; const hasModalOpen = !!document.querySelectorAll('.modal.active').length;
if (props.isSelected && !hasModalOpen && isChanged.value) 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

@@ -745,7 +745,7 @@ const saveFileAs = async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const result: any = await Application.showSaveDialog({ const result: any = await Application.showSaveDialog({
filters: [{ name: 'SQL', extensions: ['sql'] }], filters: [{ name: 'SQL', extensions: ['sql'] }],
defaultPath: (!queryName.value.includes('.sql') ? `${queryName.value}.sql` :queryName.value) || 'query.sql' defaultPath: (queryName.value !== undefined && !queryName.value.includes('.sql') ? `${queryName.value}.sql` : queryName.value) || 'query.sql'
}); });
if (result && !result.canceled) { if (result && !result.canceled) {

View File

@@ -284,7 +284,7 @@ const settingsStore = useSettingsStore();
const consoleStore = useConsoleStore(); const consoleStore = useConsoleStore();
const { getWorkspace } = useWorkspacesStore(); const { getWorkspace } = useWorkspacesStore();
const { dataTabLimit: pageSize, defaultCopyType } = storeToRefs(settingsStore); const { /* dataTabLimit: pageSize, */ defaultCopyType } = storeToRefs(settingsStore);
const { consoleHeight } = storeToRefs(consoleStore); const { consoleHeight } = storeToRefs(consoleStore);
@@ -357,28 +357,37 @@ const isSortable = computed(() => {
return fields.value.every(field => field.name); return fields.value.every(field => field.name);
}); });
const isHardSort = computed(() => { // const isHardSort = computed(() => {
return props.mode === 'table' && localResults.value.length === pageSize.value; // return props.mode === 'table' && localResults.value.length === pageSize.value;
}); // });
const sortedResults = computed(() => { const sortedResults = computed(() => {
if (currentSort.value[resultsetIndex.value] && !isHardSort.value) { // if (currentSort.value[resultsetIndex.value] && !isHardSort.value) {
const sortObj = currentSort.value[resultsetIndex.value]; // const sortObj = currentSort.value[resultsetIndex.value];
return [...localResults.value].sort((a: any, b: any) => { // return [...localResults.value].sort((a: any, b: any) => {
let modifier = 1; // const modifier = sortObj.dir === 'desc' ? -1 : 1;
let valA = typeof a[sortObj.field] === 'string' ? a[sortObj.field].toLowerCase() : a[sortObj.field]; // let valA = a[sortObj.field];
if (!isNaN(valA)) valA = Number(valA); // let valB = b[sortObj.field];
let valB = typeof b[sortObj.field] === 'string' ? b[sortObj.field].toLowerCase() : b[sortObj.field];
if (!isNaN(valB)) valB = Number(valB); // // Handle null values
if (sortObj.dir === 'desc') modifier = -1; // if (valA === null && valB !== null) return sortObj.dir === 'asc' ? -1 : 1;
if (valA < valB) return -1 * modifier; // if (valA !== null && valB === null) return sortObj.dir === 'asc' ? 1 : -1;
if (valA > valB) return 1 * modifier; // if (valA === null && valB === null) return 0;
return 0;
}); // valA = typeof valA === 'string' ? valA.toLowerCase() : valA;
} // valB = typeof valB === 'string' ? valB.toLowerCase() : valB;
else
return localResults.value; // 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)); const resultsWithRows = computed(() => props.results.filter(result => result.rows.length));
@@ -529,6 +538,7 @@ const closeContext = () => {
}; };
const showDeleteConfirmModal = (e: any) => { const showDeleteConfirmModal = (e: any) => {
if (e.code !== 'Delete') return;
if (e && e.path && ['INPUT', 'TEXTAREA', 'SELECT'].includes(e.path[0].tagName)) if (e && e.path && ['INPUT', 'TEXTAREA', 'SELECT'].includes(e.path[0].tagName))
return; return;
if (selectedRows.value.length === 0) return; if (selectedRows.value.length === 0) return;
@@ -818,12 +828,12 @@ const sort = (field: TableField) => {
}; };
} }
if (isHardSort.value) { // if (isHardSort.value) {
emit('hard-sort', { emit('hard-sort', {
field: currentSort.value[resultsetIndex.value].field, field: currentSort.value[resultsetIndex.value].field,
dir: currentSort.value[resultsetIndex.value].dir dir: currentSort.value[resultsetIndex.value].dir
}); });
} // }
}; };
const resetSort = () => { const resetSort = () => {

View File

@@ -126,6 +126,7 @@ export const enUS = {
insert: 'Insert', insert: 'Insert',
indexes: 'Indexes', indexes: 'Indexes',
foreignKeys: 'Foreign keys', foreignKeys: 'Foreign keys',
tableChecks: 'Table checks',
length: 'Length', length: 'Length',
unsigned: 'Unsigned', unsigned: 'Unsigned',
default: 'Default', default: 'Default',
@@ -190,12 +191,15 @@ export const enUS = {
addNewField: 'Add new field', addNewField: 'Add new field',
manageIndexes: 'Manage indexes', manageIndexes: 'Manage indexes',
manageForeignKeys: 'Manage foreign keys', manageForeignKeys: 'Manage foreign keys',
manageTableChecks: 'Manage table checks',
allowNull: 'Allow NULL', allowNull: 'Allow NULL',
zeroFill: 'Zero fill', zeroFill: 'Zero fill',
customValue: 'Custom value', customValue: 'Custom value',
onUpdate: 'On update', onUpdate: 'On update',
deleteField: 'Delete field', deleteField: 'Delete field',
createNewIndex: 'Create new index', createNewIndex: 'Create new index',
createNewCheck: 'Create new check',
checkClause: 'Check clause',
addToIndex: 'Add to index', addToIndex: 'Add to index',
createNewTable: 'Create new table', createNewTable: 'Create new table',
emptyTable: 'Empty table', emptyTable: 'Empty table',
@@ -205,6 +209,7 @@ export const enUS = {
emptyConfirm: 'Do you confirm to empty', emptyConfirm: 'Do you confirm to empty',
thereAreNoIndexes: 'There are no indexes', thereAreNoIndexes: 'There are no indexes',
thereAreNoForeign: 'There are no foreign keys', thereAreNoForeign: 'There are no foreign keys',
thereAreNoTableChecks: 'There are no table checks',
createNewForeign: 'Create new foreign key', createNewForeign: 'Create new foreign key',
referenceTable: 'Ref. table', referenceTable: 'Ref. table',
referenceField: 'Ref. field', referenceField: 'Ref. field',

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

View File

@@ -61,7 +61,17 @@ export const ruRU = {
actionSuccessful: '{action} успешно', actionSuccessful: '{action} успешно',
outputFormat: 'Формат вывода', outputFormat: 'Формат вывода',
singleFile: 'Один {ext} файл', singleFile: 'Один {ext} файл',
zipCompressedFile: 'ZIP сжатие {ext} файла' zipCompressedFile: 'ZIP сжатие {ext} файла',
include: 'Включая',
none: 'Нет',
singleQuote: 'Одинарная кавычка',
doubleQuote: 'Двойная кавычка',
copyName: 'Скопировать имя',
search: 'Поиск',
title: 'Название',
archive: 'Архив',
undo: 'Отменить',
moveTo: 'Переместить в'
}, },
connection: { connection: {
connectionName: 'Название соединения', connectionName: 'Название соединения',
@@ -96,7 +106,10 @@ export const ruRU = {
readOnlyMode: 'Режим только чтение', readOnlyMode: 'Режим только чтение',
untrustedConnection: 'Ненадежное соединение', untrustedConnection: 'Ненадежное соединение',
allConnections: 'Все соединения', allConnections: 'Все соединения',
searchForConnections: 'Поиск соединений' searchForConnections: 'Поиск соединений',
keepAliveInterval: 'Интервал поддержания соединения',
singleConnection: 'Одно соединение',
connection: 'Соединение'
}, },
database: { database: {
schema: 'Схема', schema: 'Схема',
@@ -255,7 +268,16 @@ export const ruRU = {
sqlExportOptions: 'Опции SQL экспорта', sqlExportOptions: 'Опции SQL экспорта',
targetTable: 'Целевая таблица', targetTable: 'Целевая таблица',
importQueryErrors: 'Внимание: {n} ошибка возникла | Внимание: {n} ошибок произошло', importQueryErrors: 'Внимание: {n} ошибка возникла | Внимание: {n} ошибок произошло',
executedQueries: '{n} запрос выполнен | {n} запросов выполнено' executedQueries: '{n} запрос выполнен | {n} запросов выполнено',
insert: 'Вставить',
materializedview: 'Материализованное представление | Материализованные представления',
exportTable: 'Экспорт таблицы',
createNewMaterializedView: 'Создать новое материализованное представление',
newMaterializedView: 'Новое материализованное представление',
switchDatabase: 'Переключить базу данных',
searchForElements: 'Поиск элементов',
searchForSchemas: 'Поиск схем',
savedQueries: 'Сохранённые запросы'
}, },
application: { application: {
settings: 'Настройки', settings: 'Настройки',
@@ -313,9 +335,9 @@ export const ruRU = {
previousTab: 'Предыдущая вкладка', previousTab: 'Предыдущая вкладка',
selectTabNumber: 'Выбрать вкладку под номером {param}', selectTabNumber: 'Выбрать вкладку под номером {param}',
toggleConsole: 'Переключиться на консоль', toggleConsole: 'Переключиться на консоль',
addShortcut: 'Добавить горячие клавиши', addShortcut: 'Добавить горячую клавишу',
editShortcut: 'Изменить горячие клавиши', editShortcut: 'Изменить горячую клавишу',
deleteShortcut: 'Удалить горячие клавиши', deleteShortcut: 'Удалить горячую клавишу',
restoreDefaults: 'Восстановить по-умолчанию', restoreDefaults: 'Восстановить по-умолчанию',
restoreDefaultsQuestion: 'Вы подтверждаете восстановление значений по-умолчанию?', restoreDefaultsQuestion: 'Вы подтверждаете восстановление значений по-умолчанию?',
registerAShortcut: 'Зарегистрировать горячие клавиши', registerAShortcut: 'Зарегистрировать горячие клавиши',
@@ -329,13 +351,14 @@ export const ruRU = {
openFilter: 'Открыть фильтр', openFilter: 'Открыть фильтр',
nextResultsPage: 'Следующая страница', nextResultsPage: 'Следующая страница',
previousResultsPage: 'Предыдущая страница', previousResultsPage: 'Предыдущая страница',
editFolder: 'Изменить директорию', editFolder: 'Изменить папку',
folderName: 'Название директории', folderName: 'Название папки',
deleteFolder: 'Удалить директорию', deleteFolder: 'Удалить папки',
editConnectionAppearance: 'Изменить внешний вид соединения', editConnectionAppearance: 'Изменить внешний вид соединения',
defaultCopyType: 'Тип копирования по-умолчанию', defaultCopyType: 'Тип копирования по-умолчанию',
showTableSize: 'Показывать размер таблицы в сайдбаре', showTableSize: 'Показывать размер таблицы в сайдбаре',
showTableSizeDescription: 'Только MySQL/MariaDB. Включение этого параметра может повлиять на производительность схемы с большим количеством таблиц.', showTableSizeDescription:
'Только MySQL/MariaDB. Включение этого параметра может повлиять на производительность схемы с большим количеством таблиц.',
searchForSchemas: 'Поиск схем', searchForSchemas: 'Поиск схем',
searchForElements: 'Поиск элементов', searchForElements: 'Поиск элементов',
switchSearchMethod: 'Переключить способ поиска', switchSearchMethod: 'Переключить способ поиска',
@@ -343,7 +366,49 @@ export const ruRU = {
closeOtherTabs: 'Закрыть остальные вкладки', closeOtherTabs: 'Закрыть остальные вкладки',
closeTabsToLeft: 'Закрыть вкладки слева', closeTabsToLeft: 'Закрыть вкладки слева',
closeTabsToRight: 'Закрыть вкладки справа', 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: { faker: {
address: 'Адрес', address: 'Адрес',

View File

@@ -16,5 +16,7 @@ export const localesNames: Record<string, string> = {
'nl-NL': 'Nederlands', 'nl-NL': 'Nederlands',
'ca-ES': 'Català', 'ca-ES': 'Català',
'cs-CZ': 'Čeština', '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

@@ -44,6 +44,15 @@ ipcRenderer.on('unhandled-exception', (event, error) => {
date: new Date() 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 // IPC query logs
ipcRenderer.on('query-log', (event, logRecord: QueryLog) => { ipcRenderer.on('query-log', (event, logRecord: QueryLog) => {

View File

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

View File

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

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

View File

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

View File

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