Compare commits

...

229 Commits

Author SHA1 Message Date
SPRINX0\prochazka 6bd81cbff5 restore table - comments 2025-12-01 12:17:00 +01:00
SPRINX0\prochazka b912190c5e delete part of restore script 2025-12-01 12:07:44 +01:00
SPRINX0\prochazka 8ae64a9dcf restore script - update 2025-12-01 11:06:18 +01:00
SPRINX0\prochazka d650d91d82 table restore script WIP 2025-12-01 10:08:00 +01:00
SPRINX0\prochazka d3322a4a15 Merge branch 'feature/table-backups' 2025-11-28 16:10:18 +01:00
SPRINX0\prochazka a65842e31f table backups 2025-11-28 16:07:36 +01:00
SPRINX0\prochazka 74fde66b51 lang texts 2025-11-28 15:37:34 +01:00
SPRINX0\prochazka c3ea155a7b refresh database options 2025-11-28 15:35:38 +01:00
Jan Prochazka c4b81e3d2c Merge pull request #1275 from dbgate/feature/settings-tab
Feature/settings tab
2025-11-28 13:59:41 +01:00
Stela Augustinova 6f6ed1a741 Remove unused tip styles from various settings components 2025-11-28 13:26:45 +01:00
Stela Augustinova 311680c090 Add commands for viewing application logs and managing plugins; update settings tab integration 2025-11-28 13:23:02 +01:00
SPRINX0\prochazka 5e54aa553a skip incremental analysis test for postgres 2025-11-28 12:47:59 +01:00
SPRINX0\prochazka 6913970830 postgresql primary key loading optimalization 2025-11-28 12:32:18 +01:00
Jan Prochazka 014e453e57 removed ttable incremental analysis for postgres 2025-11-28 12:13:32 +01:00
Jan Prochazka 25b5341f76 fix tests 2025-11-28 11:54:24 +01:00
SPRINX0\prochazka 1df51f9609 skip incremental analysis check 2025-11-28 11:01:22 +01:00
Jan Prochazka 65d13189b3 postgres analyser fixed - broken loading FKs in incremental analysis 2025-11-28 10:24:53 +01:00
Jan Prochazka 0913011120 test fix 2025-11-28 08:21:04 +01:00
Stela Augustinova 30ddc18eb1 Add ai settings component to SettingsTab 2025-11-27 16:35:45 +01:00
Jan Prochazka 697d755744 test fix 2025-11-27 16:25:24 +01:00
Jan Prochazka e3f23ddc79 fixed test 2025-11-27 15:44:31 +01:00
Jan Prochazka 094acc40e8 jest reporters 2025-11-27 15:13:28 +01:00
Jan Prochazka ebd4991de8 Revert "jest reporters"
This reverts commit d04a8fad4c.
2025-11-27 15:12:15 +01:00
Jan Prochazka d04a8fad4c jest reporters 2025-11-27 14:55:40 +01:00
CI workflows cb14bffc5a chore: auto-update github workflows 2025-11-27 13:48:04 +00:00
Jan Prochazka a4c4d17381 test reporters 2025-11-27 14:47:43 +01:00
Stela Augustinova 21eb27f6e3 Added new settings components, added wrapper to all setting components 2025-11-27 14:42:24 +01:00
Jan Prochazka abf0fc7942 incremental analysis in alter table tests 2025-11-27 14:06:48 +01:00
SPRINX0\prochazka c2703edfde prettier 2025-11-27 11:03:12 +01:00
SPRINX0\prochazka d14b90ab20 foreign key editor UX 2025-11-27 10:29:33 +01:00
SPRINX0\prochazka 48f4924932 prettier format 2025-11-27 09:29:39 +01:00
Stela Augustinova 765551988a Added keyboard shortcuts to settings tab 2025-11-27 09:23:36 +01:00
Stela Augustinova 4883eb0d1b Merge branch 'master' into feature/settings-tab 2025-11-27 09:12:34 +01:00
Stela Augustinova 06a9a93d1c Added translation tag for settings 2025-11-27 09:11:33 +01:00
SPRINX0\prochazka c92a0e1d43 fixed search in keyboard shortcuts #1273 2025-11-27 08:58:11 +01:00
Stela Augustinova c6b5ee164b Added settings tab and settings components 2025-11-26 16:21:07 +01:00
SPRINX0\prochazka c65075f887 v6.7.2-alpha.1 2025-11-26 14:43:54 +01:00
SPRINX0\prochazka a1f678a3a1 additional connnection options for dbmodel 2025-11-26 14:43:18 +01:00
Jan Prochazka fe3fefaa4e Merge pull request #1272 from dbgate/feature/translation4
Feature/translation4
2025-11-26 14:12:14 +01:00
Jan Prochazka 3ccebcb0d1 Merge pull request #1271 from dbgate/feature/translation-script
Feature/translation script
2025-11-26 14:10:01 +01:00
Jan Prochazka dbbae0eef2 Merge pull request #1270 from dbgate/feature/columns-filters-panel-visibility
Feature/columns filters panel visibility
2025-11-26 09:54:50 +01:00
Stela Augustinova f11c4881f3 Update gitinore 2025-11-25 16:08:36 +01:00
Stela Augustinova 6398c6d7ce Added new translations 2025-11-25 16:03:55 +01:00
Stela Augustinova 973ce8c3a7 Load OpenAI API key 2025-11-25 16:02:44 +01:00
Stela Augustinova d971869283 Add collapsed left column store for SQL editor settings 2025-11-25 15:17:16 +01:00
SPRINX0\prochazka 987002b8f3 v6.7.1 2025-11-25 14:58:33 +01:00
SPRINX0\prochazka f73fe495a5 changelog 2025-11-25 14:57:56 +01:00
Stela Augustinova fe7b0e2bc7 Add translation script using OpenAI for missing keys (not finished) 2025-11-25 14:38:23 +01:00
Stela Augustinova 23937c54e0 Added checkbox to hide columns/filters panel by default 2025-11-25 13:37:19 +01:00
SPRINX0\prochazka b3d0fd9d2f SYNC: fixed E2e test 2025-11-25 11:09:40 +00:00
SPRINX0\prochazka 497aaf6143 v6.7.1-premium-beta.5 2025-11-25 10:34:09 +01:00
SPRINX0\prochazka 9d6db3a93b v6.7.1-beta.4 2025-11-25 10:33:47 +01:00
CI workflows 8a6f3e6809 chore: auto-update github workflows 2025-11-25 09:22:33 +00:00
CI workflows 6c419716a4 Update pro ref 2025-11-25 09:22:15 +00:00
SPRINX0\prochazka d1a769205c SYNC: support additional objects in team files 2025-11-25 09:22:02 +00:00
Stela Augustinova b784e342c9 Translation - added translation tags for import/export, connection tab 2025-11-25 10:07:41 +01:00
CI workflows 0d82fd51c7 chore: auto-update github workflows 2025-11-25 08:21:06 +00:00
CI workflows 3b4d905485 Update pro ref 2025-11-25 08:20:50 +00:00
SPRINX0\prochazka 53c63f0f4b SYNC: diagrams supported in team files 2025-11-25 08:20:39 +00:00
SPRINX0\prochazka 5553e3cd8d SYNC: Handle error when saving to team files 2025-11-24 16:35:08 +00:00
Stela Augustinova 1e195e07e0 Translation - added translation tags for import/export 2025-11-24 17:02:34 +01:00
Stela Augustinova b6f0e15951 Translation - add translation tags for logs 2025-11-24 16:48:29 +01:00
Stela Augustinova da224303fe Translation - added translation tags for widgets 2025-11-24 16:29:29 +01:00
SPRINX0\prochazka 67ee130a9e japanese localization 2025-11-24 16:20:59 +01:00
CI workflows 18d908fa63 chore: auto-update github workflows 2025-11-24 14:40:35 +00:00
CI workflows c61f58854e Update pro ref 2025-11-24 14:40:16 +00:00
SPRINX0\prochazka f789ecd2f1 SYNC: japanese settings 2025-11-24 14:40:04 +00:00
CI workflows 1fdc30804a chore: auto-update github workflows 2025-11-24 14:31:03 +00:00
CI workflows 5ba10d0acb Update pro ref 2025-11-24 14:30:50 +00:00
SPRINX0\prochazka 12803d8154 SYNC: admin settings 2025-11-24 14:30:38 +00:00
CI workflows 36c391ccff chore: auto-update github workflows 2025-11-24 14:27:45 +00:00
CI workflows 765fb6297c Update pro ref 2025-11-24 14:27:06 +00:00
SPRINX0\prochazka 66255769ad SYNC: support for browser default language 2025-11-24 14:26:54 +00:00
CI workflows 04a8d38641 chore: auto-update github workflows 2025-11-24 14:20:00 +00:00
CI workflows 859d020031 Update pro ref 2025-11-24 14:19:44 +00:00
SPRINX0\prochazka 3c541117d0 SYNC: change language for Team Premium 2025-11-24 14:19:33 +00:00
SPRINX0\prochazka 80ca2e5215 Add the LANG environment variable for the web version. #1266 2025-11-24 14:26:25 +01:00
SPRINX0\prochazka 19f2aa2997 smaller upgrade button #1244 2025-11-24 10:57:57 +01:00
Jan Prochazka ec657f30c7 Merge pull request #1268 from dbgate/feature/sort-sql
Feature/sort sql
2025-11-24 09:04:06 +01:00
SPRINX0\prochazka 7e84d495f5 sort by fix 2025-11-24 09:02:46 +01:00
SPRINX0\prochazka c3baedd93c sort tables by size/rowCount 2025-11-24 08:58:49 +01:00
SPRINX0\prochazka ae9676f744 sql object sort WIP 2025-11-21 16:37:12 +01:00
SPRINX0\prochazka 7ec156a5d1 table rows, table size in Oracle 2025-11-21 16:19:51 +01:00
SPRINX0\prochazka b80cbea1bc show mongo collection sizes #552 2025-11-21 16:07:27 +01:00
SPRINX0\prochazka 4600fa9f32 Show table size fo MySQL and Postgres #552 2025-11-21 15:56:26 +01:00
SPRINX0\prochazka 6e0b3e5cdc fixed: Check updates option no longer available in 6.7.0 #1263 2025-11-21 15:18:00 +01:00
SPRINX0\prochazka 519ff87f5d Merge branch 'feature/mongo-legacy' 2025-11-21 12:57:31 +01:00
SPRINX0\prochazka d4a363e37e v6.7.1-premium-beta.3 2025-11-21 10:46:26 +01:00
SPRINX0\prochazka a3cfc45fef legacy mongodb optimalization + test fix 2025-11-21 10:44:06 +01:00
SPRINX0\prochazka 60602e02d9 logging app language 2025-11-20 17:31:18 +01:00
SPRINX0\prochazka 44366f7872 v6.7.1-premium-beta.2 2025-11-20 16:26:40 +01:00
SPRINX0\prochazka 2f18d8c204 fixed package version 2025-11-20 16:26:26 +01:00
SPRINX0\prochazka 08efbee52b italian translation 2025-11-20 16:14:56 +01:00
SPRINX0\prochazka eac8d78c5d v6.7.1-premium-beta.1 2025-11-20 15:38:04 +01:00
SPRINX0\prochazka db73673374 Connection to MognoDB legacy 2025-11-20 15:35:09 +01:00
SPRINX0\prochazka 281cdb7264 "Show foreign key hints" showing only in premium 2025-11-20 14:18:51 +01:00
SPRINX0\prochazka 101c80d820 fixed: A MERGE statement must be terminated by a semi-colon (;), but dbgate stripped it. #1257 2025-11-20 12:59:54 +01:00
SPRINX0\prochazka 1e06f65d9e portugese (brasil) translation 2025-11-19 18:16:59 +01:00
SPRINX0\prochazka eea85709ed fixed error in auth login 2025-11-19 17:03:22 +01:00
SPRINX0\prochazka cbca974529 v6.7.0 2025-11-19 14:22:56 +01:00
SPRINX0\prochazka fc27f57580 changelog 2025-11-19 14:22:13 +01:00
SPRINX0\prochazka e50dd6606e es tgranslations fixed 2025-11-19 14:21:13 +01:00
SPRINX0\prochazka 8c9e232d65 improved zh translation 2025-11-19 13:57:52 +01:00
SPRINX0\prochazka ef98888394 fr translations improved 2025-11-19 13:53:46 +01:00
SPRINX0\prochazka e4b9ba34df german translation polished 2025-11-19 12:52:40 +01:00
SPRINX0\prochazka 169e0ec9df sorted translation keys 2025-11-19 12:22:03 +01:00
SPRINX0\prochazka 2779353a32 renamed loc key 2025-11-19 12:18:38 +01:00
SPRINX0\prochazka 35aabb987c cs translations 2025-11-19 12:15:37 +01:00
SPRINX0\prochazka 06f02070c7 language in webapp stored in local storage 2025-11-19 10:11:24 +01:00
SPRINX0\prochazka d138d3e786 changelog 2025-11-19 09:22:49 +01:00
SPRINX0\prochazka dbea68d33a Fix horizontal scrolling on macOS trackpad/Magic Mouse #1250 2025-11-19 08:45:32 +01:00
SPRINX0\prochazka 72bcabf615 v6.6.14-beta.6 2025-11-19 08:02:22 +01:00
SPRINX0\prochazka 5db68eac24 SYNC: added localizations tests (+screenshots) 2025-11-18 17:15:08 +00:00
SPRINX0\prochazka 7d9d88860e changelog 2025-11-18 17:34:27 +01:00
SPRINX0\prochazka 06c80ad982 Chinese localization #347 #705 #939 #1079 2025-11-18 16:16:39 +01:00
SPRINX0\prochazka c4335527f8 changelog WIP 2025-11-18 16:15:09 +01:00
SPRINX0\prochazka 90d27a2ad8 v6.6.14-premium-beta.6 2025-11-18 15:27:08 +01:00
SPRINX0\prochazka 93fd0a9af0 v6.6.14-beta.5 2025-11-18 15:26:52 +01:00
SPRINX0\prochazka 987b0aeb41 es treanslation in settings 2025-11-18 15:26:38 +01:00
SPRINX0\prochazka 8dc5ac0b25 v6.6.14-beta.4 2025-11-18 15:23:25 +01:00
SPRINX0\prochazka d310a47523 v6.6.14-premium-beta.3 2025-11-18 15:23:14 +01:00
SPRINX0\prochazka bd8fa3776d es translation + fixed language change 2025-11-18 15:22:39 +01:00
SPRINX0\prochazka 305796af53 spanish translation 2025-11-18 14:56:38 +01:00
SPRINX0\prochazka 60c10a69a3 french translation 2025-11-18 14:41:38 +01:00
SPRINX0\prochazka c8aad9839f v6.6.14-premium-beta.2 2025-11-18 14:19:48 +01:00
SPRINX0\prochazka 64016a1326 v6.6.13-beta.1 2025-11-18 14:19:48 +01:00
SPRINX0\prochazka a489c7ad8e added german translation 2025-11-18 14:19:48 +01:00
Jan Prochazka afb9ba7ad6 Merge pull request #1259 from dbgate/feature/electron-translation
Feature/electron translation
2025-11-18 14:02:43 +01:00
SPRINX0\prochazka b1de5b1120 fixed command palette 2025-11-18 13:45:02 +01:00
SPRINX0\prochazka 144a23e89b fixed condition 2025-11-18 13:11:47 +01:00
SPRINX0\prochazka a6763a3e5d fixed main menu 2025-11-18 13:05:22 +01:00
SPRINX0\prochazka f047ec787a translated electron menu 2025-11-18 12:29:48 +01:00
Stela Augustinova d80c368ccb translation- tabs panel, menu 2025-11-18 10:34:44 +01:00
SPRINX0\prochazka 9b60173b8c horizontal menu translation 2025-11-18 10:14:36 +01:00
SPRINX0\prochazka 8556974ef1 translation WIP 2025-11-18 09:25:39 +01:00
Stela Augustinova edf9f3a2be translation - settings, menu 2025-11-18 09:25:01 +01:00
SPRINX0\prochazka 7bb9414be8 electron menu translation WIP 2025-11-18 09:20:56 +01:00
SPRINX0\prochazka 6e439adb51 changelog 2025-11-18 08:05:19 +01:00
Jan Prochazka f6b783e74a SYNC: fixed paste license key 2025-11-17 06:43:17 +00:00
SPRINX0\prochazka 171b81461c SYNC: fixed: Export CSV broken #1080 2025-11-14 09:17:06 +00:00
SPRINX0\prochazka 83db76aed8 v6.6.12-premium-beta.6 2025-11-13 15:28:26 +01:00
Jan Prochazka e6d1bb7e5c Merge pull request #1258 from dbgate/feature/postgresql-export-bytea
Feature/postgresql export bytea
2025-11-13 15:27:28 +01:00
Stela Augustinova a3d9fe76d6 Merge branch 'master' into feature/postgresql-export-bytea 2025-11-13 13:44:11 +01:00
Stela Augustinova 0f4f154637 Add support for base64 image source from binary object 2025-11-13 13:37:33 +01:00
Stela Augustinova 7d112a208f Enhance binary data handling in modifyRow function to support ArrayBuffer conversion to base64 2025-11-13 13:12:51 +01:00
Stela Augustinova c867d39d8d Remove recordset call in MySQL driver 2025-11-13 10:26:12 +01:00
Stela Augustinova 83b6c939f7 Test binary - added engine label 2025-11-13 10:10:33 +01:00
Stela Augustinova e1e4eb5d6f Added binary data types for engines 2025-11-13 09:40:05 +01:00
Stela Augustinova a14c08f122 Handle binary data in load cell from file by converting Buffer to base64 2025-11-12 17:03:35 +01:00
SPRINX0\prochazka 5fd50dcf45 SYNC: fix - license in pro widget 2025-11-12 15:40:48 +00:00
SPRINX0\prochazka b2ac4ee245 SYNC: CSV parameters 2025-11-12 10:22:12 +00:00
SPRINX0\prochazka 0ad7c0546b CSV for MS Excel export 2025-11-12 10:59:50 +01:00
SPRINX0\prochazka 748381fef3 v6.6.12-premium-beta.5 2025-11-12 08:50:46 +01:00
SPRINX0\prochazka 7eb9e42210 SYNC: load pro widget in trial 2025-11-12 07:47:06 +00:00
SPRINX0\prochazka 36a4b67ef4 SYNC: promo widget in trial 2025-11-12 07:47:05 +00:00
Stela Augustinova 94b35e3d5f Enhance binary data handling by converting hex strings to base64 in filter parser and updating MongoDB driver for BinData support 2025-11-11 14:39:43 +01:00
Jan Prochazka c5aa82b76a Merge pull request #1252 from dbgate/feature/translation2
Feature/translation2
2025-11-11 08:50:22 +01:00
SPRINX0\prochazka c2920e195f optimalization 2025-11-11 08:25:56 +01:00
SPRINX0\prochazka 92a78a419e fix in translation 2025-11-11 08:17:42 +01:00
Stela Augustinova 4f27c2b852 translation-select language 2025-11-10 16:29:36 +01:00
Jan Prochazka ece5779b41 Merge pull request #1251 from dbgate/feature/electron-upgrade
Feature/electron upgrade
2025-11-10 16:26:48 +01:00
Stela Augustinova 167aaa8491 translation-commands 2025-11-10 16:14:32 +01:00
SPRINX0\prochazka de622b055b v6.6.12-premium-beta.3 2025-11-10 16:00:04 +01:00
SPRINX0\prochazka 7e88b930ec v6.6.12-beta.2 2025-11-10 15:25:51 +01:00
SPRINX0\prochazka c9adc2b852 update packages 2025-11-10 15:25:39 +01:00
SPRINX0\prochazka 91d3aba611 v6.6.12-beta.1 2025-11-10 15:12:03 +01:00
SPRINX0\prochazka 48bc11dcb5 try to upgrade electron #1243 2025-11-10 15:11:45 +01:00
Stela Augustinova 9ee0b32cac translation-db object 2025-11-10 14:42:20 +01:00
SPRINX0\prochazka 4b6b74604b Use SSL automatically for Azure SQL 2025-11-10 11:57:48 +01:00
SPRINX0\prochazka 7ad3fc4751 SYNC: changelog 2025-11-07 16:03:27 +00:00
SPRINX0\prochazka e604450cfb v6.6.11 2025-11-07 17:01:21 +01:00
SPRINX0\prochazka 9cfbc83896 v6.6.11-premium-beta.3 2025-11-07 16:30:25 +01:00
SPRINX0\prochazka 98b2f4ec35 v6.6.11-premium-beta.2 2025-11-07 16:29:51 +01:00
SPRINX0\prochazka 47e30f2daf v6.6.11-beta.1 2025-11-07 16:29:51 +01:00
SPRINX0\prochazka 6c21da6959 SYNC: themable starting screen 2025-11-07 15:28:49 +00:00
SPRINX0\prochazka c5fe71d390 SYNC: text 2025-11-07 15:04:39 +00:00
Stela Augustinova d14ffcb736 translation-data form,data grid 2025-11-07 14:49:00 +01:00
Stela Augustinova e694aca70b Refactor to use _val for translation handling across components 2025-11-07 14:40:52 +01:00
SPRINX0\prochazka 3c58cb1b9c SYNC: licensing page improvements 2025-11-07 13:33:01 +00:00
SPRINX0\prochazka dc452cdadf SYNC: disable commands on special pages 2025-11-07 12:10:13 +00:00
SPRINX0\prochazka e855365cbb SYNC: themable special page layout 2025-11-07 11:19:03 +00:00
SPRINX0\prochazka cffa288227 SYNC: fix - dont' show devtools 2025-11-07 09:26:26 +00:00
SPRINX0\prochazka 89ddced342 SYNC: disable commands when modal is opened 2025-11-07 09:25:18 +00:00
Jan Prochazka 7457328b59 v6.6.10 2025-11-06 22:34:02 +01:00
Jan Prochazka 44ff413810 changelog 2025-11-06 22:33:29 +01:00
SPRINX0\prochazka d174c2c2d8 v6.6.10-premium-beta.2 2025-11-06 16:44:43 +01:00
SPRINX0\prochazka 480f4c9a8c v6.6.10-beta.1 2025-11-06 16:44:35 +01:00
SPRINX0\prochazka 7474cc5d8a SYNC: fixed trial scenario 2025-11-06 15:43:56 +00:00
CI workflows bda5c4f5dd chore: auto-update github workflows 2025-11-06 14:37:33 +00:00
CI workflows 4f5034c167 Update pro ref 2025-11-06 14:37:14 +00:00
SPRINX0\prochazka 9470db1f4d SYNC: fixed License fron environment variable is not refreshed #1245 2025-11-06 14:37:04 +00:00
Stela Augustinova dfeb910ac9 Enhance binary data handling by integrating modifyRow function in SQLite driver and helpers 2025-11-06 14:14:24 +01:00
SPRINX0\prochazka a5745795be SYNC: command palette fix 2025-11-06 12:43:04 +00:00
Stela Augustinova 98f2b5dd08 Enhance binary data handling in Oracle driver and adjust dumper for byte array values 2025-11-06 13:08:50 +01:00
SPRINX0\prochazka f642c7570e SYNC: fixed translating app object list 2025-11-06 12:07:54 +00:00
Stela Augustinova dca9ea24d7 Implement base64 encoding for binary data in SQL dumper and modify row handling in MySQL and MSSQL drivers 2025-11-06 12:30:48 +01:00
SPRINX0\prochazka 43fd7b6000 rowsAffected field added 2025-11-06 08:23:31 +01:00
Jan Prochazka 1553ec3bd4 Query result - added click-throught to returned data #1236 2025-11-05 18:35:33 +01:00
Stela Augustinova 37d54811e0 Enhance binary data handling in transformRow to serialize Buffer as base64 2025-11-05 16:07:14 +01:00
Stela Augustinova 0f2af6eb37 Add binary data handling in query tests with enhanced stream handler 2025-11-05 14:09:58 +01:00
SPRINX0\prochazka 91546228fa changed query workflow 2025-11-05 13:34:50 +01:00
SPRINX0\prochazka 5488ff06e0 _t 2025-11-05 13:34:50 +01:00
SPRINX0\prochazka ef7f050bc5 Show executed query on log #1236 2025-11-05 13:34:50 +01:00
SPRINX0\prochazka e5c94d9698 Merge branch 'feature/translation' 2025-11-05 12:18:23 +01:00
Stela Augustinova 4d3e0ac5d9 Merge branch 'master' into feature/translation 2025-11-05 11:56:51 +01:00
Stela Augustinova 0a2f0372be Enhance translation regex to support multiple default message formats 2025-11-05 11:49:21 +01:00
Stela Augustinova e378fc3cfb translation-table editor, query, table structure 2025-11-04 16:52:45 +01:00
SPRINX0\prochazka 75a1d74d9c handle changed current database for MS SQL #1237 2025-11-04 15:39:37 +01:00
SPRINX0\prochazka 1404685296 changing current DB handler for MySQL #1237 2025-11-04 15:20:21 +01:00
Stela Augustinova 0ebed9b46f Refactor dataCopy to avoid mutating original structure 2025-11-04 12:32:20 +01:00
SPRINX0\prochazka af69352361 SYNC: fixed references error 2025-11-04 08:09:30 +00:00
Jan Prochazka 840e3b861f fixed horizontal grid scroll on MacOS #453 2025-11-04 08:29:54 +01:00
Jan Prochazka a7cfe7fe04 fixed possible render error 2025-11-04 08:27:36 +01:00
SPRINX0\prochazka a324cf0fcd Column name collision resolving #1234 for postgres - commented out (not working) 2025-11-03 16:56:58 +01:00
SPRINX0\prochazka 0919f4c85b FEAT: column name collision resolving #1234 (MySQL)) 2025-11-03 16:30:56 +01:00
SPRINX0\prochazka fd4cc6a1e8 #1235 ability to load CSV files 2025-11-03 15:44:57 +01:00
Stela Augustinova d6ae3d4f16 Refactor binary data handling in SQL dumper and update test for binary insertion 2025-11-03 13:31:43 +01:00
Stela Augustinova 9c1819467a test binary data type 2025-11-03 09:17:11 +01:00
SPRINX0\prochazka 08410ef209 v6.6.9 2025-10-31 16:32:37 +01:00
SPRINX0\prochazka 6cd3242454 v6.6.9-premium-beta.1 2025-10-31 16:05:43 +01:00
CI workflows 986c1a7bc8 chore: auto-update github workflows 2025-10-31 15:05:12 +00:00
SPRINX0\prochazka a7703ec996 fix build 2025-10-31 16:04:46 +01:00
Stela Augustinova 82a4b2c769 translation-clipboard, exportMenu, macros, datagrid commands 2025-10-31 15:10:17 +01:00
SPRINX0\prochazka 9884ace309 fixed translations set during module startup - use __t 2025-10-30 10:37:06 +01:00
Stela Augustinova 70284ac440 translation-datagrid,filter,macros,newObject 2025-10-30 10:12:32 +01:00
Stela Augustinova 417334d140 Add base64 handling for binary data in filter and grid components 2025-10-29 15:08:57 +01:00
Stela Augustinova aa7fb74312 PostgreSQL export to SQL and XML bytea contents #1228 2025-10-29 12:22:13 +01:00
Stela Augustinova 8429067ae5 translation-connections,sqlObject,column,filter 2025-10-27 15:04:04 +01:00
Stela Augustinova c514a4d503 translation-settings,common 2025-10-27 09:33:26 +01:00
236 changed files with 14135 additions and 1839 deletions
+1
View File
@@ -109,6 +109,7 @@ jobs:
- name: Fix YML hashes
if: matrix.os == 'windows-2022'
run: |
yarn run fixYmlHashes
- name: Copy artifacts
run: |
+1
View File
@@ -105,6 +105,7 @@ jobs:
- name: Fix YML hashes
if: matrix.os == 'windows-2022'
run: |
yarn run fixYmlHashes
- name: Copy artifacts
run: |
+5 -2
View File
@@ -43,7 +43,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: 6195e103e1d45e4f59bade60df5dd1784f4e6c77
ref: 3b9ca48888d17d96806820c4e54bb047c18d6278
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
@@ -135,13 +135,16 @@ jobs:
endpoint: https://wus3.codesigning.azure.net/
trusted-signing-account-name: DbGate
certificate-profile-name: DbGate-Release
files-folder: app/dist
files-folder: ../dbgate-merged/app/dist
files-folder-filter: exe
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Fix YML hashes
if: matrix.os == 'windows-2022'
run: |
cd ..
cd dbgate-merged
yarn run fixYmlHashes
- name: Copy artifacts
run: |
+5 -2
View File
@@ -43,7 +43,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: 6195e103e1d45e4f59bade60df5dd1784f4e6c77
ref: 3b9ca48888d17d96806820c4e54bb047c18d6278
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
@@ -135,13 +135,16 @@ jobs:
endpoint: https://wus3.codesigning.azure.net/
trusted-signing-account-name: DbGate
certificate-profile-name: DbGate-Release
files-folder: app/dist
files-folder: ../dbgate-merged/app/dist
files-folder-filter: exe
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Fix YML hashes
if: matrix.os == 'windows-2022'
run: |
cd ..
cd dbgate-merged
yarn run fixYmlHashes
- name: Copy artifacts
run: |
+1
View File
@@ -108,6 +108,7 @@ jobs:
- name: Fix YML hashes
if: matrix.os == 'windows-2022'
run: |
yarn run fixYmlHashes
- name: Copy artifacts
run: |
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: 6195e103e1d45e4f59bade60df5dd1784f4e6c77
ref: 3b9ca48888d17d96806820c4e54bb047c18d6278
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: 6195e103e1d45e4f59bade60df5dd1784f4e6c77
ref: 3b9ca48888d17d96806820c4e54bb047c18d6278
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: 6195e103e1d45e4f59bade60df5dd1784f4e6c77
ref: 3b9ca48888d17d96806820c4e54bb047c18d6278
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
path: dbgate-pro
ref: 6195e103e1d45e4f59bade60df5dd1784f4e6c77
ref: 3b9ca48888d17d96806820c4e54bb047c18d6278
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
-18
View File
@@ -42,24 +42,6 @@ jobs:
run: |
cd packages/tools
yarn test:ci
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: integration-tests/result.json
action-name: Integration tests
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: packages/filterparser/result.json
action-name: Filter parser test results
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: packages/datalib/result.json
action-name: Datalib (perspectives) test results
services:
postgres-integr:
image: postgres
+1
View File
@@ -24,6 +24,7 @@ docker/plugins
.env.development.local
.env.test.local
.env.production.local
.env.translation
npm-debug.log*
yarn-debug.log*
+42
View File
@@ -8,6 +8,48 @@ Builds:
- linux - application for linux
- win - application for Windows
## 6.7.1
- ADDED: LANGUAGE environment variable for the web version. #1266
- ADDED: New localizations (Italian, Portugese (Brazil), Japanese)
- ADDED: Option to detect language from browser settings in web version
- FIXED: Check updates option no longer available in 6.7.0 #1263
- FIXED: A MERGE statement must be terminated by a semi-colon (;), but dbgate stripped it. #1257
- ADDED: Show table size #552
- ADDED: Sort tables by size and by row count
- ADDED: Connect to Legacy MongoDB (Premium) #540
- FIXED: Fixed problems in saving team files in Team Premium edition
- CHANGED: Files are by default saved to team folders in Team Premium edition
- ADDED: Other files types supported in Team Premium edition (diagrams, query design, perspectives, import/export jobs, shell scripts, database compare jobs)
## 6.7.0
- ADDED: Added localization support, now you can use DbGate in multiple languages (French, Spanish, German, Czech, Slovak, Simplified Chinese) #347 #705 #939 #1079
- CHANGED: Solved many issues with binary fields, huge performance improvements in binary fields processing
- FIXED: Export to CSV produces empty file #1247
- CHANGED: Upgraded electron to version 38 #1243
- FIXED: PostgreSQL export to SQL and XML doesn't include bytea field contents #1228
- FIXED: Export CSV broken #1080
- FIXED: Inconsistent handling of hex-like strings #680
- FIXED: Export mongodb binary cell as binary file #292
- CHANGED: SSL is used automatically for connections to Azure databases
- ADDED: New export formats CSV for Excel, TSV
- FIXED: Horizontal scrolling on macOS trackpad/Magic Mouse #1250
## 6.6.12
- FIXED: Cannot paste license key on Mac (special commands like copy/paste were disabled on license screen)
## 6.6.11
- FIXED: Fixed theming on application startup
- CHANGED: Improved licensing page
## 6.6.10
- FIXED: License from environment variable is not refreshed #1245
- FIXED: connection closing / reconnecting #1237
- ADDED: retain history across multiple queries #1236
- ADDED: load CSVs to temp tables #1235
- FIXED: Not possible to scroll the data view horizontally by pressing shift and scroll mouse middle button on Mac #453
- FIXED: Expired trial workflow (Premium)
- ADDED: Column name collision resolving #1234 (MySQL)
## 6.6.8
- CHANGED: Windows executable now uses Azure trusted signing certificate
- CHANGED: NPM packages now use GitHub OIDC provenance signing for better security
+1 -1
View File
@@ -128,7 +128,7 @@
"devDependencies": {
"copyfiles": "^2.2.0",
"cross-env": "^6.0.3",
"electron": "30.0.2",
"electron": "38.6.0",
"electron-builder": "25.1.8"
}
}
+41 -13
View File
@@ -31,6 +31,16 @@ let mainModule;
let appUpdateStatus = '';
let settingsJson = {};
function getTranslated(key) {
if (typeof key === 'string' && global.TRANSLATION_DATA?.[key]) {
return global.TRANSLATION_DATA?.[key];
}
if (typeof key?._transKey === 'string') {
return global.TRANSLATION_DATA?.[key._transKey] ?? key._transOptions?.defaultMessage;
}
return key;
}
process.on('uncaughtException', function (error) {
console.error('uncaughtException', error);
});
@@ -63,6 +73,7 @@ try {
let mainWindow;
let mainMenu;
let runCommandOnLoad = null;
let mainWindowMenuSet = false;
log.transports.file.level = 'debug';
autoUpdater.logger = log;
@@ -85,17 +96,22 @@ function formatKeyText(keyText) {
return keyText.replace('CtrlOrCommand+', 'Ctrl+');
}
function commandItem(item) {
function commandItem(item, disableAll = false) {
const id = item.command;
const command = commands[id];
if (item.skipInApp) {
return { skip: true };
}
if (!command) {
return { skip: true };
}
return {
id,
label: command ? command.menuName || command.toolbarName || command.name : id,
label: command
? getTranslated(command.menuName) || getTranslated(command.toolbarName) || getTranslated(command.name)
: id,
accelerator: formatKeyText(command ? command.keyText : undefined),
enabled: command ? command.enabled : false,
enabled: command ? command.enabled && (!disableAll || command.systemCommand) : false,
click() {
if (mainWindow) {
mainWindow.webContents.send('run-command', id);
@@ -107,14 +123,14 @@ function commandItem(item) {
};
}
function buildMenu() {
function buildMenu(disableAll = false) {
let template = _cloneDeepWith(mainMenuDefinition({ editMenu: true, isMac: isMac() }), item => {
if (item.divider) {
return { type: 'separator' };
}
if (item.command) {
return commandItem(item);
return commandItem(item, disableAll);
}
});
@@ -129,7 +145,7 @@ function buildMenu() {
{
label: 'DbGate',
submenu: [
commandItem({ command: 'about.show' }),
commandItem({ command: 'about.show' }, disableAll),
{ role: 'services' },
{ role: 'hide' },
{ role: 'hideOthers' },
@@ -145,22 +161,28 @@ function buildMenu() {
}
ipcMain.on('update-commands', async (event, arg) => {
commands = JSON.parse(arg);
const parsed = JSON.parse(arg);
commands = parsed.commands;
const isModalOpened = parsed.isModalOpened;
const dbgatePage = parsed.dbgatePage;
for (const key of Object.keys(commands)) {
const menu = mainMenu.getMenuItemById(key);
if (!menu) continue;
const command = commands[key];
// rebuild menu
if (menu.label != command.text || menu.accelerator != command.keyText) {
mainMenu = buildMenu();
if (global.TRANSLATION_DATA && (menu.label != command.text || menu.accelerator != command.keyText)) {
mainMenu = buildMenu(isModalOpened || !!dbgatePage);
Menu.setApplicationMenu(mainMenu);
// mainWindow.setMenu(mainMenu);
if (!mainWindowMenuSet) {
mainWindow.setMenu(mainMenu);
mainWindowMenuSet = true;
}
return;
}
menu.enabled = command.enabled;
menu.enabled = command.enabled && !isModalOpened && !dbgatePage;
}
});
ipcMain.on('quit-app', async (event, arg) => {
@@ -303,6 +325,12 @@ ipcMain.on('check-for-updates', async (event, url) => {
autoUpdater.autoDownload = false;
autoUpdater.checkForUpdates();
});
ipcMain.on('translation-data', async (event, arg) => {
global.TRANSLATION_DATA = JSON.parse(arg);
mainMenu = buildMenu();
Menu.setApplicationMenu(mainMenu);
mainWindow.setMenu(mainMenu);
});
function fillMissingSettings(value) {
const res = {
@@ -379,8 +407,8 @@ function createWindow() {
mainWindow.setFullScreen(true);
}
mainMenu = buildMenu();
mainWindow.setMenu(mainMenu);
// mainMenu = buildMenu();
// mainWindow.setMenu(mainMenu);
function loadMainWindow() {
const startUrl =
+15 -7
View File
@@ -1,6 +1,10 @@
module.exports = ({ editMenu, isMac }) => [
function _t(key, { defaultMessage, currentTranslations } = {}) {
return (currentTranslations || global.TRANSLATION_DATA)?.[key] || defaultMessage;
}
module.exports = ({ editMenu, isMac }, currentTranslations = null) => [
{
label: 'File',
label: _t('menu.file', { defaultMessage: 'File', currentTranslations }),
submenu: [
{ command: 'new.connection', hideDisabled: true },
{ command: 'new.sqliteDatabase', hideDisabled: true },
@@ -28,7 +32,7 @@ module.exports = ({ editMenu, isMac }) => [
},
editMenu
? {
label: 'Edit',
label: _t('menu.edit', { defaultMessage: 'Edit', currentTranslations }),
submenu: [
{ command: 'edit.undo' },
{ command: 'edit.redo' },
@@ -53,7 +57,7 @@ module.exports = ({ editMenu, isMac }) => [
// ],
// },
{
label: 'View',
label: _t('menu.view', { defaultMessage: 'View', currentTranslations }),
submenu: [
{ command: 'app.reload', hideDisabled: true },
{ command: 'app.toggleDevTools', hideDisabled: true },
@@ -72,10 +76,12 @@ module.exports = ({ editMenu, isMac }) => [
{ command: 'app.zoomIn', hideDisabled: true },
{ command: 'app.zoomOut', hideDisabled: true },
{ command: 'app.zoomReset', hideDisabled: true },
{ divider: true },
{ command: 'app.showLogs', hideDisabled: true },
],
},
{
label: 'Tools',
label: _t('menu.tools', { defaultMessage: 'Tools', currentTranslations }),
submenu: [
{ command: 'database.search', hideDisabled: true },
{ command: 'commandPalette.show', hideDisabled: true },
@@ -91,6 +97,8 @@ module.exports = ({ editMenu, isMac }) => [
{ divider: true },
{ command: 'app.exportConnections', hideDisabled: true },
{ command: 'app.importConnections', hideDisabled: true },
{ divider: true },
{ command: 'app.managePlugins', hideDisabled: true },
],
},
...(isMac
@@ -102,7 +110,7 @@ module.exports = ({ editMenu, isMac }) => [
]
: []),
{
label: 'Help',
label: _t('menu.help', { defaultMessage: 'Help', currentTranslations }),
submenu: [
{ command: 'app.openDocs', hideDisabled: true },
{ command: 'app.openWeb', hideDisabled: true },
@@ -114,7 +122,7 @@ module.exports = ({ editMenu, isMac }) => [
{ command: 'tabs.changelog', hideDisabled: true },
{ command: 'about.show', hideDisabled: true },
{ divider: true },
{ command: 'file.checkForUpdates', hideDisabled: true },
{ command: 'app.checkForUpdates', hideDisabled: true },
],
},
];
+279 -224
View File
@@ -16,9 +16,9 @@
ajv-keywords "^3.4.1"
"@electron/asar@^3.2.7":
version "3.2.17"
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.17.tgz#91d28087aad80d1a1c8cc4e667c6476edf50f949"
integrity sha512-OcWImUI686w8LkghQj9R2ynZ2ME693Ek6L1SiaAgqGKzBaTIZw3fHDqN82Rcl+EU1Gm9EgkJ5KLIY/q5DCRbbA==
version "3.4.1"
resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.4.1.tgz#4e9196a4b54fba18c56cd8d5cac67c5bdc588065"
integrity sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==
dependencies:
commander "^5.0.0"
glob "^7.1.6"
@@ -98,6 +98,18 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@isaacs/balanced-match@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29"
integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==
"@isaacs/brace-expansion@^5.0.0":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz#4b3dabab7d8e75a429414a96bd67bf4c1d13e0f3"
integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==
dependencies:
"@isaacs/balanced-match" "^4.0.1"
"@isaacs/cliui@^8.0.2":
version "8.0.2"
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
@@ -202,16 +214,23 @@
"@types/node" "*"
"@types/ms@*":
version "0.7.34"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433"
integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==
version "2.1.0"
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78"
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
"@types/node@*", "@types/node@^20.9.0":
version "20.12.10"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.10.tgz#8f0c3f12b0f075eee1fe20c1afb417e9765bef76"
integrity sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==
"@types/node@*":
version "24.10.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-24.10.0.tgz#6b79086b0dfc54e775a34ba8114dcc4e0221f31f"
integrity sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==
dependencies:
undici-types "~5.26.4"
undici-types "~7.16.0"
"@types/node@^22.7.7":
version "22.19.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.0.tgz#849606ef3920850583a4e7ee0930987c35ad80be"
integrity sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA==
dependencies:
undici-types "~6.21.0"
"@types/plist@^3.0.1":
version "3.0.5"
@@ -229,9 +248,9 @@
"@types/node" "*"
"@types/verror@^1.10.3":
version "1.10.10"
resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.10.tgz#d5a4b56abac169bfbc8b23d291363a682e6fa087"
integrity sha512-l4MM0Jppn18hb9xmM6wwD1uTdShpf9Pn80aXTStnK1C94gtPvJcV2FrDmbOQUAQfJ1cKZHktkQUDwEqaAKXMMg==
version "1.10.11"
resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.11.tgz#d3d6b418978c8aa202d41e5bb3483227b6ecc1bb"
integrity sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==
"@types/yauzl@^2.9.1":
version "2.10.3"
@@ -241,9 +260,9 @@
"@types/node" "*"
"@xmldom/xmldom@^0.8.8":
version "0.8.10"
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99"
integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==
version "0.8.11"
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz#b79de2d67389734c57c52595f7a7305e30c2d608"
integrity sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==
"@yarnpkg/lockfile@^1.1.0":
version "1.1.0"
@@ -263,14 +282,14 @@ agent-base@6, agent-base@^6.0.2:
debug "4"
agent-base@^7.1.0, agent-base@^7.1.2:
version "7.1.3"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1"
integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==
version "7.1.4"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8"
integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==
agentkeepalive@^4.2.1:
version "4.5.0"
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923"
integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
version "4.6.0"
resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a"
integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==
dependencies:
humanize-ms "^1.2.1"
@@ -303,9 +322,9 @@ ansi-regex@^5.0.1:
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
ansi-regex@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654"
integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==
version "6.2.2"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1"
integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
@@ -315,9 +334,9 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
color-convert "^2.0.1"
ansi-styles@^6.1.0:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
version "6.2.3"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041"
integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==
app-builder-bin@5.0.0-alpha.10:
version "5.0.0-alpha.10"
@@ -363,9 +382,9 @@ app-builder-lib@25.1.8:
temp-file "^3.4.0"
"aproba@^1.0.3 || ^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
version "2.1.0"
resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.1.0.tgz#75500a190313d95c64e871e7e4284c6ac219f0b1"
integrity sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==
are-we-there-yet@^3.0.0:
version "3.0.1"
@@ -395,10 +414,10 @@ async-exit-hook@^2.0.1:
resolved "https://registry.yarnpkg.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz#8bd8b024b0ec9b1c01cccb9af9db29bd717dfaf3"
integrity sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==
async@^3.2.3:
version "3.2.5"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66"
integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==
async@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce"
integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==
asynckit@^0.4.0:
version "0.4.0"
@@ -447,33 +466,33 @@ boolean@^3.0.1:
integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
version "1.1.12"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843"
integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
brace-expansion@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
version "2.0.2"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7"
integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==
dependencies:
balanced-match "^1.0.0"
braces@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
braces@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
fill-range "^7.0.1"
fill-range "^7.1.1"
buffer-crc32@~0.2.3:
version "0.2.13"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
buffer-equal-constant-time@1.0.1:
buffer-equal-constant-time@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
@@ -499,10 +518,10 @@ builder-util-runtime@9.2.10:
debug "^4.3.4"
sax "^1.2.4"
builder-util-runtime@9.2.5:
version "9.2.5"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.5.tgz#0afdffa0adb5c84c14926c7dd2cf3c6e96e9be83"
integrity sha512-HjIDfhvqx/8B3TDN4GbABQcgpewTU4LMRTQPkVpKYV3lsuxEJoIfvg09GyWTNmfVNSUAYf+fbTN//JX4TH20pg==
builder-util-runtime@9.3.1:
version "9.3.1"
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67"
integrity sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==
dependencies:
debug "^4.3.4"
sax "^1.2.4"
@@ -571,7 +590,15 @@ cacheable-request@^7.0.2:
normalize-url "^6.0.1"
responselike "^2.0.0"
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2:
call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
dependencies:
es-errors "^1.3.0"
function-bind "^1.1.2"
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -744,9 +771,9 @@ cross-env@^6.0.3:
cross-spawn "^7.0.0"
cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
version "6.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57"
integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
@@ -754,26 +781,19 @@ cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3, cross-spawn@^7.0.6:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
debug@^4.3.3:
version "4.4.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4:
version "4.4.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a"
integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==
dependencies:
ms "^2.1.3"
@@ -825,9 +845,9 @@ delegates@^1.0.0:
integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
detect-libc@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700"
integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==
version "2.1.2"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad"
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
detect-node@^2.0.4:
version "2.1.0"
@@ -878,9 +898,18 @@ dotenv-expand@^11.0.6:
dotenv "^16.4.5"
dotenv@^16.4.5:
version "16.4.7"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26"
integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==
version "16.6.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020"
integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==
dunder-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
dependencies:
call-bind-apply-helpers "^1.0.1"
es-errors "^1.3.0"
gopd "^1.2.0"
eastasianwidth@^0.2.0:
version "0.2.0"
@@ -936,11 +965,11 @@ electron-publish@25.1.7:
mime "^2.5.2"
electron-updater@^6.3.4:
version "6.3.4"
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.3.4.tgz#3934bc89875bb524c2cbbd11041114e97c0c2496"
integrity sha512-uZUo7p1Y53G4tl6Cgw07X1yF8Jlz6zhaL7CQJDZ1fVVkOaBfE2cWtx80avwDVi8jHp+I/FWawrMgTAeCCNIfAg==
version "6.6.2"
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.6.2.tgz#3e65e044f1a99b00d61e200e24de8e709c69ce99"
integrity sha512-Cr4GDOkbAUqRHP5/oeOmH/L2Bn6+FQPxVLZtPbcmKZC63a1F3uu5EefYOssgZXG3u/zBlubbJ5PJdITdMVggbw==
dependencies:
builder-util-runtime "9.2.5"
builder-util-runtime "9.3.1"
fs-extra "^10.1.0"
js-yaml "^4.1.0"
lazy-val "^1.0.5"
@@ -949,13 +978,13 @@ electron-updater@^6.3.4:
semver "^7.6.3"
tiny-typed-emitter "^2.1.0"
electron@30.0.2:
version "30.0.2"
resolved "https://registry.yarnpkg.com/electron/-/electron-30.0.2.tgz#95ba019216bf8be9f3097580123e33ea37497733"
integrity sha512-zv7T+GG89J/hyWVkQsLH4Y/rVEfqJG5M/wOBIGNaDdqd8UV9/YZPdS7CuFeaIj0H9LhCt95xkIQNpYB/3svOkQ==
electron@38.6.0:
version "38.6.0"
resolved "https://registry.yarnpkg.com/electron/-/electron-38.6.0.tgz#c862bff41d42776e307bf5cc92503dda23612339"
integrity sha512-68OFNxJlrEStA+t8k5atzf4frJddvRR1N1oalr49Ll8YZ0+0nEsDhw4UNhTCoZKTjSYcxFF/4rt+sco+OlnB3g==
dependencies:
"@electron/get" "^2.0.0"
"@types/node" "^20.9.0"
"@types/node" "^22.7.7"
extract-zip "^2.0.1"
emoji-regex@^8.0.0:
@@ -976,9 +1005,9 @@ encoding@^0.1.13:
iconv-lite "^0.6.2"
end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
version "1.4.5"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c"
integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==
dependencies:
once "^1.4.0"
@@ -992,27 +1021,42 @@ err-code@^2.0.2:
resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
es-define-property@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
dependencies:
get-intrinsic "^1.2.4"
es-define-property@^1.0.0, es-define-property@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
es-errors@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
dependencies:
es-errors "^1.3.0"
es-set-tostringtag@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d"
integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==
dependencies:
es-errors "^1.3.0"
get-intrinsic "^1.2.6"
has-tostringtag "^1.0.2"
hasown "^2.0.2"
es6-error@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
escalade@^3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
escape-string-regexp@^4.0.0:
version "4.0.0"
@@ -1020,9 +1064,9 @@ escape-string-regexp@^4.0.0:
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
exponential-backoff@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6"
integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==
version "3.1.3"
resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz#51cf92c1c0493c766053f9d3abee4434c244d2f6"
integrity sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==
extract-zip@^2.0.1:
version "2.0.1"
@@ -1064,10 +1108,10 @@ filelist@^1.0.4:
dependencies:
minimatch "^5.0.1"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
dependencies:
to-regex-range "^5.0.1"
@@ -1079,20 +1123,22 @@ find-yarn-workspace-root@^2.0.0:
micromatch "^4.0.2"
foreground-child@^3.1.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77"
integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==
version "3.3.1"
resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f"
integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==
dependencies:
cross-spawn "^7.0.0"
cross-spawn "^7.0.6"
signal-exit "^4.0.1"
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
version "4.0.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4"
integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
es-set-tostringtag "^2.1.0"
hasown "^2.0.2"
mime-types "^2.1.12"
fs-extra@^10.0.0, fs-extra@^10.1.0:
@@ -1105,9 +1151,9 @@ fs-extra@^10.0.0, fs-extra@^10.1.0:
universalify "^2.0.0"
fs-extra@^11.1.1:
version "11.2.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b"
integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==
version "11.3.2"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.2.tgz#c838aeddc6f4a8c74dd15f85e11fe5511bfe02a4"
integrity sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
@@ -1168,16 +1214,29 @@ get-caller-file@^2.0.5:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
get-intrinsic@^1.2.6:
version "1.3.0"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
dependencies:
call-bind-apply-helpers "^1.0.2"
es-define-property "^1.0.1"
es-errors "^1.3.0"
es-object-atoms "^1.1.1"
function-bind "^1.1.2"
has-proto "^1.0.1"
has-symbols "^1.0.3"
hasown "^2.0.0"
get-proto "^1.0.1"
gopd "^1.2.0"
has-symbols "^1.1.0"
hasown "^2.0.2"
math-intrinsics "^1.1.0"
get-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
dependencies:
dunder-proto "^1.0.1"
es-object-atoms "^1.0.0"
get-stream@^5.1.0:
version "5.2.0"
@@ -1241,12 +1300,10 @@ globalthis@^1.0.1:
define-properties "^1.2.1"
gopd "^1.0.1"
gopd@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
dependencies:
get-intrinsic "^1.1.3"
gopd@^1.0.1, gopd@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
got@^11.7.0, got@^11.8.5:
version "11.8.6"
@@ -1282,22 +1339,24 @@ has-property-descriptors@^1.0.0:
dependencies:
es-define-property "^1.0.0"
has-proto@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
has-symbols@^1.0.3, has-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
has-tostringtag@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
dependencies:
has-symbols "^1.0.3"
has-unicode@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==
hasown@^2.0.0:
hasown@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
@@ -1312,9 +1371,9 @@ hosted-git-info@^4.1.0:
lru-cache "^6.0.0"
http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
version "4.2.0"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5"
integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==
http-proxy-agent@^5.0.0:
version "5.0.0"
@@ -1412,13 +1471,10 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1,
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
ip-address@^9.0.5:
version "9.0.5"
resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a"
integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==
dependencies:
jsbn "1.1.0"
sprintf-js "^1.1.3"
ip-address@^10.0.1:
version "10.1.0"
resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.1.0.tgz#d8dcffb34d0e02eb241427444a6e23f5b0595aa4"
integrity sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==
is-ci@^2.0.0:
version "2.0.0"
@@ -1487,9 +1543,9 @@ isbinaryfile@^4.0.8:
integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==
isbinaryfile@^5.0.0:
version "5.0.4"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.4.tgz#2a2edefa76cafa66613fe4c1ea52f7f031017bdf"
integrity sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==
version "5.0.6"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.6.tgz#01eac28867aeffaebaee7eaf21d1dd3a67d7c0c7"
integrity sha512-I+NmIfBHUl+r2wcDd6JwE9yWje/PIVY/R5/CmV8dXLZd5K+L9X2klAOwfAHNnondLXkbHyTAleQAWonpTJBTtw==
isexe@^2.0.0:
version "2.0.0"
@@ -1506,14 +1562,13 @@ jackspeak@^3.1.2:
"@pkgjs/parseargs" "^0.11.0"
jake@^10.8.5:
version "10.9.1"
resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.1.tgz#8dc96b7fcc41cb19aa502af506da4e1d56f5e62b"
integrity sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==
version "10.9.4"
resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.4.tgz#d626da108c63d5cfb00ab5c25fadc7e0084af8e6"
integrity sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==
dependencies:
async "^3.2.3"
chalk "^4.0.2"
async "^3.2.6"
filelist "^1.0.4"
minimatch "^3.1.2"
picocolors "^1.1.1"
js-yaml@^4.1.0:
version "4.1.0"
@@ -1522,11 +1577,6 @@ js-yaml@^4.1.0:
dependencies:
argparse "^2.0.1"
jsbn@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==
json-buffer@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
@@ -1555,9 +1605,9 @@ jsonfile@^4.0.0:
graceful-fs "^4.1.6"
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
version "6.2.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62"
integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==
dependencies:
universalify "^2.0.0"
optionalDependencies:
@@ -1580,11 +1630,11 @@ jsonwebtoken@^9.0.2:
semver "^7.5.4"
jwa@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
version "1.4.2"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.2.tgz#16011ac6db48de7b102777e57897901520eec7b9"
integrity sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==
dependencies:
buffer-equal-constant-time "1.0.1"
buffer-equal-constant-time "^1.0.1"
ecdsa-sig-formatter "1.0.11"
safe-buffer "^5.0.1"
@@ -1729,12 +1779,17 @@ matcher@^3.0.0:
dependencies:
escape-string-regexp "^4.0.0"
math-intrinsics@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
micromatch@^4.0.2:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
dependencies:
braces "^3.0.2"
braces "^3.0.3"
picomatch "^2.3.1"
mime-db@1.52.0:
@@ -1770,13 +1825,13 @@ mimic-response@^3.1.0:
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
minimatch@^10.0.0:
version "10.0.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b"
integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==
version "10.1.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.1.1.tgz#e6e61b9b0c1dcab116b5a7d1458e8b6ae9e73a55"
integrity sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==
dependencies:
brace-expansion "^2.0.1"
"@isaacs/brace-expansion" "^5.0.0"
minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
@@ -1871,11 +1926,6 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@^2.0.0, ms@^2.1.1, ms@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
@@ -1892,9 +1942,9 @@ nice-try@^1.0.4:
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-abi@^3.45.0:
version "3.71.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.71.0.tgz#52d84bbcd8575efb71468fbaa1f9a49b2c242038"
integrity sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==
version "3.80.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.80.0.tgz#d7390951f27caa129cceeec01e1c20fc9f07581c"
integrity sha512-LyPuZJcI9HVwzXK1GPxWNzrr+vr8Hp/3UqlmWxxh8p54U1ZbclOqbSog9lWHaCX+dBaiGi6n/hIX+mKu74GmPA==
dependencies:
semver "^7.3.5"
@@ -1904,9 +1954,9 @@ node-addon-api@^1.6.3:
integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==
node-api-version@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/node-api-version/-/node-api-version-0.2.0.tgz#5177441da2b1046a4d4547ab9e0972eed7b1ac1d"
integrity sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg==
version "0.2.1"
resolved "https://registry.yarnpkg.com/node-api-version/-/node-api-version-0.2.1.tgz#19bad54f6d65628cbee4e607a325e4488ace2de9"
integrity sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==
dependencies:
semver "^7.3.5"
@@ -2081,6 +2131,11 @@ pend@~1.2.0:
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==
picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
picomatch@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
@@ -2119,9 +2174,9 @@ promise-retry@^2.0.1:
retry "^0.12.0"
pump@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
version "3.0.3"
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d"
integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
@@ -2261,9 +2316,9 @@ sanitize-filename@^1.6.3:
truncate-utf8-bytes "^1.0.0"
sax@^1.2.4:
version "1.3.0"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0"
integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==
version "1.4.3"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.3.tgz#fcebae3b756cdc8428321805f4b70f16ec0ab5db"
integrity sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==
semver-compare@^1.0.0:
version "1.0.0"
@@ -2280,15 +2335,10 @@ semver@^6.2.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.2:
version "7.6.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.1.tgz#60bfe090bf907a25aa8119a72b9f90ef7ca281b2"
integrity sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==
semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3:
version "7.6.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
semver@^7.3.2, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3:
version "7.7.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
serialize-error@^7.0.1:
version "7.0.1"
@@ -2372,11 +2422,11 @@ socks-proxy-agent@^7.0.0:
socks "^2.6.2"
socks@^2.6.2:
version "2.8.3"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5"
integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==
version "2.8.7"
resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.7.tgz#e2fb1d9a603add75050a2067db8c381a0b5669ea"
integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==
dependencies:
ip-address "^9.0.5"
ip-address "^10.0.1"
smart-buffer "^4.2.0"
source-map-support@^0.5.19:
@@ -2392,7 +2442,7 @@ source-map@^0.6.0:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
sprintf-js@^1.1.2, sprintf-js@^1.1.3:
sprintf-js@^1.1.2:
version "1.1.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==
@@ -2454,9 +2504,9 @@ string_decoder@~1.1.1:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
version "7.1.2"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba"
integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==
dependencies:
ansi-regex "^6.0.1"
@@ -2522,9 +2572,9 @@ tmp@^0.0.33:
os-tmpdir "~1.0.2"
tmp@^0.2.0:
version "0.2.3"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae"
integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==
version "0.2.5"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8"
integrity sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==
to-regex-range@^5.0.1:
version "5.0.1"
@@ -2546,14 +2596,19 @@ type-fest@^0.13.1:
integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
typescript@^5.4.3:
version "5.7.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6"
integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==
version "5.9.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f"
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
undici-types@~5.26.4:
version "5.26.5"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
undici-types@~6.21.0:
version "6.21.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb"
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
undici-types@~7.16.0:
version "7.16.0"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46"
integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==
unique-filename@^2.0.0:
version "2.0.1"
@@ -2592,9 +2647,9 @@ uri-js@^4.2.2:
punycode "^2.1.0"
utf8-byte-length@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61"
integrity sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==
version "1.0.5"
resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e"
integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
+3 -2
View File
@@ -6,7 +6,7 @@ const { getFiles } = require('./helpers');
const readFilePromise = promisify(fs.readFile);
const translationRegex = /_t\(\s*['"]([^'"]+)['"]\s*,\s*\{\s*defaultMessage\s*:\s*['"]([^'"]+)['"]\s*\}/g;
const translationRegex = /_t\(\s*['"]([^'"]+)['"]\s*,\s*\{\s*defaultMessage\s*:\s*(?:'([^'\\]*(?:\\.[^'\\]*)*)'|"([^"\\]*(?:\\.[^"\\]*)*)"|\`([^`\\]*(?:\\.[^`\\]*)*(?:\{[^}]*\}[^`\\]*(?:\\.[^`\\]*)*)*)\`)(?:\s*,\s*[^}]*)*\s*\}/g;
/**
* @param {string} file
@@ -20,7 +20,8 @@ async function extractTranslationsFromFile(file) {
let match;
while ((match = translationRegex.exec(content)) !== null) {
const [_, key, defaultText] = match;
const [_, key, singleQuotedText, doubleQuotedText, templateLiteral] = match;
const defaultText = singleQuotedText || doubleQuotedText || templateLiteral;
translations[key] = defaultText;
}
+27
View File
@@ -160,4 +160,31 @@ program
}
});
program
.command('sort')
.description('Sort translation files by keys')
.action(() => {
try {
const languages = getAllNonDefaultLanguages();
for (const language of languages) {
const filePath = `./translations/${language}.json`;
const content = fs.readFileSync(filePath, 'utf-8');
const translations = JSON.parse(content);
const sortedTranslations = {};
Object.keys(translations)
.sort()
.forEach(key => {
// @ts-ignore
sortedTranslations[key] = translations[key];
});
fs.writeFileSync(filePath, JSON.stringify(sortedTranslations, null, 2), 'utf-8');
console.log(`Sorted translations for language: ${language}`);
}
} catch (error) {
console.error(error);
console.error('Error during sort:', error.message);
process.exit(1);
}
});
module.exports = { program };
+132
View File
@@ -0,0 +1,132 @@
require('dotenv').config({ path: '.env.translation' });
const fs = require('fs');
const path = require('path');
const OpenAI = require('openai');
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const translationsDir = path.join(__dirname, '../../translations');
const enFilePath = path.join(translationsDir, 'en.json');
const languageNames = {
'cs.json': 'Czech',
'de.json': 'German',
'es.json': 'Spanish',
'fr.json': 'French',
'it.json': 'Italian',
'ja.json': 'Japanese',
'pt.json': 'Portuguese',
'sk.json': 'Slovak',
'zh.json': 'Chinese'
};
// Read source (english)
const enTranslations = JSON.parse(fs.readFileSync(enFilePath, 'utf8'));
const enKeys = Object.keys(enTranslations);
// Get all translation files
const translationFiles = fs.readdirSync(translationsDir)
.filter(file => file.endsWith('.json') && file !== 'en.json')
.sort();
console.log(`Found ${enKeys.length} keys in en.json\n`);
console.log('='.repeat(80));
async function translateMissingIds({file, translations, missingIds}){
const languageName = languageNames[file];
if (!languageName) {
console.log(`No language name mapping for file: ${file}`);
return;
}
// Build object with only missing translations
const needed = {};
missingIds.forEach(key => {
needed[key] = enTranslations[key];
});
// Get all existing translations as style examples
const existingTranslations = {};
Object.keys(translations).forEach(key => {
if (translations[key] && !translations[key].startsWith('***')) {
existingTranslations[key] = {
en: enTranslations[key],
translated: translations[key]
};
}
});
const prompt = `You are a professional translator for DbGate, a database management application.
Translate the following English UI strings to ${languageName}.
IMPORTANT RULES:
1. Preserve ALL placeholders exactly as they appear: {plugin}, {columnNumber}, {0}, {1}, etc.
2. Maintain technical terminology appropriately for database software
3. Match the translation style, tone, and formality of the existing translations shown below
4. Keep the same level of brevity or verbosity as the existing translations
5. Return ONLY valid JSON - no markdown, no explanations, no code blocks
6. Use the same keys as provided
EXISTING TRANSLATIONS (for style reference):
${JSON.stringify(existingTranslations, null, 2)}
STRINGS TO TRANSLATE:
${JSON.stringify(needed, null, 2)}
Return format: {"key": "translated value", ...}`;
const response = await client.chat.completions.create({
model: 'gpt-5.1',
messages: [
{ role: 'system', content: 'You are a professional translator specializing in software localization. Match the style and tone of existing translations. Return only valid JSON.' },
{ role: 'user', content: prompt }
],
temperature: 0.2
});
let translatedJson = response.choices[0].message.content.trim();
// Remove markdown code blocks if present
translatedJson = translatedJson.replace(/^```json\n?/, '').replace(/\n?```$/, '');
return JSON.parse(translatedJson);
}
(async () => {
for (const file of translationFiles) {
const filePath = path.join(translationsDir, file);
const translations = JSON.parse(fs.readFileSync(filePath, 'utf8'));
const missingIds = enKeys.filter(key => !translations.hasOwnProperty(key) || (typeof translations[key] === 'string' && translations[key].startsWith('***')));
console.log(`\n${file.toUpperCase()}`);
console.log('-'.repeat(80));
if (missingIds.length === 0) {
console.log('✓ All translations complete!');
continue;
} else {
console.log(`Found ${missingIds.length} untranslated IDs\n`);
}
const newTranslations = await translateMissingIds({file, translations, missingIds});
if (!newTranslations) {
console.log(`Skipping file due to translation error: ${file}`);
continue;
}
for (const [key, value] of Object.entries(newTranslations)) {
translations[key] = value;
console.log(`Translated: ${key} => ${value}`);
}
fs.writeFileSync(filePath, JSON.stringify(translations, null, 2) + '\n', 'utf8');
console.log(`\n✓ Updated translations written to ${file}`);
}
console.log('\n' + '='.repeat(80));
console.log('Translation complete!\n');
})();
+1
View File
@@ -4,6 +4,7 @@ const volatilePackages = [
'@clickhouse/client',
'bson', // this package is already bundled and is used in mongodb
'mongodb',
'mongodb-old',
'mongodb-client-encryption',
'tedious',
'msnodesqlv8',
+1 -1
View File
@@ -60,7 +60,7 @@ describe('Data browser data', () => {
cy.contains('MyChinook').click();
cy.testid('SqlObjectList_search').clear().type('album');
cy.contains('Tables (1/11)');
cy.contains('347 rows, InnoDB');
cy.contains('347 rows, 65.5 KB, InnoDB');
cy.testid('SqlObjectList_searchMenuDropDown').click();
cy.contains('Column name').click();
cy.contains('Tables (2/11)');
+49 -11
View File
@@ -110,7 +110,7 @@ describe('Charts', () => {
cy.themeshot('new-object-window');
});
it.only('Database chat - charts', () => {
it('Database chat - charts', () => {
cy.contains('MySql-connection').click();
cy.contains('MyChinook').click();
cy.testid('TabsPanel_buttonNewObject').click();
@@ -119,7 +119,9 @@ describe('Charts', () => {
cy.get('body').realType('show me chart of most popular genres');
cy.get('body').realPress('{enter}');
cy.testid('DatabaseChatTab_executeAllQueries', { timeout: 30000 }).click();
cy.testid('chart-canvas', { timeout: 30000 }).should($c => expect($c[0].toDataURL()).to.match(/^data:image\/png;base64/));
cy.testid('chart-canvas', { timeout: 30000 }).should($c =>
expect($c[0].toDataURL()).to.match(/^data:image\/png;base64/)
);
cy.themeshot('database-chat-chart');
});
@@ -155,15 +157,51 @@ describe('Charts', () => {
cy.testid('MessageViewRow-explainErrorButton-1').click();
cy.testid('ChatCodeRenderer_useSqlButton', { timeout: 30000 });
cy.themeshot('explain-query-error');
});
// cy.testid('TabsPanel_buttonNewObject').click();
// cy.testid('NewObjectModal_databaseChat').click();
// cy.wait(1000);
// cy.get('body').realType('show me chart of most popular genres');
// cy.get('body').realPress('{enter}');
// cy.testid('DatabaseChatTab_executeAllQueries', { timeout: 30000 }).click();
// cy.wait(5000);
// cy.testid('chart-canvas').should($c => expect($c[0].toDataURL()).to.match(/^data:image\/png;base64/));
// cy.themeshot('database-chat-chart');
it('Switch language', () => {
cy.contains('MySql-connection').click();
cy.contains('MyChinook').click();
cy.testid('WidgetIconPanel_settings').click();
cy.contains('Settings').click();
cy.testid('SettingsModal_languageSelect').select('Deutsch');
cy.testid('ConfirmModal_okButton').click();
cy.testid('WidgetIconPanel_settings').click();
cy.contains('Einstellungen').click();
cy.contains('Lokalisierung');
cy.themeshot('switch-language-de');
cy.testid('SettingsModal_languageSelect').select('Français');
cy.testid('ConfirmModal_okButton').click();
cy.testid('WidgetIconPanel_settings').click();
cy.contains('Paramètres').click();
cy.contains('Localisation');
cy.themeshot('switch-language-fr');
cy.testid('SettingsModal_languageSelect').select('Español');
cy.testid('ConfirmModal_okButton').click();
cy.testid('WidgetIconPanel_settings').click();
cy.contains('Configuración').click();
cy.contains('Localización');
cy.themeshot('switch-language-es');
cy.testid('SettingsModal_languageSelect').select('Čeština');
cy.testid('ConfirmModal_okButton').click();
cy.testid('WidgetIconPanel_settings').click();
cy.contains('Nastavení').click();
cy.contains('Lokalizace');
cy.themeshot('switch-language-cs');
cy.testid('SettingsModal_languageSelect').select('中文');
cy.testid('ConfirmModal_okButton').click();
cy.testid('WidgetIconPanel_settings').click();
cy.contains('设置').click();
cy.contains('本地化');
cy.themeshot('switch-language-zh');
cy.testid('SettingsModal_languageSelect').select('English');
cy.testid('ConfirmModal_okButton').click();
cy.testid('WidgetIconPanel_settings');
});
});
@@ -12,6 +12,7 @@ const {
} = require('dbgate-tools');
function pickImportantTableInfo(engine, table) {
if (!table) return table;
const props = ['columnName', 'defaultValue'];
if (!engine.skipNullability) props.push('notNull');
if (!engine.skipAutoIncrement) props.push('autoIncrement');
@@ -25,6 +26,13 @@ function pickImportantTableInfo(engine, table) {
.map(props =>
_.omitBy(props, (v, k) => k == 'defaultValue' && v == 'NULL' && engine.setNullDefaultInsteadOfDrop)
),
// foreignKeys: table.foreignKeys
// .sort((a, b) => a.refTableName.localeCompare(b.refTableName))
// .map(fk => ({
// constraintType: fk.constraintType,
// refTableName: fk.refTableName,
// columns: fk.columns.map(col => ({ columnName: col.columnName, refColumnName: col.refColumnName })),
// })),
};
}
@@ -33,7 +41,7 @@ function checkTableStructure(engine, t1, t2) {
expect(pickImportantTableInfo(engine, t1)).toEqual(pickImportantTableInfo(engine, t2));
}
async function testTableDiff(engine, conn, driver, mangle) {
async function testTableDiff(engine, conn, driver, mangle, changedTable = 't1') {
const initQuery = formatQueryWithoutParams(driver, `create table ~t0 (~id int not null primary key)`);
await driver.query(conn, transformSqlForEngine(engine, initQuery));
@@ -68,17 +76,38 @@ async function testTableDiff(engine, conn, driver, mangle) {
await driver.query(conn, transformSqlForEngine(engine, query));
}
const tget = x => x.tables.find(y => y.pureName == 't1');
const structure1 = generateDbPairingId(extendDatabaseInfo(await driver.analyseFull(conn)));
if (!engine.skipReferences) {
const query = formatQueryWithoutParams(
driver,
`create table ~t3 (~id int not null primary key, ~fkval int ${
driver.dialect.implicitNullDeclaration ? '' : 'null'
})`
);
await driver.query(conn, transformSqlForEngine(engine, query));
}
const tget = x => x?.tables?.find(y => y.pureName == changedTable);
const structure1Source = await driver.analyseFull(conn);
const structure1 = generateDbPairingId(extendDatabaseInfo(structure1Source));
let structure2 = _.cloneDeep(structure1);
mangle(tget(structure2));
structure2 = extendDatabaseInfo(structure2);
const { sql } = getAlterTableScript(tget(structure1), tget(structure2), {}, structure1, structure2, driver);
// sleep 1s - some engines have update datetime precision only to seconds
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('RUNNING ALTER SQL', driver.engine, ':', sql);
await driver.script(conn, sql);
// if (!engine.skipIncrementalAnalysis) {
// const structure2RealIncremental = await driver.analyseIncremental(conn, structure1Source);
// checkTableStructure(engine, tget(structure2RealIncremental), tget(structure2));
// }
const structure2Real = extendDatabaseInfo(await driver.analyseFull(conn));
checkTableStructure(engine, tget(structure2Real), tget(structure2));
@@ -214,6 +243,48 @@ describe('Alter table', () => {
})
);
test.each(engines.filter(x => !x.skipReferences).map(engine => [engine.label, engine]))(
'Drop FK - %s',
testWrapper(async (conn, driver, engine) => {
await testTableDiff(
engine,
conn,
driver,
tbl => {
tbl.foreignKeys = [];
},
't2'
);
})
);
test.each(engines.filter(x => !x.skipReferences).map(engine => [engine.label, engine]))(
'Create FK - %s',
testWrapper(async (conn, driver, engine) => {
await testTableDiff(
engine,
conn,
driver,
tbl => {
tbl.foreignKeys = [
{
constraintType: 'foreignKey',
pureName: 't3',
refTableName: 't1',
columns: [
{
columnName: 'fkval',
refColumnName: 'col_ref',
},
],
},
];
},
't3'
);
})
);
// test.each(engines.map(engine => [engine.label, engine]))(
// 'Change autoincrement - %s',
// testWrapper(async (conn, driver, engine) => {
+73
View File
@@ -49,6 +49,32 @@ class StreamHandler {
}
}
class BinaryTestStreamHandler {
constructor(resolve, reject, expectedValue) {
this.resolve = resolve;
this.reject = reject;
this.expectedValue = expectedValue;
this.rowsReceived = [];
}
row(row) {
try {
this.rowsReceived.push(row);
if (this.expectedValue) {
expect(row).toEqual(this.expectedValue);
}
} catch (error) {
this.reject(error);
return;
}
}
recordset(columns) {}
done(result) {
this.resolve(this.rowsReceived);
}
info(msg) {}
}
function executeStreamItem(driver, conn, sql) {
return new Promise(resolve => {
const handler = new StreamHandler(resolve);
@@ -223,4 +249,51 @@ describe('Query', () => {
expect(row[keys[0]] == 1).toBeTruthy();
})
);
test.each(engines.filter(x => x.binaryDataType).map(engine => [engine.label, engine]))(
'Binary - %s',
testWrapper(async (dbhan, driver, engine) => {
await runCommandOnDriver(dbhan, driver, dmp =>
dmp.createTable({
pureName: 't1',
columns: [
{ columnName: 'id', dataType: 'int', notNull: true, autoIncrement: true },
{ columnName: 'val', dataType: engine.binaryDataType },
],
primaryKey: {
columns: [{ columnName: 'id' }],
},
})
);
const structure = await driver.analyseFull(dbhan);
const table = structure.tables.find(x => x.pureName == 't1');
const dmp = driver.createDumper();
dmp.putCmd("INSERT INTO ~t1 (~val) VALUES (%v)", {
$binary: { base64: 'iVBORw0KWgo=' },
});
await driver.query(dbhan, dmp.s, {discardResult: true});
const dmp2 = driver.createDumper();
dmp2.put('SELECT ~val FROM ~t1');
const res = await driver.query(dbhan, dmp2.s);
const row = res.rows[0];
const keys = Object.keys(row);
expect(keys.length).toEqual(1);
expect(row[keys[0]]).toEqual({$binary: {base64: 'iVBORw0KWgo='}});
const res2 = await driver.readQuery(dbhan, dmp2.s);
const rows = await Array.fromAsync(res2);
const rowsVal = rows.filter(r => r.val != null);
expect(rowsVal.length).toEqual(1);
expect(rowsVal[0].val).toEqual({$binary: {base64: 'iVBORw0KWgo='}});
const res3 = await new Promise((resolve, reject) => {
const handler = new BinaryTestStreamHandler(resolve, reject, {val: {$binary: {base64: 'iVBORw0KWgo='}}});
driver.stream(dbhan, dmp2.s, handler);
});
})
);
});
+10 -4
View File
@@ -44,6 +44,7 @@ const mysqlEngine = {
supportRenameSqlObject: false,
dbSnapshotBySeconds: true,
dumpFile: 'data/chinook-mysql.sql',
binaryDataType: 'blob',
dumpChecks: [
{
sql: 'select count(*) as res from genre',
@@ -186,6 +187,7 @@ const mariaDbEngine = {
/** @type {import('dbgate-types').TestEngineInfo} */
const postgreSqlEngine = {
label: 'PostgreSQL',
skipIncrementalAnalysis: true,
connection: {
engine: 'postgres@dbgate-plugin-postgres',
password: 'Pwd2020Db',
@@ -216,6 +218,7 @@ const postgreSqlEngine = {
supportSchemas: true,
supportRenameSqlObject: true,
defaultSchemaName: 'public',
binaryDataType: 'bytea',
dumpFile: 'data/chinook-postgre.sql',
dumpChecks: [
{
@@ -446,6 +449,7 @@ const sqlServerEngine = {
supportTableComments: true,
supportColumnComments: true,
// skipSeparateSchemas: true,
binaryDataType: 'varbinary(100)',
triggers: [
{
testName: 'triggers before each row',
@@ -506,6 +510,7 @@ const sqliteEngine = {
},
},
],
binaryDataType: 'blob',
};
const libsqlFileEngine = {
@@ -619,6 +624,7 @@ const oracleEngine = {
},
},
],
binaryDataType: 'blob',
};
/** @type {import('dbgate-types').TestEngineInfo} */
@@ -754,16 +760,16 @@ const enginesOnLocal = [
// cassandraEngine,
// mysqlEngine,
// mariaDbEngine,
// postgreSqlEngine,
// sqlServerEngine,
postgreSqlEngine,
//sqlServerEngine,
// sqliteEngine,
// cockroachDbEngine,
// clickhouseEngine,
// libsqlFileEngine,
// libsqlWsEngine,
// oracleEngine,
//oracleEngine,
// duckdbEngine,
firebirdEngine,
//firebirdEngine,
];
/** @type {import('dbgate-types').TestEngineInfo[] & Record<string, import('dbgate-types').TestEngineInfo>} */
+1
View File
@@ -1,3 +1,4 @@
module.exports = {
setupFilesAfterEnv: ['<rootDir>/setupTests.js'],
reporters: ['default', 'github-actions'],
};
+1 -1
View File
@@ -18,7 +18,7 @@
},
"devDependencies": {
"cross-env": "^7.0.3",
"jest": "^27.0.1",
"jest": "^28.1.3",
"pino-pretty": "^11.2.2",
"tmp": "^0.2.3"
}
+2 -1
View File
@@ -1,6 +1,6 @@
{
"private": true,
"version": "6.6.8",
"version": "6.7.2-alpha.1",
"name": "dbgate-all",
"workspaces": [
"packages/*",
@@ -74,6 +74,7 @@
"translations:add-missing": "node common/translations-cli/index.js add-missing",
"translations:remove-unused": "node common/translations-cli/index.js remove-unused",
"translations:check": "node common/translations-cli/index.js check",
"translations:sort": "node common/translations-cli/index.js sort",
"errors": "node common/assign-dbgm-codes.mjs ."
},
"dependencies": {
+1 -1
View File
@@ -2,7 +2,7 @@ DEVMODE=1
SHELL_SCRIPTING=1
ALLOW_DBGATE_PRIVATE_CLOUD=1
DEVWEB=1
LOCAL_AUTH_PROXY=1
# LOCAL_AUTH_PROXY=1
# LOCAL_AI_GATEWAY=true
# REDIRECT_TO_DBGATE_CLOUD_LOGIN=1
+1 -1
View File
@@ -31,7 +31,7 @@
"cors": "^2.8.5",
"cross-env": "^6.0.3",
"dbgate-datalib": "^6.0.0-alpha.1",
"dbgate-query-splitter": "^4.11.7",
"dbgate-query-splitter": "^4.11.9",
"dbgate-sqltree": "^6.0.0-alpha.1",
"dbgate-tools": "^6.0.0-alpha.1",
"debug": "^4.3.4",
+2 -2
View File
@@ -35,8 +35,8 @@ module.exports = {
},
refreshPublicFiles_meta: true,
async refreshPublicFiles({ isRefresh }) {
await refreshPublicFiles(isRefresh);
async refreshPublicFiles({ isRefresh }, req) {
await refreshPublicFiles(isRefresh, req?.headers?.['x-ui-language']);
return {
status: 'ok',
};
+2
View File
@@ -71,6 +71,7 @@ module.exports = {
const isLicenseValid = checkedLicense?.status == 'ok';
const logoutUrl = storageConnectionError ? null : await authProvider.getLogoutUrl();
const adminConfig = storageConnectionError ? null : await storage.readConfig({ group: 'admin' });
const settingsConfig = storageConnectionError ? null : await storage.readConfig({ group: 'settings' });
storage.startRefreshLicense();
@@ -121,6 +122,7 @@ module.exports = {
allowPrivateCloud: platformInfo.isElectron || !!process.env.ALLOW_DBGATE_PRIVATE_CLOUD,
...currentVersion,
redirectToDbGateCloudLogin: !!process.env.REDIRECT_TO_DBGATE_CLOUD_LOGIN,
preferrendLanguage: settingsConfig?.['storage.language'] || process.env.LANGUAGE || null,
};
return configResult;
+14 -3
View File
@@ -14,7 +14,11 @@ const JsonLinesDatabase = require('../utility/JsonLinesDatabase');
const processArgs = require('../utility/processArgs');
const { safeJsonParse, getLogger, extractErrorLogData } = require('dbgate-tools');
const platformInfo = require('../utility/platformInfo');
const { connectionHasPermission, testConnectionPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
const {
connectionHasPermission,
testConnectionPermission,
loadPermissionsFromRequest,
} = require('../utility/hasPermission');
const pipeForkLogs = require('../utility/pipeForkLogs');
const requireEngineDriver = require('../utility/requireEngineDriver');
const { getAuthProviderById } = require('../auth/authProvider');
@@ -116,7 +120,10 @@ function getPortalCollections() {
}
}
logger.info({ connections: connections.map(pickSafeConnectionInfo) }, 'DBGM-00005 Using connections from ENV variables');
logger.info(
{ connections: connections.map(pickSafeConnectionInfo) },
'DBGM-00005 Using connections from ENV variables'
);
const noengine = connections.filter(x => !x.engine);
if (noengine.length > 0) {
logger.warn(
@@ -502,7 +509,11 @@ module.exports = {
state,
client: 'web',
});
res.redirect(authResp.url);
if (authResp?.url) {
res.redirect(authResp.url);
return;
}
res.json({ error: 'No URL returned from auth provider' });
},
dbloginApp_meta: true,
@@ -29,7 +29,17 @@ const generateDeploySql = require('../shell/generateDeploySql');
const { createTwoFilesPatch } = require('diff');
const diff2htmlPage = require('../utility/diff2htmlPage');
const processArgs = require('../utility/processArgs');
const { testConnectionPermission, hasPermission, loadPermissionsFromRequest, loadTablePermissionsFromRequest, getTablePermissionRole, loadDatabasePermissionsFromRequest, getDatabasePermissionRole, getTablePermissionRoleLevelIndex, testDatabaseRolePermission } = require('../utility/hasPermission');
const {
testConnectionPermission,
hasPermission,
loadPermissionsFromRequest,
loadTablePermissionsFromRequest,
getTablePermissionRole,
loadDatabasePermissionsFromRequest,
getDatabasePermissionRole,
getTablePermissionRoleLevelIndex,
testDatabaseRolePermission,
} = require('../utility/hasPermission');
const { MissingCredentialsError } = require('../utility/exceptions');
const pipeForkLogs = require('../utility/pipeForkLogs');
const crypto = require('crypto');
@@ -100,7 +110,7 @@ module.exports = {
socket.emitChanged(`database-status-changed`, { conid, database });
},
handle_ping() { },
handle_ping() {},
// session event handlers
@@ -256,23 +266,24 @@ module.exports = {
auditLogger:
auditLogSessionGroup && select?.from?.name?.pureName
? response => {
sendToAuditLog(req, {
category: 'dbop',
component: 'DatabaseConnectionsController',
event: 'sql.select',
action: 'select',
severity: 'info',
conid,
database,
schemaName: select?.from?.name?.schemaName,
pureName: select?.from?.name?.pureName,
sumint1: response?.rows?.length,
sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${select?.from?.name?.pureName
sendToAuditLog(req, {
category: 'dbop',
component: 'DatabaseConnectionsController',
event: 'sql.select',
action: 'select',
severity: 'info',
conid,
database,
schemaName: select?.from?.name?.schemaName,
pureName: select?.from?.name?.pureName,
sumint1: response?.rows?.length,
sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${
select?.from?.name?.pureName
}`,
sessionGroup: auditLogSessionGroup,
message: `Loaded table data from ${select?.from?.name?.pureName}`,
});
}
sessionGroup: auditLogSessionGroup,
message: `Loaded table data from ${select?.from?.name?.pureName}`,
});
}
: null,
}
);
@@ -335,21 +346,21 @@ module.exports = {
auditLogger:
auditLogSessionGroup && options?.pureName
? response => {
sendToAuditLog(req, {
category: 'dbop',
component: 'DatabaseConnectionsController',
event: 'nosql.collectionData',
action: 'select',
severity: 'info',
conid,
database,
pureName: options?.pureName,
sumint1: response?.result?.rows?.length,
sessionParam: `${conid}::${database}::${options?.pureName}`,
sessionGroup: auditLogSessionGroup,
message: `Loaded collection data ${options?.pureName}`,
});
}
sendToAuditLog(req, {
category: 'dbop',
component: 'DatabaseConnectionsController',
event: 'nosql.collectionData',
action: 'select',
severity: 'info',
conid,
database,
pureName: options?.pureName,
sumint1: response?.result?.rows?.length,
sessionParam: `${conid}::${database}::${options?.pureName}`,
sessionGroup: auditLogSessionGroup,
message: `Loaded collection data ${options?.pureName}`,
});
}
: null,
}
);
@@ -455,10 +466,18 @@ module.exports = {
[changeSet.inserts, 'create_update_delete'],
[changeSet.deletes, 'create_update_delete'],
[changeSet.updates, 'update_only'],
]
];
for (const [operations, requiredRole] of fieldsAndRoles) {
for (const operation of operations) {
const role = getTablePermissionRole(conid, database, 'tables', operation.schemaName, operation.pureName, tablePermissions, databasePermissions);
const role = getTablePermissionRole(
conid,
database,
'tables',
operation.schemaName,
operation.pureName,
tablePermissions,
databasePermissions
);
if (getTablePermissionRoleLevelIndex(role) < getTablePermissionRoleLevelIndex(requiredRole)) {
throw new Error('DBGM-00262 Permission not granted');
}
@@ -628,7 +647,15 @@ module.exports = {
function applyTablePermissionRole(list, objectTypeField) {
const res = [];
for (const item of list ?? []) {
const tablePermissionRole = getTablePermissionRole(conid, database, objectTypeField, item.schemaName, item.pureName, tablePermissions, databasePermissionRole);
const tablePermissionRole = getTablePermissionRole(
conid,
database,
objectTypeField,
item.schemaName,
item.pureName,
tablePermissions,
databasePermissionRole
);
if (tablePermissionRole != 'deny') {
res.push({
...item,
@@ -647,7 +674,7 @@ module.exports = {
functions: applyTablePermissionRole(opened.structure.functions, 'functions'),
triggers: applyTablePermissionRole(opened.structure.triggers, 'triggers'),
collections: applyTablePermissionRole(opened.structure.collections, 'collections'),
}
};
return res;
}
@@ -881,17 +908,17 @@ module.exports = {
return {
...(command == 'backup'
? driver.backupDatabaseCommand(
connection,
{ outputFile, database, options, selectedTables, skippedTables, argsFormat },
// @ts-ignore
externalTools
)
connection,
{ outputFile, database, options, selectedTables, skippedTables, argsFormat },
// @ts-ignore
externalTools
)
: driver.restoreDatabaseCommand(
connection,
{ inputFile, database, options, argsFormat },
// @ts-ignore
externalTools
)),
connection,
{ inputFile, database, options, argsFormat },
// @ts-ignore
externalTools
)),
transformMessage: driver.transformNativeCommandMessage
? message => driver.transformNativeCommandMessage(message, command)
: null,
@@ -990,7 +1017,10 @@ module.exports = {
async executeSessionQuery({ sesid, conid, database, sql }, req) {
await testConnectionPermission(conid, req);
logger.info({ sesid, sql }, 'DBGM-00010 Processing query');
sessions.dispatchMessage(sesid, 'Query execution started');
sessions.dispatchMessage(sesid, {
message: 'Query execution started',
sql,
});
const opened = await this.ensureOpened(conid, database);
opened.subprocess.send({ msgtype: 'executeSessionQuery', sql, sesid });
+20 -1
View File
@@ -83,6 +83,16 @@ module.exports = {
socket.emit(`session-recordset-${sesid}`, { jslid, resultIndex });
},
handle_endrecordset(sesid, props) {
const { jslid, rowCount, durationMs } = props;
this.dispatchMessage(sesid, {
message: `Query returned ${rowCount} rows in ${durationMs} ms`,
rowCount,
durationMs,
jslid,
});
},
handle_stats(sesid, stats) {
jsldata.notifyChangedStats(stats);
},
@@ -97,6 +107,12 @@ module.exports = {
socket.emit(`session-initialize-file-${jslid}`);
},
handle_changedCurrentDatabase(sesid, props) {
const { database } = props;
this.dispatchMessage(sesid, `Current database changed to ${database}`);
socket.emit(`session-changedb-${sesid}`, { database });
},
handle_ping() {},
create_meta: true,
@@ -182,7 +198,10 @@ module.exports = {
});
logger.info({ sesid, sql }, 'DBGM-00019 Processing query');
this.dispatchMessage(sesid, 'Query execution started');
this.dispatchMessage(sesid, {
message: 'Query execution started',
sql,
});
session.subprocess.send({
msgtype: 'executeQuery',
sql,
+38 -1
View File
@@ -1533,6 +1533,12 @@ module.exports = {
"columnName": "name",
"dataType": "varchar(250)",
"notNull": true
},
{
"pureName": "team_file_types",
"columnName": "format",
"dataType": "varchar(50)",
"notNull": false
}
],
"foreignKeys": [],
@@ -1549,7 +1555,38 @@ module.exports = {
"preloadedRows": [
{
"id": -1,
"name": "sql"
"name": "sql",
"format": "text"
},
{
"id": -2,
"name": "diagrams",
"format": "json"
},
{
"id": -3,
"name": "query",
"format": "json"
},
{
"id": -4,
"name": "perspectives",
"format": "json"
},
{
"id": -5,
"name": "impexp",
"format": "json"
},
{
"id": -6,
"name": "shell",
"format": "text"
},
{
"id": -7,
"name": "dbcompare",
"format": "json"
}
]
},
+13 -6
View File
@@ -193,7 +193,7 @@ async function getCloudSigninHeaders(holder = null) {
return null;
}
async function updateCloudFiles(isRefresh) {
async function updateCloudFiles(isRefresh, language) {
let lastCloudFilesTags;
try {
lastCloudFilesTags = await fs.readFile(path.join(datadir(), 'cloud-files-tags.txt'), 'utf-8');
@@ -218,6 +218,7 @@ async function updateCloudFiles(isRefresh) {
...getLicenseHttpHeaders(),
...(await getCloudInstanceHeaders()),
'x-app-version': currentVersion.version,
'x-app-language': language || 'en',
},
}
);
@@ -274,7 +275,7 @@ async function ensurePromoWidgetDataLoaded() {
promoWidgetDataLoaded = true;
}
async function updatePremiumPromoWidget() {
async function updatePremiumPromoWidget(language) {
await ensurePromoWidgetDataLoaded();
const tags = (await collectCloudFilesSearchTags()).join(',');
@@ -283,8 +284,10 @@ async function updatePremiumPromoWidget() {
`${DBGATE_CLOUD_URL}/premium-promo-widget?identifier=${promoWidgetData?.identifier ?? 'empty'}&tags=${tags}`,
{
headers: {
...getLicenseHttpHeaders(),
...(await getCloudInstanceHeaders()),
'x-app-version': currentVersion.version,
'x-app-language': language || 'en',
},
}
);
@@ -299,17 +302,21 @@ async function updatePremiumPromoWidget() {
socket.emitChanged(`promo-widget-changed`);
}
async function refreshPublicFiles(isRefresh) {
async function refreshPublicFiles(isRefresh, uiLanguage) {
const language = platformInfo.isElectron
? (await config.getCachedSettings())?.['localization.language'] || 'en'
: uiLanguage;
if (!cloudFiles) {
await loadCloudFiles();
}
try {
await updateCloudFiles(isRefresh);
await updateCloudFiles(isRefresh, language);
} catch (err) {
logger.error(extractErrorLogData(err), 'DBGM-00166 Error updating cloud files');
}
if (!isProApp()) {
await updatePremiumPromoWidget();
const configSettings = await config.get();
if (!isProApp() || configSettings?.trialDaysLeft != null) {
await updatePremiumPromoWidget(language);
}
}
+18 -3
View File
@@ -14,9 +14,10 @@ class QueryStreamTableWriter {
this.currentChangeIndex = 1;
this.initializedFile = false;
this.sesid = sesid;
this.started = new Date().getTime();
}
initializeFromQuery(structure, resultIndex, chartDefinition, autoDetectCharts = false) {
initializeFromQuery(structure, resultIndex, chartDefinition, autoDetectCharts = false, options = {}) {
this.jslid = crypto.randomUUID();
this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
fs.writeFileSync(
@@ -24,6 +25,7 @@ class QueryStreamTableWriter {
JSON.stringify({
...structure,
__isStreamHeader: true,
...options
}) + '\n'
);
this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' });
@@ -118,6 +120,13 @@ class QueryStreamTableWriter {
this.chartProcessor = null;
}
}
process.send({
msgtype: 'endrecordset',
jslid: this.jslid,
rowCount: this.currentRowCount,
sesid: this.sesid,
durationMs: new Date().getTime() - this.started,
});
resolve();
});
} else {
@@ -148,6 +157,7 @@ class StreamHandler {
// this.error = this.error.bind(this);
this.done = this.done.bind(this);
this.info = this.info.bind(this);
this.changedCurrentDatabase = this.changedCurrentDatabase.bind(this);
// use this for cancelling - not implemented
// this.stream = null;
@@ -166,7 +176,11 @@ class StreamHandler {
}
}
recordset(columns) {
changedCurrentDatabase(database) {
process.send({ msgtype: 'changedCurrentDatabase', database, sesid: this.sesid });
}
recordset(columns, options) {
if (this.rowsLimitOverflow) {
return;
}
@@ -176,7 +190,8 @@ class StreamHandler {
Array.isArray(columns) ? { columns } : columns,
this.queryStreamInfoHolder.resultIndex,
this.frontMatter?.[`chart-${this.queryStreamInfoHolder.resultIndex + 1}`],
this.autoDetectCharts
this.autoDetectCharts,
options
);
this.queryStreamInfoHolder.resultIndex += 1;
this.rowCounter = 0;
+1
View File
@@ -2,4 +2,5 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleFileExtensions: ['js'],
reporters: ['default', 'github-actions'],
};
+7 -7
View File
@@ -103,11 +103,11 @@ export class TableGridDisplay extends GridDisplay {
isChecked: this.isColumnChecked(col),
hintColumnNames:
this.getFkDictionaryDescription(col.isForeignKeyUnique ? col.foreignKey : null)?.columns?.map(columnName =>
shortenIdentifier(`hint_${col.uniqueName}_${columnName}`, this.driver.dialect.maxIdentifierLength)
shortenIdentifier(`hint_${col.uniqueName}_${columnName}`, this.driver?.dialect?.maxIdentifierLength)
) || null,
hintColumnDelimiter: this.getFkDictionaryDescription(col.isForeignKeyUnique ? col.foreignKey : null)
?.delimiter,
uniqueNameShorten: shortenIdentifier(col.uniqueName, this.driver.dialect.maxIdentifierLength),
uniqueNameShorten: shortenIdentifier(col.uniqueName, this.driver?.dialect?.maxIdentifierLength),
isExpandable: !!col.foreignKey,
})) || []
);
@@ -118,7 +118,7 @@ export class TableGridDisplay extends GridDisplay {
if (this.isExpandedColumn(column.uniqueName)) {
const table = this.getFkTarget(column);
if (table) {
const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength);
const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver?.dialect?.maxIdentifierLength);
const subcolumns = this.getDisplayColumns(table, column.uniquePath);
this.addReferenceToSelect(select, parentAlias, column);
@@ -131,7 +131,7 @@ export class TableGridDisplay extends GridDisplay {
}
addReferenceToSelect(select: Select, parentAlias: string, column: DisplayColumn) {
const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength);
const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver?.dialect?.maxIdentifierLength);
if ((select.from.relations || []).find(x => x.alias == childAlias)) return;
const table = this.getFkTarget(column);
if (table && table.primaryKey) {
@@ -196,11 +196,11 @@ export class TableGridDisplay extends GridDisplay {
this.addReferenceToSelect(
select,
parentUniqueName
? shortenIdentifier(`${parentUniqueName}_ref`, this.driver.dialect.maxIdentifierLength)
? shortenIdentifier(`${parentUniqueName}_ref`, this.driver?.dialect?.maxIdentifierLength)
: 'basetbl',
column
);
const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength);
const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver?.dialect?.maxIdentifierLength);
select.columns.push(
...hintDescription.columns.map(
columnName =>
@@ -209,7 +209,7 @@ export class TableGridDisplay extends GridDisplay {
columnName,
alias: shortenIdentifier(
`hint_${column.uniqueName}_${columnName}`,
this.driver.dialect.maxIdentifierLength
this.driver?.dialect?.maxIdentifierLength
),
source: { alias: childAlias },
} as ColumnRefExpression)
+14 -1
View File
@@ -35,6 +35,12 @@ program
.option('-u, --user <user>', 'user name')
.option('-p, --password <password>', 'password')
.option('-d, --database <database>', 'database name')
.option('--url <url>', 'database url')
.option('--file <file>', 'database file')
.option('--socket-path <socketPath>', 'socket path')
.option('--service-name <serviceName>', 'service name (for Oracle)')
.option('--auth-type <authType>', 'authentication type')
.option('--use-ssl', 'use SSL connection')
.option('--auto-index-foreign-keys', 'automatically adds indexes to all foreign keys')
.option(
'--load-data-condition <condition>',
@@ -48,7 +54,7 @@ program
.command('deploy <modelFolder>')
.description('Deploys model to database')
.action(modelFolder => {
const { engine, server, user, password, database, transaction } = program.opts();
const { engine, server, user, password, database, url, file, transaction } = program.opts();
// const hooks = [];
// if (program.autoIndexForeignKeys) hooks.push(dbmodel.hooks.autoIndexForeignKeys);
@@ -60,6 +66,13 @@ program
user,
password,
database,
databaseUrl: url,
useDatabaseUrl: !!url,
databaseFile: file,
socketPath: program.socketPath,
serviceName: program.serviceName,
authType: program.authType,
useSsl: program.useSsl,
},
modelFolder,
useTransaction: transaction,
+1
View File
@@ -2,4 +2,5 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleFileExtensions: ['js'],
reporters: ['default', 'github-actions'],
};
+4 -2
View File
@@ -1,4 +1,4 @@
import { arrayToHexString, evalFilterBehaviour, isTypeDateTime } from 'dbgate-tools';
import { arrayToHexString, base64ToHex, evalFilterBehaviour, isTypeDateTime } from 'dbgate-tools';
import { format, toDate } from 'date-fns';
import _isString from 'lodash/isString';
import _cloneDeepWith from 'lodash/cloneDeepWith';
@@ -24,7 +24,9 @@ export function getFilterValueExpression(value, dataType?) {
if (value.type == 'Buffer' && Array.isArray(value.data)) {
return '0x' + arrayToHexString(value.data);
}
if (value?.$binary?.base64) {
return base64ToHex(value.$binary.base64);
}
return `="${value}"`;
}
+2 -5
View File
@@ -2,7 +2,7 @@ import P from 'parsimmon';
import moment from 'moment';
import { Condition } from 'dbgate-sqltree';
import { interpretEscapes, token, word, whitespace } from './common';
import { hexStringToArray, parseNumberSafe } from 'dbgate-tools';
import { hexToBase64, parseNumberSafe } from 'dbgate-tools';
import { FilterBehaviour, TransformType } from 'dbgate-types';
const binaryCondition =
@@ -385,10 +385,7 @@ const createParser = (filterBehaviour: FilterBehaviour) => {
hexstring: () =>
token(P.regexp(/0x(([0-9a-fA-F][0-9a-fA-F])+)/, 1))
.map(x => ({
type: 'Buffer',
data: hexStringToArray(x),
}))
.map(x => ({ $binary: { base64: hexToBase64(x) } }))
.desc('hex string'),
noQuotedString: () => P.regexp(/[^\s^,^'^"]+/).desc('string unquoted'),
+5 -2
View File
@@ -1,7 +1,7 @@
import type { SqlDumper } from 'dbgate-types';
import { Command, Select, Update, Delete, Insert } from './types';
import { dumpSqlExpression } from './dumpSqlExpression';
import { dumpSqlFromDefinition, dumpSqlSourceRef } from './dumpSqlSource';
import { dumpSqlFromDefinition, dumpSqlSourceDef, dumpSqlSourceRef } from './dumpSqlSource';
import { dumpSqlCondition } from './dumpSqlCondition';
export function dumpSqlSelect(dmp: SqlDumper, cmd: Select) {
@@ -115,7 +115,10 @@ export function dumpSqlInsert(dmp: SqlDumper, cmd: Insert) {
cmd.fields.map(x => x.targetColumn)
);
dmp.putCollection(',', cmd.fields, x => dumpSqlExpression(dmp, x));
if (dmp.dialect.requireFromDual) {
if (cmd.whereNotExistsSource) {
dmp.put(' ^from ');
dumpSqlSourceDef(dmp, cmd.whereNotExistsSource);
} else if (dmp.dialect.requireFromDual) {
dmp.put(' ^from ^dual ');
}
dmp.put(' ^where ^not ^exists (^select * ^from %f ^where ', cmd.targetTable);
@@ -2,6 +2,7 @@ import _ from 'lodash';
import type { SqlDumper } from 'dbgate-types';
import { Expression, ColumnRefExpression } from './types';
import { dumpSqlSourceRef } from './dumpSqlSource';
import { dumpSqlSelect } from './dumpSqlCommand';
export function dumpSqlExpression(dmp: SqlDumper, expr: Expression) {
switch (expr.exprType) {
@@ -67,5 +68,11 @@ export function dumpSqlExpression(dmp: SqlDumper, expr: Expression) {
});
dmp.put(')');
break;
case 'select':
dmp.put('(');
dumpSqlSelect(dmp, expr.select);
dmp.put(')');
break;
}
}
+8 -1
View File
@@ -44,6 +44,7 @@ export interface Insert {
fields: UpdateField[];
targetTable: NamedObjectInfo;
insertWhereNotExistsCondition?: Condition;
whereNotExistsSource?: Source;
}
export interface AllowIdentityInsert {
@@ -226,6 +227,11 @@ export interface RowNumberExpression {
orderBy: OrderByExpression[];
}
export interface SelectExpression {
exprType: 'select';
select: Select;
}
export type Expression =
| ColumnRefExpression
| ValueExpression
@@ -235,7 +241,8 @@ export type Expression =
| CallExpression
| MethodCallExpression
| TranformExpression
| RowNumberExpression;
| RowNumberExpression
| SelectExpression;
export type OrderByExpression = Expression & { direction: 'ASC' | 'DESC' };
export type ResultField = Expression & { alias?: string };
+1
View File
@@ -2,4 +2,5 @@ module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
moduleFileExtensions: ['js'],
reporters: ['default', 'github-actions'],
};
+1 -1
View File
@@ -33,7 +33,7 @@
},
"dependencies": {
"blueimp-md5": "^2.19.0",
"dbgate-query-splitter": "^4.11.7",
"dbgate-query-splitter": "^4.11.9",
"dbgate-sqltree": "^6.0.0-alpha.1",
"debug": "^4.3.4",
"json-stable-stringify": "^1.0.1",
+8
View File
@@ -78,6 +78,14 @@ export class SqlDumper implements AlterProcessor {
else if (_isNumber(value)) this.putRaw(value.toString());
else if (_isDate(value)) this.putStringValue(new Date(value).toISOString());
else if (value?.type == 'Buffer' && _isArray(value?.data)) this.putByteArrayValue(value?.data);
else if (value?.$binary?.base64) {
const binary = atob(value.$binary.base64);
const bytes = new Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
this.putByteArrayValue(bytes);
}
else if (value?.$bigint) this.putRaw(value?.$bigint);
else if (_isPlainObject(value) || _isArray(value)) this.putStringValue(JSON.stringify(value));
else this.put('^null');
+1
View File
@@ -47,6 +47,7 @@ export const mongoFilterBehaviour: FilterBehaviour = {
allowStringToken: true,
allowNumberDualTesting: true,
allowObjectIdTesting: true,
allowHexString: true,
};
export const evalFilterBehaviour: FilterBehaviour = {
+19
View File
@@ -1,4 +1,5 @@
import _cloneDeep from 'lodash/cloneDeep';
import _uniq from 'lodash/uniq';
import _isString from 'lodash/isString';
import type {
ColumnInfo,
@@ -75,9 +76,27 @@ export function findForeignKeyForColumn(table: TableInfo, column: ColumnInfo | s
return (table.foreignKeys || []).find(fk => fk.columns.find(col => col.columnName == column.columnName));
}
export function getConflictingColumnNames(columns: ColumnInfo[]): Set<string> {
const conflictingNames = new Set(
_uniq(columns.map(x => x.columnName).filter((item, index, arr) => arr.indexOf(item) !== index))
);
return conflictingNames;
}
export function makeUniqueColumnNames(res: ColumnInfo[]) {
const usedNames = new Set();
const conflictingNames = getConflictingColumnNames(res);
for (let i = 0; i < res.length; i++) {
if (
conflictingNames.has(res[i].columnName) &&
res[i].pureName &&
!usedNames.has(`${res[i].pureName}_${res[i].columnName}`)
) {
res[i].columnName = `${res[i].pureName}_${res[i].columnName}`;
usedNames.add(res[i].columnName);
continue;
}
if (usedNames.has(res[i].columnName)) {
let suffix = 2;
while (usedNames.has(`${res[i].columnName}${suffix}`)) suffix++;
+32 -7
View File
@@ -43,6 +43,19 @@ export function hexStringToArray(inputString) {
return res;
}
export function base64ToHex(base64String) {
const binaryString = atob(base64String);
const hexString = Array.from(binaryString, c =>
c.charCodeAt(0).toString(16).padStart(2, '0')
).join('');
return '0x' + hexString.toUpperCase();
};
export function hexToBase64(hexString) {
const binaryString = hexString.match(/.{1,2}/g).map(byte => String.fromCharCode(parseInt(byte, 16))).join('');
return btoa(binaryString);
}
export function parseCellValue(value, editorTypes?: DataEditorTypesBehaviour) {
if (!_isString(value)) return value;
@@ -54,9 +67,10 @@ export function parseCellValue(value, editorTypes?: DataEditorTypesBehaviour) {
const mHex = value.match(/^0x([0-9a-fA-F][0-9a-fA-F])+$/);
if (mHex) {
return {
type: 'Buffer',
data: hexStringToArray(value.substring(2)),
};
$binary: {
base64: hexToBase64(value.substring(2))
}
}
}
}
@@ -230,11 +244,19 @@ export function stringifyCellValue(
if (value === true) return { value: 'true', gridStyle: 'valueCellStyle' };
if (value === false) return { value: 'false', gridStyle: 'valueCellStyle' };
if (editorTypes?.parseHexAsBuffer) {
if (value?.type == 'Buffer' && _isArray(value.data)) {
return { value: '0x' + arrayToHexString(value.data), gridStyle: 'valueCellStyle' };
}
if (value?.$binary?.base64) {
return {
value: base64ToHex(value.$binary.base64),
gridStyle: 'valueCellStyle',
};
}
if (editorTypes?.parseHexAsBuffer) {
// if (value?.type == 'Buffer' && _isArray(value.data)) {
// return { value: '0x' + arrayToHexString(value.data), gridStyle: 'valueCellStyle' };
// }
}
if (editorTypes?.parseObjectIdAsDollar) {
if (value?.$oid) {
switch (intent) {
@@ -482,6 +504,9 @@ export function getAsImageSrc(obj) {
if (obj?.type == 'Buffer' && _isArray(obj?.data)) {
return `data:image/png;base64, ${arrayBufferToBase64(obj?.data)}`;
}
if (obj?.$binary?.base64) {
return `data:image/png;base64, ${obj.$binary.base64}`;
}
if (_isString(obj) && (obj.startsWith('http://') || obj.startsWith('https://'))) {
return obj;
+1
View File
@@ -16,6 +16,7 @@ export interface SqlDumper extends AlterProcessor {
transform(type: TransformType, dumpExpr: () => void);
createDatabase(name: string);
dropDatabase(name: string);
comment(value: string);
callableTemplate(func: CallableObjectInfo);
+1
View File
@@ -21,6 +21,7 @@ export interface StreamOptions {
error?: (error) => void;
done?: (result) => void;
info?: (info) => void;
changedCurrentDatabase?: (database: string) => void;
}
export type CollectionOperationInfo =
+2
View File
@@ -96,4 +96,6 @@ export type TestEngineInfo = {
}>;
objects?: Array<TestObjectInfo>;
binaryDataType?: string;
};
+13 -2
View File
@@ -26,12 +26,23 @@
<script lang="javascript">
window.dbgate_page = '{{page}}';
</script>
if (localStorage.getItem('currentThemeType') == 'dark') {
document.documentElement.style.setProperty('--theme-background', '#111');
document.documentElement.style.setProperty('--theme-foreground', '#e3e3e3');
} else {
document.documentElement.style.setProperty('--theme-background', '#fff');
document.documentElement.style.setProperty('--theme-foreground', '#262626');
}
</script>
<script defer src="build/bundle.js"></script>
<style>
body {
background-color: var(--theme-background);
}
.lds-ellipsis {
display: inline-block;
position: relative;
@@ -44,7 +55,7 @@
width: 13px;
height: 13px;
border-radius: 50%;
background: #000;
background: var(--theme-foreground);
animation-timing-function: cubic-bezier(0, 1, 1, 0);
}
.lds-ellipsis div:nth-child(1) {
+1 -1
View File
@@ -32,7 +32,7 @@
"chartjs-plugin-datalabels": "^2.2.0",
"cross-env": "^7.0.3",
"dbgate-datalib": "^6.0.0-alpha.1",
"dbgate-query-splitter": "^4.11.7",
"dbgate-query-splitter": "^4.11.9",
"dbgate-sqltree": "^6.0.0-alpha.1",
"dbgate-tools": "^6.0.0-alpha.1",
"dbgate-types": "^6.0.0-alpha.1",
+8 -1
View File
@@ -27,7 +27,7 @@
import SettingsListener from './utility/SettingsListener.svelte';
import { handleAuthOnStartup } from './clientAuth';
import { initializeAppUpdates } from './utility/appUpdate';
import { _t } from './translations';
import { _t, getCurrentTranslations, saveSelectedLanguageToCache } from './translations';
import { installCloudListeners } from './utility/cloudListeners';
export let isAdminPage = false;
@@ -61,6 +61,13 @@
initializeAppUpdates();
installCloudListeners();
refreshPublicCloudFiles();
saveSelectedLanguageToCache(config.preferrendLanguage);
const electron = getElectron();
if (electron) {
electron.send('translation-data', JSON.stringify(getCurrentTranslations()));
global.TRANSLATION_DATA = getCurrentTranslations();
}
}
loadedApi = loadedApiValue;
+113 -69
View File
@@ -14,6 +14,7 @@
import ErrorInfo from './elements/ErrorInfo.svelte';
import { isOneOfPage } from './utility/pageDefs';
import { openWebLink } from './utility/simpleTools';
import FontIcon from './icons/FontIcon.svelte';
const config = useConfig();
const values = writable({ amoid: null, databaseServer: null });
@@ -22,17 +23,15 @@
$: trialDaysLeft = $config?.trialDaysLeft;
let errorMessage = '';
let expiredMessageSet = false;
$: if (isExpired && !expiredMessageSet) {
errorMessage = 'Your license is expired';
expiredMessageSet = true;
}
let isInsertingLicense = false;
$: trialButtonAvailable = !isExpired && trialDaysLeft == null;
// $: console.log('CONFIG', $config);
$: {
if ($config?.isLicenseValid) {
if ($config?.isLicenseValid && trialDaysLeft == null) {
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
}
}
@@ -41,83 +40,124 @@
<FormProviderCore {values}>
<SpecialPageLayout>
{#if getElectron() || ($config?.storageDatabase && hasPermission('admin/license'))}
<div class="heading">License</div>
<FormTextAreaField label="Enter your license key" name="licenseKey" rows={5} />
<div class="heading">Thank you for using DbGate!</div>
<div class="submit">
<FormSubmit
value="Save license"
on:click={async e => {
sessionStorage.setItem('continueTrialConfirmed', '1');
const { licenseKey } = e.detail;
const resp = await apiCall('config/save-license-key', { licenseKey, tryToRenew: true });
if (resp?.status == 'ok') {
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
} else {
errorMessage = resp?.errorMessage || 'Error saving license key';
}
}}
/>
</div>
{#if isExpired}
<div class="infotext"><FontIcon icon="img warn" /> Your license has expired. Please insert new license.</div>
{:else if trialDaysLeft > 0}
<div class="infotext">
<FontIcon icon="img warn" /> Your trial period will expire in {trialDaysLeft} day{trialDaysLeft != 1
? 's'
: ''}.
</div>
{:else}
<div class="infotext">
<FontIcon icon="img info" /> Proceed by selecting a licensing option or providing your license key.
</div>
{/if}
{#if !isExpired && trialDaysLeft == null}
{#if isInsertingLicense}
<FormTextAreaField label="Enter your license key" name="licenseKey" rows={5} />
<div class="submit">
<div class="flex flex1">
<div class="col-6 flex">
<FormSubmit
value="Save license"
on:click={async e => {
sessionStorage.setItem('continueTrialConfirmed', '1');
const { licenseKey } = e.detail;
const resp = await apiCall('config/save-license-key', { licenseKey, tryToRenew: true });
if (resp?.status == 'ok') {
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
} else {
errorMessage = resp?.errorMessage || 'Error saving license key';
}
}}
/>
</div>
<div class="col-6 flex">
<FormStyledButton
value="Cancel"
on:click={() => {
isInsertingLicense = false;
errorMessage = '';
}}
/>
</div>
</div>
</div>
{/if}
{#if !isInsertingLicense}
<div class="submit">
<FormStyledButton
value="Start 30-day trial"
on:click={async e => {
errorMessage = '';
const license = await apiCall('config/start-trial');
if (license?.status == 'ok') {
value="Insert license key"
on:click={() => {
isInsertingLicense = true;
}}
/>
</div>
{#if trialButtonAvailable}
<div class="submit">
<FormStyledButton
value="Start 30-day trial"
on:click={async e => {
errorMessage = '';
const license = await apiCall('config/start-trial');
if (license?.status == 'ok') {
sessionStorage.setItem('continueTrialConfirmed', '1');
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
} else {
errorMessage = license?.errorMessage || 'Error starting trial';
}
}}
/>
</div>
{/if}
{#if trialDaysLeft > 0}
<div class="submit">
<FormStyledButton
value={`Continue trial (${trialDaysLeft} days left)`}
on:click={async e => {
sessionStorage.setItem('continueTrialConfirmed', '1');
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
} else {
errorMessage = license?.errorMessage || 'Error starting trial';
}
}}
/>
</div>
{/if}
}}
/>
</div>
{/if}
{#if trialDaysLeft > 0}
<div class="submit">
<FormStyledButton
value={`Continue trial (${trialDaysLeft} days left)`}
value="Purchase DbGate Premium"
on:click={async e => {
sessionStorage.setItem('continueTrialConfirmed', '1');
internalRedirectTo(isOneOfPage('admin-license') ? '/admin.html' : '/index.html');
// openWebLink(
// `https://auth.dbgate.eu/create-checkout-session-simple?source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
// );
// openWebLink(
// `https://auth-proxy.dbgate.udolni.net/redirect-to-purchase?product=${getElectron() ? 'premium' : 'teram-premium'}&source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
// );
openWebLink(
`https://auth.dbgate.eu/redirect-to-purchase?product=${getElectron() ? 'premium' : 'team-premium'}&source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
);
}}
/>
</div>
{/if}
<div class="submit">
<FormStyledButton
value="Purchase DbGate Premium"
on:click={async e => {
// openWebLink(
// `https://auth.dbgate.eu/create-checkout-session-simple?source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
// );
// openWebLink(
// `https://auth-proxy.dbgate.udolni.net/redirect-to-purchase?product=${getElectron() ? 'premium' : 'teram-premium'}&source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
// );
openWebLink(
`https://auth.dbgate.eu/redirect-to-purchase?product=${getElectron() ? 'premium' : 'team-premium'}&source=trial-${isExpired ? 'expired' : (trialDaysLeft ?? 'no')}`
);
}}
/>
</div>
{#if getElectron()}
<div class="submit">
<FormStyledButton
value="Exit"
on:click={e => {
getElectron().send('quit-app');
}}
/>
</div>
{#if getElectron()}
<div class="submit">
<FormStyledButton
value="Exit"
on:click={e => {
getElectron().send('quit-app');
}}
/>
</div>
{/if}
{/if}
{#if errorMessage}
@@ -141,6 +181,10 @@
font-size: xx-large;
}
.infotext {
margin: 1em;
}
.submit {
margin: var(--dim-large-form-margin);
display: flex;
+1 -1
View File
@@ -16,7 +16,7 @@
<div class="heading">Configuration error</div>
{#if $config?.checkedLicense?.status == 'error'}
<ErrorInfo
message={`Invalid license. Please contact sales@dbgate.io for more details. ${$config?.checkedLicense?.error}`}
message={`Invalid license. Please contact sales@dbgate.io for more details. ${$config?.checkedLicense?.error || ''}`}
/>
{:else if $config?.configurationError}
<ErrorInfo message={$config?.configurationError} />
+15 -2
View File
@@ -8,6 +8,7 @@
import Link from '../elements/Link.svelte';
import { focusedConnectionOrDatabase } from '../stores';
import { tick } from 'svelte';
import { _tval } from '../translations';
export let list;
export let module;
@@ -38,8 +39,19 @@
$: matcher = module.createMatcher && module.createMatcher(filter, passProps?.searchSettings);
$: listTranslated = (list || []).map(data => ({
...data,
group: data?.group && _tval(data.group),
title: data?.title && _tval(data.title),
description: data?.description && _tval(data.description),
args: (data?.args || []).map(x => ({
...x,
label: x?.label && _tval(x.label),
})),
}));
$: dataLabeled = _.compact(
(list || []).map(data => {
(listTranslated || []).map(data => {
const matchResult = matcher ? matcher(data) : true;
let isMatched = true;
@@ -102,7 +114,8 @@
$: groups = groupFunc ? extendGroups(_.groupBy(dataLabeled, 'group'), emptyGroupNames) : null;
$: listLimited = isExpandedBySearch && !expandLimited ? filtered.slice(0, filter.trim().length < 3 ? 1 : 3) : list;
$: listLimited =
isExpandedBySearch && !expandLimited ? filtered.slice(0, filter.trim().length < 3 ? 1 : 3) : listTranslated;
$: isListLimited = isExpandedBySearch && listLimited.length < filtered.length;
$: listMissingItems = isListLimited ? filtered.slice(listLimited.length) : [];
@@ -446,8 +446,7 @@ await dbgateApi.executeQuery(${JSON.stringify(
driver?.databaseEngineTypes?.includes('document') && {
onClick: handleNewCollection,
text: _t('database.newCollection', {
defaultMessage: 'New {collectionLabel}',
values: { collectionLabel: driver?.collectionSingularLabel ?? 'collection/container' },
defaultMessage: 'New collection/container'
}),
},
hasPermission(`dbops/query`) &&
@@ -1,5 +1,7 @@
<script lang="ts" context="module">
import { copyTextToClipboard } from '../utility/clipboard';
import { _t, _tval, DefferedTranslationResult } from '../translations';
import sqlFormatter from 'sql-formatter';
export const extractKey = ({ schemaName, pureName }) => (schemaName ? `${schemaName}.${pureName}` : pureName);
export const createMatcher =
@@ -69,13 +71,13 @@
function createScriptTemplatesSubmenu(objectTypeField) {
return {
label: 'SQL template',
label: _t('dbObject.sqlTemplate', { defaultMessage: 'SQL template' }),
submenu: getSupportedScriptTemplates(objectTypeField),
};
}
interface DbObjMenuItem {
label?: string;
label?: string | DefferedTranslationResult;
tab?: string;
forceNewTab?: boolean;
initialData?: any;
@@ -87,7 +89,8 @@
isRename?: boolean;
isTruncate?: boolean;
isCopyTableName?: boolean;
isDuplicateTable?: boolean;
isTableBackup?: boolean;
isTableRestore?: boolean;
isDiagram?: boolean;
functionName?: string;
isExport?: boolean;
@@ -105,6 +108,8 @@
}
function createMenusCore(objectTypeField, driver, data): DbObjMenuItem[] {
const backupMatch = data.objectTypeField === 'tables' ? data.pureName.match(TABLE_BACKUP_REGEX) : null;
switch (objectTypeField) {
case 'tables':
return [
@@ -113,19 +118,19 @@
divider: true,
},
isProApp() && {
label: 'Design query',
label: _t('dbObject.designQuery', { defaultMessage: 'Design query' }),
isQueryDesigner: true,
requiresWriteAccess: true,
},
isProApp() && {
label: 'Design perspective query',
label: _t('dbObject.designPerspectiveQuery', { defaultMessage: 'Design perspective query' }),
tab: 'PerspectiveTab',
forceNewTab: true,
icon: 'img perspective',
},
createScriptTemplatesSubmenu('tables'),
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE TABLE',
@@ -154,33 +159,40 @@
divider: true,
},
hasPermission('dbops/model/edit') && {
label: 'Drop table',
label: _t('dbObject.dropTable', { defaultMessage: 'Drop table' }),
isDrop: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/rename') &&
!driver?.dialect.disableRenameTable && {
label: 'Rename table',
label: _t('dbObject.renameTable', { defaultMessage: 'Rename table' }),
isRename: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/truncate') && {
label: 'Truncate table',
label: _t('dbObject.truncateTable', { defaultMessage: 'Truncate table' }),
isTruncate: true,
requiresWriteAccess: true,
},
{
label: 'Copy table name',
label: _t('dbObject.copyTableName', { defaultMessage: 'Copy table name' }),
isCopyTableName: true,
requiresWriteAccess: false,
},
hasPermission('dbops/table/backup') && {
label: 'Create table backup',
isDuplicateTable: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/backup') &&
!backupMatch && {
label: _t('dbObject.createTableBackup', { defaultMessage: 'Create table backup' }),
isTableBackup: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/restore') &&
backupMatch && {
label: _t('dbObject.createRestoreScript', { defaultMessage: 'Create restore script' }),
isTableRestore: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/view') && {
label: 'Show diagram',
label: _t('dbObject.showDiagram', { defaultMessage: 'Show diagram' }),
isDiagram: true,
},
{
@@ -204,18 +216,18 @@
divider: true,
},
isProApp() && {
label: 'Design query',
label: _t('dbObject.designQuery', { defaultMessage: 'Design query' }),
isQueryDesigner: true,
},
isProApp() && {
label: 'Design perspective query',
label: _t('dbObject.designPerspectiveQuery', { defaultMessage: 'Design perspective query' }),
tab: 'PerspectiveTab',
forceNewTab: true,
icon: 'img perspective',
},
createScriptTemplatesSubmenu('views'),
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE VIEW',
@@ -235,12 +247,12 @@
divider: true,
},
hasPermission('dbops/model/edit') && {
label: 'Drop view',
label: _t('dbObject.dropView', { defaultMessage: 'Drop view' }),
isDrop: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/edit') && {
label: 'Rename view',
label: _t('dbObject.renameView', { defaultMessage: 'Rename view' }),
isRename: true,
requiresWriteAccess: true,
},
@@ -260,12 +272,12 @@
divider: true,
},
hasPermission('dbops/model/edit') && {
label: 'Drop view',
label: _t('dbObject.dropView', { defaultMessage: 'Drop view' }),
isDrop: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/edit') && {
label: 'Rename view',
label: _t('dbObject.renameView', { defaultMessage: 'Rename view' }),
isRename: true,
requiresWriteAccess: true,
},
@@ -273,12 +285,12 @@
divider: true,
},
{
label: 'Query designer',
label: _t('dbObject.queryDesigner', { defaultMessage: 'Query designer' }),
isQueryDesigner: true,
},
createScriptTemplatesSubmenu('matviews'),
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE MATERIALIZED VIEW',
@@ -306,7 +318,7 @@
case 'queries':
return [
{
label: 'Open data',
label: _t('dbObject.openData', { defaultMessage: 'Open data' }),
tab: 'QueryDataTab',
forceNewTab: true,
},
@@ -318,18 +330,18 @@
divider: true,
},
hasPermission('dbops/model/edit') && {
label: 'Drop procedure',
label: _t('dbObject.dropProcedure', { defaultMessage: 'Drop procedure' }),
isDrop: true,
requiresWriteAccess: true,
},
hasPermission('dbops/model/edit') && {
label: 'Rename procedure',
label: _t('dbObject.renameProcedure', { defaultMessage: 'Rename procedure' }),
isRename: true,
requiresWriteAccess: true,
},
createScriptTemplatesSubmenu('procedures'),
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE PROCEDURE',
@@ -352,7 +364,7 @@
return [
...defaultDatabaseObjectAppObjectActions['triggers'],
hasPermission('dbops/model/edit') && {
label: 'Drop trigger',
label: _t('dbObject.dropTrigger', { defaultMessage: 'Drop trigger' }),
isDrop: true,
requiresWriteAccess: true,
},
@@ -360,7 +372,7 @@
divider: true,
},
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE TRIGGER',
@@ -384,7 +396,7 @@
divider: true,
},
isProApp() && {
label: 'Design perspective query',
label: _t('dbObject.designPerspectiveQuery', { defaultMessage: 'Design perspective query' }),
tab: 'PerspectiveTab',
forceNewTab: true,
icon: 'img perspective',
@@ -395,17 +407,17 @@
functionName: 'tableReader',
},
hasPermission('dbops/model/edit') && {
label: `Drop ${driver?.collectionSingularLabel ?? 'collection/container'}`,
label: _t('dbObject.dropCollection', { defaultMessage: 'Drop collection/container' }),
isDropCollection: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/rename') && {
label: `Rename ${driver?.collectionSingularLabel ?? 'collection/container'}`,
label: _t('dbObject.renameCollection', { defaultMessage: 'Rename collection/container' }),
isRenameCollection: true,
requiresWriteAccess: true,
},
hasPermission('dbops/table/backup') && {
label: `Create ${driver?.collectionSingularLabel ?? 'collection/container'} backup`,
label: _t('dbObject.createCollectionBackup', { defaultMessage: 'Create collection/container backup' }),
isDuplicateCollection: true,
requiresWriteAccess: true,
},
@@ -418,7 +430,7 @@
const menu: DbObjMenuItem[] = [
...defaultDatabaseObjectAppObjectActions['schedulerEvents'],
hasPermission('dbops/model/edit') && {
label: 'Drop event',
label: _t('dbObject.dropEvent', { defaultMessage: 'Drop event' }),
isDrop: true,
requiresWriteAccess: true,
},
@@ -426,12 +438,12 @@
if (data?.status === 'ENABLED') {
menu.push({
label: 'Disable',
label: _t('dbObject.disable', { defaultMessage: 'Disable' }),
isDisableEvent: true,
});
} else {
menu.push({
label: 'Enable',
label: _t('dbObject.enable', { defaultMessage: 'Enable' }),
isEnableEvent: true,
});
}
@@ -441,7 +453,7 @@
divider: true,
},
{
label: 'SQL generator',
label: _t('dbObject.sqlGenerator', { defaultMessage: 'SQL generator' }),
submenu: [
{
label: 'CREATE SCHEDULER EVENT',
@@ -474,7 +486,7 @@
if (menu.isQueryDesigner) {
openNewTab(
{
title: 'Query #',
title: _t('dbObject.query', { defaultMessage: 'Query #' }),
icon: 'img query-design',
tabComponent: 'QueryDesignTab',
focused: true,
@@ -499,7 +511,7 @@
} else if (menu.isDiagram) {
openNewTab(
{
title: 'Diagram #',
title: _t('dbObject.diagram', { defaultMessage: 'Diagram #' }),
icon: 'img diagram',
tabComponent: 'DiagramTab',
props: {
@@ -589,7 +601,10 @@
});
} else if (menu.isDropCollection) {
showModal(ConfirmModal, {
message: `Really drop collection ${data.pureName}?`,
message: _t('dbObject.confirmDropCollection', {
defaultMessage: 'Really drop collection {name}?',
values: { name: data.pureName },
}),
onConfirm: async () => {
const dbid = _.pick(data, ['conid', 'database']);
runOperationOnDatabase(dbid, {
@@ -603,8 +618,8 @@
} else if (menu.isRenameCollection) {
const driver = await getDriver();
showModal(InputTextModal, {
label: `New ${driver?.collectionSingularLabel ?? 'collection/container'} name`,
header: `Rename ${driver?.collectionSingularLabel ?? 'collection/container'}`,
label: _t('dbObject.newCollectionName', { defaultMessage: 'New collection/container name' }),
header: _t('dbObject.renameCollection', { defaultMessage: 'Rename collection/container' }),
value: data.pureName,
onConfirm: async newName => {
const dbid = _.pick(data, ['conid', 'database']);
@@ -620,7 +635,10 @@
const driver = await getDriver();
showModal(ConfirmModal, {
message: `Really create ${driver?.collectionSingularLabel ?? 'collection/container'} copy named ${newName}?`,
message: _t('dbObject.confirmCloneCollection', {
defaultMessage: 'Really create collection/container copy named {name}?',
values: { name: newName },
}),
onConfirm: async () => {
const dbid = _.pick(data, ['conid', 'database']);
runOperationOnDatabase(dbid, {
@@ -630,7 +648,7 @@
});
},
});
} else if (menu.isDuplicateTable) {
} else if (menu.isTableBackup) {
const driver = await getDriver();
const dmp = driver.createDumper();
const newTable = _.cloneDeep(data);
@@ -664,6 +682,25 @@
},
engine: driver.engine,
});
} else if (menu.isTableRestore) {
const backupMatch = data.objectTypeField === 'tables' ? data.pureName.match(TABLE_BACKUP_REGEX) : null;
const driver = await getDriver();
const dmp = driver.createDumper();
const db = await getDatabaseInfo(data);
if (db) {
const originalTable = db?.tables?.find(x => x.pureName == backupMatch[1] && x.schemaName == data.schemaName);
if (originalTable) {
createTableRestoreScript(data, originalTable, dmp);
newQuery({
title: _t('dbObject.restoreScript', {
defaultMessage: 'Restore {name} #',
values: { name: backupMatch[1] },
}),
initialData: sqlFormatter.format(dmp.s),
});
}
}
} else if (menu.isImport) {
const { conid, database } = data;
openImportExportTab({
@@ -718,7 +755,9 @@
const filteredSumenus = coreMenus.map(item => {
if (!item.submenu) {
return item;
if (!item) return item;
return { ...item, label: _tval(item.label) };
}
return {
...item,
@@ -768,7 +807,9 @@
openNewTab(
{
// title: getObjectTitle(connection, schemaName, pureName),
title: tabComponent ? getObjectTitle(connection, schemaName, pureName) : 'Query #',
title: tabComponent
? getObjectTitle(connection, schemaName, pureName)
: _t('dbObject.query', { defaultMessage: 'Query #' }),
focused: tabComponent == null,
tooltip,
icon:
@@ -997,6 +1038,8 @@
return handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode, focusTab });
}
export const TABLE_BACKUP_REGEX = /^_(.*)_(\d\d\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d)-(\d\d)$/;
</script>
<script lang="ts">
@@ -1014,7 +1057,7 @@
} from '../stores';
import openNewTab from '../utility/openNewTab';
import { extractDbNameFromComposite, filterNameCompoud, getConnectionLabel } from 'dbgate-tools';
import { getConnectionInfo } from '../utility/metadataLoaders';
import { getConnectionInfo, getDatabaseInfo } from '../utility/metadataLoaders';
import fullDisplayName from '../utility/fullDisplayName';
import { showModal } from '../modals/modalTools';
import { findEngineDriver } from 'dbgate-tools';
@@ -1035,6 +1078,9 @@
import { getSupportedScriptTemplates } from '../utility/applyScriptTemplate';
import { getBoolSettingsValue, getOpenDetailOnArrowsSettings } from '../settings/settingsTools';
import { isProApp } from '../utility/proTools';
import formatFileSize from '../utility/formatFileSize';
import { createTableRestoreScript } from '../utility/tableRestoreScript';
import newQuery from '../query/newQuery';
export let data;
export let passProps;
@@ -1063,6 +1109,9 @@
if (data.tableRowCount != null) {
res.push(`${formatRowCount(data.tableRowCount)} rows`);
}
if (data.sizeBytes) {
res.push(formatFileSize(data.sizeBytes));
}
if (data.tableEngine) {
res.push(data.tableEngine);
}
@@ -1071,14 +1120,21 @@
}
$: isPinned = !!$pinnedTables.find(x => testEqual(data, x));
$: backupParsed = data.objectTypeField === 'tables' ? data.pureName.match(TABLE_BACKUP_REGEX) : null;
$: backupTitle =
backupParsed != null
? `${backupParsed[1]} (${backupParsed[2]}-${backupParsed[3]}-${backupParsed[4]} ${backupParsed[5]}:${backupParsed[6]}:${backupParsed[7]})`
: null;
</script>
<AppObjectCore
{...$$restProps}
module={$$props.module}
{data}
title={data.schemaName && !passProps?.hideSchemaName ? `${data.schemaName}.${data.pureName}` : data.pureName}
icon={databaseObjectIcons[data.objectTypeField]}
title={backupTitle ??
(data.schemaName && !passProps?.hideSchemaName ? `${data.schemaName}.${data.pureName}` : data.pureName)}
icon={backupParsed ? 'img table-backup' : databaseObjectIcons[data.objectTypeField]}
menu={createMenu}
showPinnedInsteadOfUnpin={passProps?.showPinnedInsteadOfUnpin}
onPin={passProps?.ingorePin ? null : isPinned ? null : () => pinnedTables.update(list => [...list, data])}
+12 -11
View File
@@ -1,3 +1,4 @@
import { __t } from '../translations';
export function matchDatabaseObjectAppObject(obj1, obj2) {
return (
obj1?.objectTypeField == obj2?.objectTypeField &&
@@ -11,12 +12,12 @@ export function matchDatabaseObjectAppObject(obj1, obj2) {
function getTableLikeActions(dataTab) {
return [
{
label: 'Open data',
label: __t('dbObject.openData', { defaultMessage: 'Open data' }),
tab: dataTab,
defaultActionId: 'openTable',
},
{
label: 'Open raw data',
label: __t('dbObject.openRawData', { defaultMessage: 'Open raw data' }),
tab: dataTab,
defaultActionId: 'openRawTable',
isRawMode: true,
@@ -33,13 +34,13 @@ function getTableLikeActions(dataTab) {
// defaultActionId: 'openForm',
// },
{
label: 'Open structure',
label: __t('dbObject.openStructure', { defaultMessage: 'Open structure' }),
tab: 'TableStructureTab',
icon: 'img table-structure',
defaultActionId: 'openStructure',
},
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -53,7 +54,7 @@ export const defaultDatabaseObjectAppObjectActions = {
matviews: getTableLikeActions('ViewDataTab'),
procedures: [
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -61,7 +62,7 @@ export const defaultDatabaseObjectAppObjectActions = {
],
functions: [
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -69,7 +70,7 @@ export const defaultDatabaseObjectAppObjectActions = {
],
triggers: [
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -77,12 +78,12 @@ export const defaultDatabaseObjectAppObjectActions = {
],
collections: [
{
label: 'Open data',
label: __t('dbObject.openData', { defaultMessage: 'Open data' }),
tab: 'CollectionDataTab',
defaultActionId: 'openTable',
},
{
label: 'Open JSON',
label: __t('dbObject.openJson', { defaultMessage: 'Open JSON' }),
tab: 'CollectionDataTab',
defaultActionId: 'openJson',
initialData: {
@@ -94,7 +95,7 @@ export const defaultDatabaseObjectAppObjectActions = {
],
schedulerEvents: [
{
label: 'Show SQL',
label: __t('dbObject.showSql', { defaultMessage: 'Show SQL' }),
tab: 'SqlObjectTab',
defaultActionId: 'showSql',
icon: 'img sql-file',
@@ -102,7 +103,7 @@ export const defaultDatabaseObjectAppObjectActions = {
],
queries: [
{
label: 'Show query',
label: __t('dbObject.showQuery', { defaultMessage: 'Show query' }),
tab: 'QueryDataTab',
defaultActionId: 'showAppQuery',
icon: 'img app-query',
@@ -5,6 +5,7 @@
import getElectron from '../utility/getElectron';
import InlineButtonLabel from '../buttons/InlineButtonLabel.svelte';
import resolveApi, { resolveApiHeaders } from '../utility/resolveApi';
import { _t } from '../translations';
import uuidv1 from 'uuid/v1';
@@ -49,11 +50,11 @@
</script>
{#if electron}
<InlineButton on:click={handleOpenElectronFile} title="Open file" data-testid={$$props['data-testid']}>
<InlineButton on:click={handleOpenElectronFile} title={_t('files.openFile', { defaultMessage: "Open file" })} data-testid={$$props['data-testid']}>
<FontIcon {icon} />
</InlineButton>
{:else}
<InlineButtonLabel on:click={() => {}} title="Upload file" data-testid={$$props['data-testid']} htmlFor={inputId}>
<InlineButtonLabel on:click={() => {}} title={_t('files.uploadFile', { defaultMessage: "Upload file" })} data-testid={$$props['data-testid']} htmlFor={inputId}>
<FontIcon {icon} />
</InlineButtonLabel>
{/if}
@@ -1,6 +1,7 @@
<script lang="ts">
import FontIcon from '../icons/FontIcon.svelte';
import { isProApp } from '../utility/proTools';
import { _t } from '../translations';
export let icon;
export let title;
@@ -21,7 +22,7 @@
data-testid={$$props['data-testid']}
title={disabled
? isProFeature && !isProApp()
? 'This feature is available only in DbGate Premium'
? _t('common.featurePremium', { defaultMessage: 'This feature is available only in DbGate Premium' })
: disabledMessage
: undefined}
>
@@ -1,6 +1,6 @@
<script context="module">
function getCommandTitle(command) {
let res = command.text;
let res = _tval(command.text);
if (command.keyText || command.keyTextFromGroup) {
res += ` (${formatKeyText(command.keyText || command.keyTextFromGroup)})`;
}
@@ -12,6 +12,8 @@
import { commandsCustomized } from '../stores';
import { formatKeyText } from '../utility/common';
import ToolStripButton from './ToolStripButton.svelte';
import _ from 'lodash';
import { _tval } from '../translations';
export let command;
export let component = ToolStripButton;
@@ -32,6 +34,6 @@
{iconAfter}
{...$$restProps}
>
{buttonLabel || cmd.toolbarName || cmd.name}
{(_tval(buttonLabel) || _tval(cmd?.toolbarName) || _tval(cmd?.name))}
</svelte:component>
{/if}
@@ -23,7 +23,8 @@
import hasPermission from '../utility/hasPermission';
import ToolStripCommandButton from './ToolStripCommandButton.svelte';
import ToolStripDropDownButton from './ToolStripDropDownButton.svelte';
import _ from 'lodash';
import { _tval } from '../translations';
export let quickExportHandlerRef = null;
export let command = 'sqlDataGrid.export';
export let label = 'Export';
@@ -39,7 +40,7 @@
{#if hasPermission('dbops/export')}
{#if quickExportHandlerRef}
<ToolStripDropDownButton menu={getExportMenu} {label} icon="icon export" />
<ToolStripDropDownButton menu={getExportMenu} label={_tval(label)} icon="icon export" />
{:else}
<ToolStripCommandButton {command} />
{/if}
+2 -1
View File
@@ -1,6 +1,7 @@
<script lang="ts">
import FormStyledButtonLikeLabel from '../buttons/FormStyledButtonLikeLabel.svelte';
import uploadFiles from '../utility/uploadFiles';
import { _t } from '../translations';
const handleChange = e => {
const files = [...e.target.files];
@@ -9,6 +10,6 @@
</script>
<div class="m-1">
<FormStyledButtonLikeLabel htmlFor="uploadFileButton">Upload file</FormStyledButtonLikeLabel>
<FormStyledButtonLikeLabel htmlFor="uploadFileButton">{_t('files.uploadFile', { defaultMessage: "Upload file" })}</FormStyledButtonLikeLabel>
<input type="file" id="uploadFileButton" hidden on:change={handleChange} />
</div>
@@ -10,6 +10,9 @@
if (value?.type == 'Buffer' && _.isArray(value?.data)) {
return 'data:image/png;base64, ' + btoa(String.fromCharCode.apply(null, value?.data));
}
if (value?.$binary?.base64) {
return 'data:image/png;base64, ' + value.$binary.base64;
}
return null;
} catch (err) {
console.log('Error showing picture', err);
+13 -12
View File
@@ -1,9 +1,9 @@
<script context="module">
registerCommand({
id: 'commandPalette.show',
category: 'Command palette',
name: 'Show',
toolbarName: 'Command palette',
category: __t('command.commandPalette', { defaultMessage: 'Command palette' }),
name: __t('command.commandPalette.show', { defaultMessage: 'Show' }),
toolbarName: __t('command.commandPalette', { defaultMessage: 'Command palette' }),
toolbarOrder: 0,
keyText: 'F1',
toolbar: true,
@@ -15,9 +15,9 @@
registerCommand({
id: 'database.search',
category: 'Database',
toolbarName: 'Database search',
name: 'Search',
category: __t('command.database', { defaultMessage: 'Database' }),
toolbarName: __t('command.database.databaseSearch', { defaultMessage: 'Database search' }),
name: __t('command.database.search', { defaultMessage: 'Search' }),
keyText: isElectronAvailable() ? 'CtrlOrCommand+P' : 'F3',
onClick: () => visibleCommandPalette.set('database'),
testEnabled: () => getVisibleCommandPalette() != 'database',
@@ -81,6 +81,7 @@
import { getLocalStorage } from '../utility/storageCache';
import registerCommand from './registerCommand';
import { formatKeyText, switchCurrentDatabase } from '../utility/common';
import { _tval, __t } from '../translations';
let domInput;
let filter = '';
@@ -113,11 +114,11 @@
($visibleCommandPalette == 'database'
? extractDbItems($databaseInfo, { conid, database }, $connectionList)
: parentCommand
? parentCommand.getSubCommands()
: sortedComands
? parentCommand.getSubCommands()
: sortedComands
).filter(x => !x.isGroupCommand),
{
extract: x => x.text,
extract: x => _tval(x.text),
pre: '<b>',
post: '</b>',
}
@@ -162,10 +163,10 @@
on:clickOutside={() => {
$visibleCommandPalette = null;
}}
data-testid='CommandPalette_main'
data-testid="CommandPalette_main"
>
<div
class="overlay"
<div
class="overlay"
on:click={() => {
$visibleCommandPalette = null;
}}
@@ -3,12 +3,13 @@ import { currentDatabase, getCurrentDatabase } from '../stores';
import getElectron from '../utility/getElectron';
import registerCommand from './registerCommand';
import { apiCall } from '../utility/api';
import { switchCurrentDatabase } from '../utility/common';
import { getDatabasStatusMenu, switchCurrentDatabase } from '../utility/common';
import { __t } from '../translations';
registerCommand({
id: 'database.changeState',
category: 'Database',
name: 'Change status',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.changeStatus', { defaultMessage: 'Change status' }),
getSubCommands: () => {
const current = getCurrentDatabase();
if (!current) return [];
@@ -17,33 +18,7 @@ registerCommand({
conid: connection._id,
database: name,
};
return [
{
text: 'Sync model (incremental)',
onClick: () => {
apiCall('database-connections/sync-model', dbid);
},
},
{
text: 'Sync model (full)',
onClick: () => {
apiCall('database-connections/sync-model', { ...dbid, isFullRefresh: true });
},
},
{
text: 'Reopen',
onClick: () => {
apiCall('database-connections/refresh', dbid);
},
},
{
text: 'Disconnect',
onClick: () => {
const electron = getElectron();
if (electron) apiCall('database-connections/disconnect', dbid);
switchCurrentDatabase(null);
},
},
];
return getDatabasStatusMenu(dbid);
},
});
@@ -3,6 +3,7 @@ import { recentDatabases, currentDatabase, getRecentDatabases } from '../stores'
import registerCommand from './registerCommand';
import { getConnectionLabel } from 'dbgate-tools';
import { switchCurrentDatabase } from '../utility/common';
import { __t } from '../translations';
currentDatabase.subscribe(value => {
if (!value) return;
@@ -24,9 +25,9 @@ function switchDatabaseCommand(db) {
registerCommand({
id: 'database.switch',
category: 'Database',
name: 'Change to recent',
menuName: 'Switch recent database',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.changeRecent', { defaultMessage: 'Change to recent' }),
menuName: __t('command.database.switchRecent', { defaultMessage: 'Switch recent database' }),
keyText: 'CtrlOrCommand+D',
getSubCommands: () => getRecentDatabases().map(switchDatabaseCommand),
});
+14 -7
View File
@@ -1,5 +1,7 @@
import { commands } from '../stores';
import { invalidateCommandDefinitions } from './invalidateCommands';
import _ from 'lodash';
import { _tval, DefferedTranslationResult, isDefferedTranslationResult } from '../translations';
export interface SubCommand {
text: string;
@@ -8,10 +10,10 @@ export interface SubCommand {
export interface GlobalCommand {
id: string;
category: string; // null for group commands
category: string | DefferedTranslationResult; // null for group commands
isGroupCommand?: boolean;
name: string;
text?: string /* category: name */;
name: string | DefferedTranslationResult;
text?: string | DefferedTranslationResult;
keyText?: string;
keyTextFromGroup?: string; // automatically filled from group
group?: string;
@@ -23,11 +25,11 @@ export interface GlobalCommand {
toolbar?: boolean;
enabled?: boolean;
showDisabled?: boolean;
toolbarName?: string;
menuName?: string;
toolbarName?: string | DefferedTranslationResult;
menuName?: string | DefferedTranslationResult;
toolbarOrder?: number;
disableHandleKeyText?: string;
isRelatedToTab?: boolean,
isRelatedToTab?: boolean;
systemCommand?: boolean;
}
@@ -41,7 +43,12 @@ export default function registerCommand(command: GlobalCommand) {
return {
...x,
[command.id]: {
text: `${command.category}: ${command.name}`,
text:
isDefferedTranslationResult(command.category) || isDefferedTranslationResult(command.name)
? {
_transCallback: () => `${_tval(command.category)}: ${_tval(command.name)}`,
}
: `${command.category}: ${command.name}`,
...command,
enabled: !testEnabled,
},
+234 -182
View File
@@ -11,6 +11,7 @@ import {
promoWidgetPreview,
visibleToolbar,
visibleWidgetSideBar,
selectedWidget,
} from '../stores';
import registerCommand from './registerCommand';
import { get } from 'svelte/store';
@@ -52,6 +53,7 @@ import { openWebLink } from '../utility/simpleTools';
import { _t } from '../translations';
import ExportImportConnectionsModal from '../modals/ExportImportConnectionsModal.svelte';
import { getBoolSettingsValue } from '../settings/settingsTools';
import { __t } from '../translations';
// function themeCommand(theme: ThemeDefinition) {
// return {
@@ -69,42 +71,42 @@ import { getBoolSettingsValue } from '../settings/settingsTools';
registerCommand({
id: 'theme.changeTheme',
category: 'Theme',
name: 'Change',
toolbarName: 'Change theme',
category: __t('command.theme', { defaultMessage: 'Theme' }),
name: __t('command.theme.change', { defaultMessage: 'Change' }),
toolbarName: __t('command.theme.changeToolbar', { defaultMessage: 'Change theme' }),
onClick: () => showModal(SettingsModal, { selectedTab: 'theme' }),
// getSubCommands: () => get(extensions).themes.map(themeCommand),
});
registerCommand({
id: 'toolbar.show',
category: 'Toolbar',
name: 'Show',
category: __t('command.toolbar', { defaultMessage: 'Toolbar' }),
name: __t('command.toolbar.show', { defaultMessage: 'Show' }),
onClick: () => visibleToolbar.set(true),
testEnabled: () => !getVisibleToolbar(),
});
registerCommand({
id: 'toolbar.hide',
category: 'Toolbar',
name: 'Hide',
category: __t('command.toolbar', { defaultMessage: 'Toolbar' }),
name: __t('command.toolbar.hide', { defaultMessage: 'Hide' }),
onClick: () => visibleToolbar.set(false),
testEnabled: () => getVisibleToolbar(),
});
registerCommand({
id: 'about.show',
category: 'About',
name: 'Show',
toolbarName: 'About',
category: __t('command.about', { defaultMessage: 'About' }),
name: __t('command.about.show', { defaultMessage: 'Show' }),
toolbarName: __t('command.about.toolbar', { defaultMessage: 'About' }),
onClick: () => showModal(AboutModal),
});
registerCommand({
id: 'toggle.sidebar',
category: 'Sidebar',
name: 'Show',
toolbarName: 'Toggle sidebar',
category: __t('command.sidebar', { defaultMessage: 'Sidebar' }),
name: __t('command.sidebar.show', { defaultMessage: 'Show' }),
toolbarName: __t('command.sidebar.toggleToolbar', { defaultMessage: 'Toggle sidebar' }),
keyText: 'CtrlOrCommand+B',
onClick: () => visibleWidgetSideBar.update(x => !x),
});
@@ -113,14 +115,14 @@ registerCommand({
id: 'new.connection',
toolbar: true,
icon: 'icon new-connection',
toolbarName: 'Add connection',
category: 'New',
toolbarName: __t('command.new.connection', { defaultMessage: 'Add connection' }),
category: __t('command.new', { defaultMessage: 'New' }),
toolbarOrder: 1,
name: 'Connection',
name: __t('command.new.connection', { defaultMessage: 'Connection' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase,
onClick: () => {
openNewTab({
title: 'New Connection',
title: _t('common.newConnection', { defaultMessage: 'New Connection' }),
icon: 'img connection',
tabComponent: 'ConnectionTab',
});
@@ -131,15 +133,15 @@ registerCommand({
id: 'new.connectionOnCloud',
toolbar: true,
icon: 'img cloud-connection',
toolbarName: 'Add connection',
category: 'New',
toolbarName: __t('command.new.connection', { defaultMessage: 'Add connection' }),
category: __t('command.new', { defaultMessage: 'New' }),
toolbarOrder: 1,
name: 'Connection on Cloud',
name: __t('command.new.connectionCloud', { defaultMessage: 'Connection on Cloud' }),
testEnabled: () =>
!getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase && !!getCloudSigninTokenHolder(),
onClick: () => {
openNewTab({
title: 'New Connection on Cloud',
title: _t('common.newConnectionCloud', { defaultMessage: 'New Connection on Cloud' }),
icon: 'img cloud-connection',
tabComponent: 'ConnectionTab',
props: {
@@ -153,10 +155,10 @@ registerCommand({
id: 'new.connection.folder',
toolbar: true,
icon: 'icon add-folder',
toolbarName: 'Add connection folder',
category: 'New',
toolbarName: __t('command.new.connectionFolderToolbar', { defaultMessage: 'Add connection folder' }),
category: __t('command.new', { defaultMessage: 'New' }),
toolbarOrder: 1,
name: 'Connection folder',
name: __t('command.new.connectionFolder', { defaultMessage: 'Connection folder' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal,
onClick: () => {
showModal(InputTextModal, {
@@ -176,22 +178,22 @@ registerCommand({
registerCommand({
id: 'new.query',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'icon file',
toolbar: true,
toolbarOrder: 2,
name: 'Query',
toolbarName: 'New query',
name: __t('command.new.query', { defaultMessage: 'Query' }),
toolbarName: __t('command.new.queryToolbar', { defaultMessage: 'New query' }),
keyText: 'CtrlOrCommand+T',
onClick: () => newQuery(),
});
registerCommand({
id: 'new.shell',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img shell',
name: 'JavaScript Shell',
menuName: 'New JavaScript shell',
name: __t('command.new.shell', { defaultMessage: 'JavaScript Shell' }),
menuName: __t('command.new.JSShell', { defaultMessage: 'New JavaScript shell' }),
onClick: () => {
openNewTab({
title: 'Shell #',
@@ -204,10 +206,10 @@ registerCommand({
if (isProApp()) {
registerCommand({
id: 'new.queryDesign',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img query-design',
name: 'Query design',
menuName: 'New query design',
name: __t('command.new.queryDesign', { defaultMessage: 'Query design' }),
menuName: __t('command.new.newQueryDesign', { defaultMessage: 'New query design' }),
onClick: () => newQueryDesign(),
testEnabled: () =>
getCurrentDatabase() &&
@@ -218,10 +220,10 @@ if (isProApp()) {
if (isProApp()) {
registerCommand({
id: 'new.modelTransform',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img transform',
name: 'Model transform',
menuName: 'New model transform',
name: __t('command.new.modelTransform', { defaultMessage: 'Model transform' }),
menuName: __t('command.new.newModelTransform', { defaultMessage: 'New model transform' }),
onClick: () => {
openNewTab(
{
@@ -262,10 +264,10 @@ if (isProApp()) {
if (isProApp()) {
registerCommand({
id: 'new.perspective',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img perspective',
name: 'Perspective',
menuName: 'New perspective',
name: __t('command.new.perspective', { defaultMessage: 'Perspective' }),
menuName: __t('command.new.newPerspective', { defaultMessage: 'New perspective' }),
onClick: () => newPerspective(),
});
}
@@ -273,10 +275,10 @@ if (isProApp()) {
if (isProApp()) {
registerCommand({
id: 'new.application',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img app',
name: 'Application',
menuName: 'New application',
name: __t('command.new.application', { defaultMessage: 'Application' }),
menuName: __t('command.new.newApplication', { defaultMessage: 'New application' }),
onClick: () => {
openNewTab({
title: 'Application #',
@@ -289,10 +291,10 @@ if (isProApp()) {
registerCommand({
id: 'new.diagram',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img diagram',
name: 'ER Diagram',
menuName: 'New ER diagram',
name: __t('command.new.diagram', { defaultMessage: 'ER Diagram' }),
menuName: __t('command.new.newDiagram', { defaultMessage: 'New ER diagram' }),
testEnabled: () =>
getCurrentDatabase() &&
findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql'),
@@ -301,9 +303,9 @@ registerCommand({
registerCommand({
id: 'new.archiveFolder',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img archive',
name: 'Archive folder',
name: __t('command.new.archiveFolder', { defaultMessage: 'Archive folder' }),
onClick: () => {
showModal(InputTextModal, {
value: '',
@@ -335,11 +337,11 @@ registerCommand({
registerCommand({
id: 'new.table',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'icon table',
name: 'Table',
name: __t('command.new.table', { defaultMessage: 'Table' }),
toolbar: true,
toolbarName: 'New table',
toolbarName: __t('command.new.tableToolbar', { defaultMessage: 'New table' }),
testEnabled: () => {
if (!hasPermission('dbops/model/edit')) return false;
const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions());
@@ -355,11 +357,11 @@ registerCommand({
registerCommand({
id: 'new.collection',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'icon table',
name: 'Collection',
name: __t('command.new.collection', { defaultMessage: 'Collection' }),
toolbar: true,
toolbarName: 'New collection/container',
toolbarName: __t('command.new.collectionToolbar', { defaultMessage: 'New collection/container' }),
testEnabled: () => {
const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions());
return !!get(currentDatabase) && driver?.databaseEngineTypes?.includes('document');
@@ -381,9 +383,9 @@ registerCommand({
registerCommand({
id: 'new.markdown',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img markdown',
name: 'Markdown page',
name: __t('command.new.markdown', { defaultMessage: 'Markdown page' }),
onClick: () => {
openNewTab({
title: 'Page #',
@@ -396,9 +398,9 @@ registerCommand({
if (isProApp()) {
registerCommand({
id: 'new.modelCompare',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'icon compare',
name: 'Compare DB',
name: __t('command.new.modelCompare', { defaultMessage: 'Compare DB' }),
toolbar: true,
onClick: () => {
openNewTab({
@@ -412,10 +414,10 @@ if (isProApp()) {
registerCommand({
id: 'new.jsonl',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img archive',
name: 'JSON Lines',
menuName: 'New JSON lines file',
name: __t('command.new.jsonl', { defaultMessage: 'JSON Lines' }),
menuName: __t('command.new.newJsonl', { defaultMessage: 'New JSON lines file' }),
onClick: () => {
openNewTab(
{
@@ -432,10 +434,10 @@ registerCommand({
registerCommand({
id: 'new.sqliteDatabase',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img sqlite-database',
name: 'SQLite database',
menuName: _t('command.new.sqliteDatabase', { defaultMessage: 'New SQLite database' }),
name: __t('command.new.sqliteDatabase', { defaultMessage: 'SQLite database' }),
menuName: __t('command.new.sqliteDatabase', { defaultMessage: 'New SQLite database' }),
onClick: () => {
showModal(InputTextModal, {
value: 'newdb',
@@ -452,10 +454,10 @@ registerCommand({
registerCommand({
id: 'new.duckdbDatabase',
category: 'New',
category: __t('command.new', { defaultMessage: 'New' }),
icon: 'img sqlite-database',
name: 'DuckDB database',
menuName: _t('command.new.duckdbDatabase', { defaultMessage: 'New DuckDB database' }),
name: __t('command.new.duckdbDatabase', { defaultMessage: 'DuckDB database' }),
menuName: __t('command.new.duckdbDatabase', { defaultMessage: 'New DuckDB database' }),
onClick: () => {
showModal(InputTextModal, {
value: 'newdb',
@@ -472,8 +474,8 @@ registerCommand({
registerCommand({
id: 'tabs.changelog',
category: 'Tabs',
name: 'Changelog',
category: __t('command.tabs', { defaultMessage: 'Tabs' }),
name: __t('command.tabs.changelog', { defaultMessage: 'Changelog' }),
onClick: () => {
openNewTab({
title: 'ChangeLog',
@@ -488,7 +490,7 @@ registerCommand({
id: 'group.save',
category: null,
isGroupCommand: true,
name: 'Save',
name: __t('command.save', { defaultMessage: 'Save' }),
keyText: 'CtrlOrCommand+S',
group: 'save',
});
@@ -497,7 +499,7 @@ registerCommand({
id: 'group.saveAs',
category: null,
isGroupCommand: true,
name: 'Save As',
name: __t('command.saveAs', { defaultMessage: 'Save As' }),
keyText: 'CtrlOrCommand+Shift+S',
group: 'saveAs',
});
@@ -506,7 +508,7 @@ registerCommand({
id: 'group.undo',
category: null,
isGroupCommand: true,
name: 'Undo',
name: __t('command.undo', { defaultMessage: 'Undo' }),
keyText: 'CtrlOrCommand+Z',
group: 'undo',
});
@@ -515,15 +517,15 @@ registerCommand({
id: 'group.redo',
category: null,
isGroupCommand: true,
name: 'Redo',
name: __t('command.redo', { defaultMessage: 'Redo' }),
keyText: 'CtrlOrCommand+Y',
group: 'redo',
});
registerCommand({
id: 'file.open',
category: 'File',
name: 'Open',
category: __t('command.file', { defaultMessage: 'File' }),
name: __t('command.file.open', { defaultMessage: 'Open' }),
keyText: 'CtrlOrCommand+O',
testEnabled: () => getElectron() != null,
onClick: openElectronFile,
@@ -531,36 +533,39 @@ registerCommand({
registerCommand({
id: 'file.openArchive',
category: 'File',
name: 'Open DB Model/Archive',
category: __t('command.file', { defaultMessage: 'File' }),
name: __t('command.file.openArchive', { defaultMessage: 'Open DB Model/Archive' }),
testEnabled: () => getElectron() != null,
onClick: openArchiveFolder,
});
registerCommand({
id: 'folder.showLogs',
category: 'Folder',
name: 'Open logs',
category: __t('command.folder', { defaultMessage: 'Folder' }),
name: __t('command.folder.openLogs', { defaultMessage: 'Open logs' }),
testEnabled: () => getElectron() != null,
onClick: () => electron.showItemInFolder(getCurrentConfig().logsFilePath),
});
registerCommand({
id: 'folder.showData',
category: 'Folder',
name: 'Open data folder',
category: __t('command.folder', { defaultMessage: 'Folder' }),
name: __t('command.folder.openData', { defaultMessage: 'Open data folder' }),
testEnabled: () => getElectron() != null,
onClick: () => electron.showItemInFolder(getCurrentConfig().connectionsFilePath),
});
registerCommand({
id: 'app.resetSettings',
category: 'File',
name: 'Reset layout data & settings',
category: __t('command.file', { defaultMessage: 'File' }),
name: __t('command.file.resetLayout', { defaultMessage: 'Reset layout data & settings' }),
testEnabled: () => true,
onClick: () => {
showModal(ConfirmModal, {
message: `Really reset layout data? All opened tabs, settings and layout data will be lost. Connections and saved files will be preserved. After this, restart DbGate for applying changes.`,
message: _t('command.file.resetLayoutConfirm', {
defaultMessage:
'Really reset layout data? All opened tabs, settings and layout data will be lost. Connections and saved files will be preserved. After this, restart DbGate for applying changes.',
}),
onConfirm: async () => {
await apiCall('config/delete-settings');
localStorage.clear();
@@ -577,8 +582,8 @@ registerCommand({
registerCommand({
id: 'app.exportConnections',
category: 'Settings',
name: 'Export connections',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.exportConnections', { defaultMessage: 'Export connections' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase,
onClick: () => {
showModal(ExportImportConnectionsModal, {
@@ -589,8 +594,8 @@ registerCommand({
registerCommand({
id: 'app.importConnections',
category: 'Settings',
name: 'Import connections',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.importConnections', { defaultMessage: 'Import connections' }),
testEnabled: () => !getCurrentConfig()?.runAsPortal && !getCurrentConfig()?.storageDatabase,
onClick: async () => {
const files = await electron.showOpenDialog({
@@ -615,8 +620,8 @@ registerCommand({
registerCommand({
id: 'file.import',
category: 'File',
name: 'Import data',
category: __t('command.file', { defaultMessage: 'File' }),
name: __t('command.file.import', { defaultMessage: 'Import data' }),
toolbar: true,
icon: 'icon import',
onClick: () =>
@@ -636,8 +641,8 @@ registerCommand({
registerCommand({
id: 'view.reset',
category: 'View',
name: 'Reset view',
category: __t('command.view', { defaultMessage: 'View' }),
name: __t('command.view.reset', { defaultMessage: 'Reset view' }),
onClick: () => {
const keys = [
'leftPanelWidth',
@@ -664,14 +669,16 @@ registerCommand({
'currentArchive',
];
for (const key of keys) removeLocalStorage(key);
showSnackbarSuccess('Restart DbGate (or reload on web) for applying changes');
showSnackbarSuccess(
_t('command.view.restart', { defaultMessage: 'Restart DbGate (or reload on web) for applying changes' })
);
},
});
registerCommand({
id: 'sql.generator',
category: 'SQL',
name: 'SQL Generator',
category: __t('command.sql', { defaultMessage: 'SQL' }),
name: __t('command.sql.generator', { defaultMessage: 'SQL Generator' }),
toolbar: true,
icon: 'icon sql-generator',
testEnabled: () =>
@@ -687,8 +694,8 @@ registerCommand({
registerCommand({
id: 'database.export',
category: 'Database',
name: 'Export database',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.export', { defaultMessage: 'Export database' }),
toolbar: true,
icon: 'icon export',
testEnabled: () => getCurrentDatabase() != null && hasPermission(`dbops/export`) && isProApp(),
@@ -705,8 +712,8 @@ registerCommand({
if (isProApp()) {
registerCommand({
id: 'database.compare',
category: 'Database',
name: 'Compare databases',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.compare', { defaultMessage: 'Compare databases' }),
toolbar: true,
icon: 'icon compare',
testEnabled: () =>
@@ -738,8 +745,8 @@ if (isProApp()) {
registerCommand({
id: 'database.chat',
category: 'Database',
name: 'Database chat',
category: __t('command.database', { defaultMessage: 'Database' }),
name: __t('command.database.chat', { defaultMessage: 'Database chat' }),
toolbar: true,
icon: 'icon ai',
testEnabled: () =>
@@ -762,12 +769,25 @@ if (isProApp()) {
if (hasPermission('settings/change')) {
registerCommand({
id: 'settings.commands',
category: 'Settings',
name: 'Keyboard shortcuts',
id: 'settings.settingsTab',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.settingsTab', { defaultMessage: 'Settings tab' }),
onClick: () => {
openNewTab({
title: 'Keyboard Shortcuts',
title: _t('command.settings.settingsTab', { defaultMessage: 'Settings tab' }),
icon: 'icon settings',
tabComponent: 'SettingsTab',
props: {},
});
},
});
registerCommand({
id: 'settings.commands',
category: __t('command.settings', { defaultMessage: 'Settings' }),
name: __t('command.settings.shortcuts', { defaultMessage: 'Keyboard shortcuts' }),
onClick: () => {
openNewTab({
title: _t('command.settings.shortcuts', { defaultMessage: 'Keyboard shortcuts' }),
icon: 'icon keyboard',
tabComponent: 'CommandListTab',
props: {},
@@ -776,20 +796,20 @@ if (hasPermission('settings/change')) {
testEnabled: () => hasPermission('settings/change'),
});
registerCommand({
id: 'settings.show',
category: 'Settings',
name: 'Change',
toolbarName: 'Settings',
onClick: () => showModal(SettingsModal),
testEnabled: () => hasPermission('settings/change'),
});
// registerCommand({
// id: 'settings.show',
// category: __t('command.settings', { defaultMessage: 'Settings' }),
// name: __t('command.settings.change', { defaultMessage: 'Change' }),
// toolbarName: __t('command.settings', { defaultMessage: 'Settings' }),
// onClick: () => showModal(SettingsModal),
// testEnabled: () => hasPermission('settings/change'),
// });
}
registerCommand({
id: 'cloud.logout',
category: 'Cloud',
name: 'Logout',
category: __t('command.cloud', { defaultMessage: 'Cloud' }),
name: __t('command.cloud.logout', { defaultMessage: 'Logout' }),
onClick: () => {
cloudSigninTokenHolder.set(null);
},
@@ -797,8 +817,10 @@ registerCommand({
registerCommand({
id: 'file.exit',
category: 'File',
name: isMac() ? 'Quit' : 'Exit',
category: __t('command.file', { defaultMessage: 'File' }),
name: isMac()
? __t('command.file.quit', { defaultMessage: 'Quit' })
: __t('command.file.exit', { defaultMessage: 'Exit' }),
// keyText: isMac() ? 'Command+Q' : null,
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('quit-app'),
@@ -806,16 +828,16 @@ registerCommand({
registerCommand({
id: 'app.logout',
category: 'App',
name: 'Logout',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.app.logout', { defaultMessage: 'Logout' }),
testEnabled: () => getCurrentConfig()?.isUserLoggedIn,
onClick: doLogout,
});
registerCommand({
id: 'app.loggedUserCommands',
category: 'App',
name: 'Logged user',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.app.loggedUser', { defaultMessage: 'Logged user' }),
getSubCommands: () => {
const config = getCurrentConfig();
if (!config) return [];
@@ -832,16 +854,16 @@ registerCommand({
registerCommand({
id: 'app.disconnect',
category: 'App',
name: 'Disconnect',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.app.disconnect', { defaultMessage: 'Disconnect' }),
testEnabled: () => getCurrentConfig()?.singleConnection != null && !getCurrentConfig()?.isUserLoggedIn,
onClick: () => disconnectServerConnection(getCurrentConfig()?.singleConnection?._id),
});
registerCommand({
id: 'file.checkForUpdates',
category: 'App',
name: 'Check for updates',
id: 'app.checkForUpdates',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.app.checkForUpdates', { defaultMessage: 'Check for updates' }),
// testEnabled: () => true,
testEnabled: () => getAppUpdaterActive(),
onClick: () => getElectron().send('check-for-updates'),
@@ -861,34 +883,35 @@ export function registerFileCommands({
undoRedo = false,
executeAdditionalCondition = null,
copyPaste = false,
defaultTeamFolder = false,
}) {
if (save) {
registerCommand({
id: idPrefix + '.save',
group: 'save',
category,
name: 'Save',
name: __t('command.save', { defaultMessage: 'Save' }),
// keyText: 'CtrlOrCommand+S',
icon: 'icon save',
toolbar: true,
isRelatedToTab: true,
testEnabled: () => getCurrentEditor() != null,
onClick: () => saveTabFile(getCurrentEditor(), 'save', folder, format, fileExtension),
onClick: () => saveTabFile(getCurrentEditor(), 'save', folder, format, fileExtension, defaultTeamFolder),
});
registerCommand({
id: idPrefix + '.saveAs',
group: 'saveAs',
category,
name: 'Save As',
name: __t('command.saveAs', { defaultMessage: 'Save As' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => saveTabFile(getCurrentEditor(), 'save-as', folder, format, fileExtension),
onClick: () => saveTabFile(getCurrentEditor(), 'save-as', folder, format, fileExtension, defaultTeamFolder),
});
registerCommand({
id: idPrefix + '.saveToDisk',
category,
name: 'Save to disk',
name: __t('command.saveToDisk', { defaultMessage: 'Save to disk' }),
testEnabled: () => getCurrentEditor() != null && getElectron() != null,
onClick: () => saveTabFile(getCurrentEditor(), 'save-to-disk', folder, format, fileExtension),
onClick: () => saveTabFile(getCurrentEditor(), 'save-to-disk', folder, format, fileExtension, defaultTeamFolder),
});
}
@@ -896,7 +919,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.execute',
category,
name: 'Execute',
name: __t('command.execute', { defaultMessage: 'Execute' }),
icon: 'icon run',
toolbar: true,
isRelatedToTab: true,
@@ -910,7 +933,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.kill',
category,
name: 'Kill',
name: __t('command.kill', { defaultMessage: 'Kill' }),
icon: 'icon close',
toolbar: true,
isRelatedToTab: true,
@@ -923,7 +946,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.toggleComment',
category,
name: 'Toggle comment',
name: __t('command.toggleComment', { defaultMessage: 'Toggle comment' }),
keyText: 'CtrlOrCommand+/',
disableHandleKeyText: 'CtrlOrCommand+/',
testEnabled: () => getCurrentEditor() != null,
@@ -935,7 +958,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.copy',
category,
name: 'Copy',
name: __t('command.copy', { defaultMessage: 'Copy' }),
disableHandleKeyText: 'CtrlOrCommand+C',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().copy(),
@@ -943,7 +966,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.paste',
category,
name: 'Paste',
name: __t('command.paste', { defaultMessage: 'Paste' }),
disableHandleKeyText: 'CtrlOrCommand+V',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().paste(),
@@ -954,7 +977,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.find',
category,
name: 'Find',
name: __t('command.find', { defaultMessage: 'Find' }),
keyText: 'CtrlOrCommand+F',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().find(),
@@ -963,7 +986,7 @@ export function registerFileCommands({
id: idPrefix + '.replace',
category,
keyText: isMac() ? 'Alt+Command+F' : 'CtrlOrCommand+H',
name: 'Replace',
name: __t('command.replace', { defaultMessage: 'Replace' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().replace(),
});
@@ -972,7 +995,7 @@ export function registerFileCommands({
registerCommand({
id: idPrefix + '.undo',
category,
name: 'Undo',
name: __t('command.undo', { defaultMessage: 'Undo' }),
group: 'undo',
icon: 'icon undo',
testEnabled: () => getCurrentEditor()?.canUndo(),
@@ -982,7 +1005,7 @@ export function registerFileCommands({
id: idPrefix + '.redo',
category,
group: 'redo',
name: 'Redo',
name: __t('command.redo', { defaultMessage: 'Redo' }),
icon: 'icon redo',
testEnabled: () => getCurrentEditor()?.canRedo(),
onClick: () => getCurrentEditor().redo(),
@@ -992,24 +1015,24 @@ export function registerFileCommands({
registerCommand({
id: 'app.minimize',
category: 'Application',
name: 'Minimize',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.minimize', { defaultMessage: 'Minimize' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'minimize'),
});
registerCommand({
id: 'app.maximize',
category: 'Application',
name: 'Maximize',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.maximize', { defaultMessage: 'Maximize' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'maximize'),
});
registerCommand({
id: 'app.toggleFullScreen',
category: 'Application',
name: 'Toggle full screen',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.toggleFullScreen', { defaultMessage: 'Toggle full screen' }),
keyText: 'F11',
testEnabled: () => getElectron() != null,
onClick: async () => {
@@ -1023,45 +1046,45 @@ registerCommand({
registerCommand({
id: 'app.toggleDevTools',
category: 'Application',
name: 'Toggle Dev Tools',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.toggleDevTools', { defaultMessage: 'Toggle Dev Tools' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'devtools'),
});
registerCommand({
id: 'app.reload',
category: 'Application',
name: 'Reload',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.reload', { defaultMessage: 'Reload' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'reload'),
});
registerCommand({
id: 'app.openDocs',
category: 'Application',
name: 'Documentation',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.documentation', { defaultMessage: 'Documentation' }),
onClick: () => openWebLink('https://docs.dbgate.io/'),
});
registerCommand({
id: 'app.openWeb',
category: 'Application',
name: 'DbGate web',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.web', { defaultMessage: 'DbGate web' }),
onClick: () => openWebLink('https://www.dbgate.io/'),
});
registerCommand({
id: 'app.openIssue',
category: 'Application',
name: 'Report problem or feature request',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.openIssue', { defaultMessage: 'Report problem or feature request' }),
onClick: () => openWebLink('https://github.com/dbgate/dbgate/issues/new'),
});
registerCommand({
id: 'app.openSponsoring',
category: 'Application',
name: 'Become sponsor',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.becomeSponsor', { defaultMessage: 'Become sponsor' }),
testEnabled: () => !isProApp(),
onClick: () => openWebLink('https://opencollective.com/dbgate'),
});
@@ -1075,8 +1098,8 @@ registerCommand({
registerCommand({
id: 'app.zoomIn',
category: 'Application',
name: 'Zoom in',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.zoomIn', { defaultMessage: 'Zoom in' }),
keyText: 'CtrlOrCommand+=',
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'zoomin'),
@@ -1084,8 +1107,8 @@ registerCommand({
registerCommand({
id: 'app.zoomOut',
category: 'Application',
name: 'Zoom out',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.zoomOut', { defaultMessage: 'Zoom out' }),
keyText: 'CtrlOrCommand+-',
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'zoomout'),
@@ -1093,16 +1116,16 @@ registerCommand({
registerCommand({
id: 'app.zoomReset',
category: 'Application',
name: 'Reset zoom',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.zoomReset', { defaultMessage: 'Reset zoom' }),
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'zoomreset'),
});
registerCommand({
id: 'edit.undo',
category: 'Edit',
name: 'Undo',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.undo', { defaultMessage: 'Undo' }),
keyText: 'CtrlOrCommand+Z',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1111,8 +1134,8 @@ registerCommand({
registerCommand({
id: 'edit.redo',
category: 'Edit',
name: 'Redo',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.redo', { defaultMessage: 'Redo' }),
systemCommand: true,
testEnabled: () => getElectron() != null,
onClick: () => getElectron().send('window-action', 'redo'),
@@ -1120,8 +1143,8 @@ registerCommand({
registerCommand({
id: 'edit.cut',
category: 'Edit',
name: 'Cut',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.cut', { defaultMessage: 'Cut' }),
keyText: 'CtrlOrCommand+X',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1130,8 +1153,8 @@ registerCommand({
registerCommand({
id: 'edit.copy',
category: 'Edit',
name: 'Copy',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.copy', { defaultMessage: 'Copy' }),
keyText: 'CtrlOrCommand+C',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1140,8 +1163,8 @@ registerCommand({
registerCommand({
id: 'edit.paste',
category: 'Edit',
name: 'Paste',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.paste', { defaultMessage: 'Paste' }),
keyText: 'CtrlOrCommand+V',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1150,8 +1173,8 @@ registerCommand({
registerCommand({
id: 'edit.selectAll',
category: 'Edit',
name: 'Select All',
category: __t('command.edit', { defaultMessage: 'Edit' }),
name: __t('command.edit.selectAll', { defaultMessage: 'Select All' }),
keyText: 'CtrlOrCommand+A',
systemCommand: true,
testEnabled: () => getElectron() != null,
@@ -1160,8 +1183,8 @@ registerCommand({
registerCommand({
id: 'app.unsetCurrentDatabase',
category: 'Application',
name: 'Unset current database',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.unsetCurrentDatabase', { defaultMessage: 'Unset current database' }),
testEnabled: () => getCurrentDatabase() != null,
onClick: () => currentDatabase.set(null),
});
@@ -1170,8 +1193,8 @@ let loadedCampaignList = [];
registerCommand({
id: 'internal.loadCampaigns',
category: 'Internal',
name: 'Load campaign list',
category: __t('command.internal', { defaultMessage: 'Internal' }),
name: __t('command.internal.loadCampaigns', { defaultMessage: 'Load campaign list' }),
testEnabled: () => getBoolSettingsValue('internal.showCampaigns', false),
onClick: async () => {
const resp = await apiCall('cloud/promo-widget-list', {});
@@ -1181,8 +1204,8 @@ registerCommand({
registerCommand({
id: 'internal.showCampaigns',
category: 'Internal',
name: 'Show campaigns',
category: __t('command.internal', { defaultMessage: 'Internal' }),
name: __t('command.internal.showCampaigns', { defaultMessage: 'Show campaigns' }),
testEnabled: () => getBoolSettingsValue('internal.showCampaigns', false) && loadedCampaignList?.length > 0,
getSubCommands: () => {
return loadedCampaignList.map(campaign => ({
@@ -1201,6 +1224,35 @@ registerCommand({
},
});
if ( hasPermission('application-log'))
{
registerCommand({
id: 'app.showLogs',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.showLogs', { defaultMessage: 'View application logs' }),
onClick: () => {
openNewTab({
title: 'Application log',
icon: 'img applog',
tabComponent: 'AppLogTab',
});
},
});
}
if (hasPermission('widgets/plugins'))
{
registerCommand({
id: 'app.managePlugins',
category: __t('command.application', { defaultMessage: 'Application' }),
name: __t('command.application.managePlugins', { defaultMessage: 'Manage plugins' }),
onClick: () => {
selectedWidget.set('plugins');
visibleWidgetSideBar.set(true);
},
});
}
const electron = getElectron();
if (electron) {
electron.addEventListener('run-command', (e, commandId) => runCommand(commandId));
@@ -3,16 +3,16 @@
registerCommand({
id: 'collectionDataGrid.openQuery',
category: 'Data grid',
name: 'Open query',
category: __t('command.dataGrid', { defaultMessage: 'Data grid' }),
name: __t('command.dataGrid.openQuery', { defaultMessage: 'Open query' }),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().openQuery(),
});
registerCommand({
id: 'collectionDataGrid.export',
category: 'Data grid',
name: 'Export',
category: __t('command.dataGrid', { defaultMessage: 'Data grid' }),
name: __t('command.dataGrid.export', { defaultMessage: 'Export' }),
keyText: 'CtrlOrCommand+E',
icon: 'icon export',
testEnabled: () => getCurrentEditor() != null,
@@ -140,6 +140,7 @@
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
import { mongoFilterBehaviour, standardFilterBehaviours } from 'dbgate-tools';
import { openImportExportTab } from '../utility/importExportTools';
import { __t } from '../translations';
export let conid;
export let display;
+13 -12
View File
@@ -3,8 +3,8 @@
registerCommand({
id: 'dataGrid.switchToForm',
category: 'Data grid',
name: 'Switch to form',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.switchToform', { defaultMessage: 'Switch to form' }),
icon: 'icon form',
keyText: 'F4',
testEnabled: () => getCurrentEditor()?.switchViewEnabled('form'),
@@ -13,8 +13,8 @@
registerCommand({
id: 'dataGrid.switchToJson',
category: 'Data grid',
name: 'Switch to JSON',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.switchToJSON', { defaultMessage: 'Switch to JSON' }),
icon: 'icon json',
keyText: 'F4',
testEnabled: () => getCurrentEditor()?.switchViewEnabled('json'),
@@ -23,8 +23,8 @@
registerCommand({
id: 'dataGrid.switchToTable',
category: 'Data grid',
name: 'Switch to table',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.witchToTable', { defaultMessage: 'Switch to table'}),
icon: 'icon table',
keyText: 'F4',
testEnabled: () => getCurrentEditor()?.switchViewEnabled('table'),
@@ -33,8 +33,8 @@
registerCommand({
id: 'dataGrid.toggleLeftPanel',
category: 'Data grid',
name: 'Toggle left panel',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.toggleLeftPanel', { defaultMessage: 'Toggle left panel' }),
keyText: 'CtrlOrCommand+L',
testEnabled: () => getCurrentEditor()?.canShowLeftPanel(),
onClick: () => getCurrentEditor().toggleLeftPanel(),
@@ -68,6 +68,7 @@
import registerCommand from '../commands/registerCommand';
import { registerMenu } from '../utility/contextMenu';
import { getLocalStorage, setLocalStorage } from '../utility/storageCache';
import { __t, _t } from '../translations';
import { isProApp } from '../utility/proTools';
export let config;
@@ -174,7 +175,7 @@
<div class="left" slot="1">
<WidgetColumnBar>
<WidgetColumnBarItem
title="Columns"
title={_t('dataGrid.columns', { defaultMessage: 'Columns' })}
name="columns"
height="45%"
skip={isFormView}
@@ -184,7 +185,7 @@
</WidgetColumnBarItem>
<WidgetColumnBarItem
title="Filters"
title={_t('dataGrid.filters', { defaultMessage: 'Filters' })}
name="filters"
height={showReferences && display?.hasReferences && !isFormView ? '15%' : '30%'}
skip={!display?.filterable}
@@ -202,7 +203,7 @@
</WidgetColumnBarItem>
<WidgetColumnBarItem
title="References"
title={_t('dataGrid.references', { defaultMessage: 'References' })}
name="references"
height="30%"
collapsed={isDetailView}
@@ -213,7 +214,7 @@
</WidgetColumnBarItem>
<WidgetColumnBarItem
title="Macros"
title={_t('dataGrid.macros', { defaultMessage: 'Macros' })}
name="macros"
skip={!(showMacros && isProApp())}
collapsed={!expandMacros}
+82 -74
View File
@@ -3,8 +3,8 @@
registerCommand({
id: 'dataGrid.refresh',
category: 'Data grid',
name: _t('common.refresh', { defaultMessage: 'Refresh' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('common.refresh', { defaultMessage: 'Refresh' }),
keyText: 'F5 | CtrlOrCommand+R',
toolbar: true,
isRelatedToTab: true,
@@ -15,8 +15,8 @@
registerCommand({
id: 'dataGrid.deepRefresh',
category: 'Data grid',
name: 'Refresh with structure',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('common.datagrid.deepRefresh', { defaultMessage: 'Refresh with structure' }),
keyText: 'Ctrl+F5',
toolbar: true,
isRelatedToTab: true,
@@ -27,8 +27,8 @@
registerCommand({
id: 'dataGrid.revertRowChanges',
category: 'Data grid',
name: _t('command.datagrid.revertRowChanges', { defaultMessage: 'Revert row changes' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.revertRowChanges', { defaultMessage: 'Revert row changes' }),
keyText: 'CtrlOrCommand+U',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataGrid().revertRowChanges(),
@@ -36,9 +36,9 @@
registerCommand({
id: 'dataGrid.revertAllChanges',
category: 'Data grid',
name: _t('command.datagrid.revertAllChanges', { defaultMessage: 'Revert all changes' }),
toolbarName: _t('command.datagrid.revertAllChanges.toolbar', { defaultMessage: 'Revert all' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.revertAllChanges', { defaultMessage: 'Revert all changes' }),
toolbarName: __t('command.datagrid.revertAllChanges.toolbar', { defaultMessage: 'Revert all' }),
icon: 'icon undo',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataGrid().revertAllChanges(),
@@ -46,9 +46,9 @@
registerCommand({
id: 'dataGrid.deleteSelectedRows',
category: 'Data grid',
name: _t('command.datagrid.deleteSelectedRows', { defaultMessage: 'Delete selected rows' }),
toolbarName: _t('command.datagrid.deleteSelectedRows.toolbar', { defaultMessage: 'Delete row(s)' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.deleteSelectedRows', { defaultMessage: 'Delete selected rows' }),
toolbarName: __t('command.datagrid.deleteSelectedRows.toolbar', { defaultMessage: 'Delete row(s)' }),
keyText: isMac() ? 'Command+Backspace' : 'CtrlOrCommand+Delete',
icon: 'icon minus',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
@@ -57,9 +57,9 @@
registerCommand({
id: 'dataGrid.insertNewRow',
category: 'Data grid',
name: _t('command.datagrid.insertNewRow', { defaultMessage: 'Insert new row' }),
toolbarName: _t('command.datagrid.insertNewRow.toolbar', { defaultMessage: 'New row' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.insertNewRow', { defaultMessage: 'Insert new row' }),
toolbarName: __t('command.datagrid.insertNewRow.toolbar', { defaultMessage: 'New row' }),
icon: 'icon add',
keyText: isMac() ? 'Command+I' : 'Insert',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
@@ -68,9 +68,9 @@
registerCommand({
id: 'dataGrid.addNewColumn',
category: 'Data grid',
name: _t('command.datagrid.addNewColumn', { defaultMessage: 'Add new column' }),
toolbarName: _t('command.datagrid.addNewColumn.toolbar', { defaultMessage: 'New column' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.addNewColumn', { defaultMessage: 'Add new column' }),
toolbarName: __t('command.datagrid.addNewColumn.toolbar', { defaultMessage: 'New column' }),
icon: 'icon add-column',
testEnabled: () => getCurrentDataGrid()?.addNewColumnEnabled(),
onClick: () => getCurrentDataGrid().addNewColumn(),
@@ -78,9 +78,9 @@
registerCommand({
id: 'dataGrid.cloneRows',
category: 'Data grid',
name: _t('command.datagrid.cloneRows', { defaultMessage: 'Clone rows' }),
toolbarName: _t('command.datagrid.cloneRows.toolbar', { defaultMessage: 'Clone row(s)' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.cloneRows', { defaultMessage: 'Clone rows' }),
toolbarName: __t('command.datagrid.cloneRows.toolbar', { defaultMessage: 'Clone row(s)' }),
keyText: 'CtrlOrCommand+Shift+C',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
onClick: () => getCurrentDataGrid().cloneRows(),
@@ -88,8 +88,8 @@
registerCommand({
id: 'dataGrid.setNull',
category: 'Data grid',
name: _t('command.datagrid.setNull', { defaultMessage: 'Set NULL' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.setNull', { defaultMessage: 'Set NULL' }),
keyText: 'CtrlOrCommand+0',
testEnabled: () =>
getCurrentDataGrid()?.getGrider()?.editable && !getCurrentDataGrid()?.getEditorTypes()?.supportFieldRemoval,
@@ -98,8 +98,8 @@
registerCommand({
id: 'dataGrid.removeField',
category: 'Data grid',
name: _t('command.datagrid.removeField', { defaultMessage: 'Remove field' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.removeField', { defaultMessage: 'Remove field' }),
keyText: 'CtrlOrCommand+0',
testEnabled: () =>
getCurrentDataGrid()?.getGrider()?.editable && getCurrentDataGrid()?.getEditorTypes()?.supportFieldRemoval,
@@ -108,8 +108,8 @@
registerCommand({
id: 'dataGrid.undo',
category: 'Data grid',
name: _t('command.datagrid.undo', { defaultMessage: 'Undo' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.undo', { defaultMessage: 'Undo' }),
group: 'undo',
icon: 'icon undo',
toolbar: true,
@@ -120,8 +120,8 @@
registerCommand({
id: 'dataGrid.redo',
category: 'Data grid',
name: _t('command.datagrid.redo', { defaultMessage: 'Redo' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.redo', { defaultMessage: 'Redo' }),
group: 'redo',
icon: 'icon redo',
toolbar: true,
@@ -132,16 +132,16 @@
registerCommand({
id: 'dataGrid.reconnect',
category: 'Data grid',
name: _t('command.datagrid.reconnect', { defaultMessage: 'Reconnect' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.reconnect', { defaultMessage: 'Reconnect' }),
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().reconnect(),
});
registerCommand({
id: 'dataGrid.copyToClipboard',
category: 'Data grid',
name: _t('command.datagrid.copyToClipboard', { defaultMessage: 'Copy to clipboard' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.copyToClipboard', { defaultMessage: 'Copy to clipboard' }),
keyText: 'CtrlOrCommand+C',
disableHandleKeyText: 'CtrlOrCommand+C',
testEnabled: () => getCurrentDataGrid() != null,
@@ -150,57 +150,57 @@
registerCommand({
id: 'dataGrid.editJsonDocument',
category: 'Data grid',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
keyText: 'CtrlOrCommand+J',
name: _t('command.datagrid.editJsonDocument', { defaultMessage: 'Edit row as JSON document' }),
name: __t('command.datagrid.editJsonDocument', { defaultMessage: 'Edit row as JSON document' }),
testEnabled: () => getCurrentDataGrid()?.editJsonEnabled(),
onClick: () => getCurrentDataGrid().editJsonDocument(),
});
registerCommand({
id: 'dataGrid.openSelectionInMap',
category: 'Data grid',
name: _t('command.datagrid.openSelectionInMap', { defaultMessage: 'Open selection in map' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.openSelectionInMap', { defaultMessage: 'Open selection in map' }),
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().openSelectionInMap(),
});
registerCommand({
id: 'dataGrid.viewJsonDocument',
category: 'Data grid',
name: _t('command.datagrid.viewJsonDocument', { defaultMessage: 'View row as JSON document' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.viewJsonDocument', { defaultMessage: 'View row as JSON document' }),
testEnabled: () => getCurrentDataGrid()?.viewJsonDocumentEnabled(),
onClick: () => getCurrentDataGrid().viewJsonDocument(),
});
registerCommand({
id: 'dataGrid.viewJsonValue',
category: 'Data grid',
name: _t('command.datagrid.viewJsonValue', { defaultMessage: 'View cell as JSON document' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.viewJsonValue', { defaultMessage: 'View cell as JSON document' }),
testEnabled: () => getCurrentDataGrid()?.viewJsonValueEnabled(),
onClick: () => getCurrentDataGrid().viewJsonValue(),
});
registerCommand({
id: 'dataGrid.openJsonArrayInSheet',
category: 'Data grid',
name: _t('command.datagrid.openJsonArrayInSheet', { defaultMessage: 'Open array as table' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.openJsonArrayInSheet', { defaultMessage: 'Open array as table' }),
testEnabled: () => getCurrentDataGrid()?.openJsonArrayInSheetEnabled(),
onClick: () => getCurrentDataGrid().openJsonArrayInSheet(),
});
registerCommand({
id: 'dataGrid.saveCellToFile',
category: 'Data grid',
name: _t('command.datagrid.saveCellToFile', { defaultMessage: 'Save cell to file' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.saveCellToFile', { defaultMessage: 'Save cell to file' }),
testEnabled: () => getCurrentDataGrid()?.saveCellToFileEnabled(),
onClick: () => getCurrentDataGrid().saveCellToFile(),
});
registerCommand({
id: 'dataGrid.loadCellFromFile',
category: 'Data grid',
name: _t('command.datagrid.loadCellFromFile', { defaultMessage: 'Load cell from file' }),
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.loadCellFromFile', { defaultMessage: 'Load cell from file' }),
testEnabled: () => getCurrentDataGrid()?.loadCellFromFileEnabled(),
onClick: () => getCurrentDataGrid().loadCellFromFile(),
});
@@ -216,62 +216,62 @@
//
registerCommand({
id: 'dataGrid.filterSelected',
category: 'Data grid',
name: 'Filter selected value',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.filterSelected', { defaultMessage : 'Filter selected value'}),
keyText: 'CtrlOrCommand+Shift+F',
testEnabled: () => getCurrentDataGrid()?.getDisplay().filterable,
onClick: () => getCurrentDataGrid().filterSelectedValue(),
});
registerCommand({
id: 'dataGrid.findColumn',
category: 'Data grid',
name: 'Find column',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.findColumn', { defaultMessage: 'Find column'}),
keyText: 'CtrlOrCommand+F',
testEnabled: () => getCurrentDataGrid() != null,
getSubCommands: () => getCurrentDataGrid().buildFindMenu(),
});
registerCommand({
id: 'dataGrid.hideColumn',
category: 'Data grid',
name: 'Hide column',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datgrid.hideColumn', { defaultMessage: 'Hide column' }),
keyText: isMac() ? 'Alt+Command+F' : 'CtrlOrCommand+H',
testEnabled: () => getCurrentDataGrid()?.canShowLeftPanel(),
onClick: () => getCurrentDataGrid().hideColumn(),
});
registerCommand({
id: 'dataGrid.clearFilter',
category: 'Data grid',
name: 'Clear filter',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.clearFilter', { defaultMessage : 'Clear filter'}),
keyText: 'CtrlOrCommand+Shift+E',
testEnabled: () => getCurrentDataGrid()?.clearFilterEnabled(),
onClick: () => getCurrentDataGrid().clearFilter(),
});
registerCommand({
id: 'dataGrid.generateSqlFromData',
category: 'Data grid',
name: 'Generate SQL',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.generateSql', { defaultMessage: 'Generate SQL'}),
keyText: 'CtrlOrCommand+G',
testEnabled: () => getCurrentDataGrid()?.generateSqlFromDataEnabled(),
onClick: () => getCurrentDataGrid().generateSqlFromData(),
});
registerCommand({
id: 'dataGrid.openFreeTable',
category: 'Data grid',
name: 'Edit selection as table',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.editSelection', { defaultMessage: 'Edit selection as table'}),
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().openFreeTable(),
});
registerCommand({
id: 'dataGrid.newJson',
category: 'Data grid',
name: 'Add JSON document',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.addJsonDocument', { defaultMessage: 'Add JSON document'}),
testEnabled: () => getCurrentDataGrid()?.addJsonDocumentEnabled(),
onClick: () => getCurrentDataGrid().addJsonDocument(),
});
registerCommand({
id: 'dataGrid.editCellValue',
category: 'Data grid',
name: 'Edit cell value',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.editCell', { defaultMessage: 'Edit cell value' }),
testEnabled: () => getCurrentDataGrid()?.editCellValueEnabled(),
onClick: () => getCurrentDataGrid().editCellValue(),
});
@@ -279,8 +279,8 @@
if (isProApp()) {
registerCommand({
id: 'dataGrid.sendToDataDeploy',
category: 'Data grid',
name: 'Send to data deployer',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.datagrid.sendToDataDeployer', { defaultMessage: 'Send to data deployer' }),
testEnabled: () => getCurrentDataGrid()?.sendToDataDeployEnabled(),
onClick: () => getCurrentDataGrid().sendToDataDeploy(),
});
@@ -361,6 +361,7 @@
detectSqlFilterBehaviour,
stringifyCellValue,
shouldOpenMultilineDialog,
base64ToHex,
} from 'dbgate-tools';
import { getContext, onDestroy } from 'svelte';
import _, { map } from 'lodash';
@@ -421,7 +422,7 @@
import { openJsonLinesData } from '../utility/openJsonLinesData';
import contextMenuActivator from '../utility/contextMenuActivator';
import InputTextModal from '../modals/InputTextModal.svelte';
import { _t } from '../translations';
import { __t, _t, _tval } from '../translations';
import { isProApp } from '../utility/proTools';
import SaveArchiveModal from '../modals/SaveArchiveModal.svelte';
import hasPermission from '../utility/hasPermission';
@@ -758,7 +759,7 @@
export function saveCellToFileEnabled() {
const value = getSelectedExportableCell();
return _.isString(value) || (value?.type == 'Buffer' && _.isArray(value?.data));
return _.isString(value) || (value?.type == 'Buffer' && _.isArray(value?.data)) || (value?.$binary?.base64);
}
export async function saveCellToFile() {
@@ -771,6 +772,8 @@
fs.promises.writeFile(file, value);
} else if (value?.type == 'Buffer' && _.isArray(value?.data)) {
fs.promises.writeFile(file, window['Buffer'].from(value.data));
} else if (value?.$binary?.base64) {
fs.promises.writeFile(file, window['Buffer'].from(value.$binary.base64, 'base64'));
}
}
}
@@ -796,8 +799,9 @@
isText
? data
: {
type: 'Buffer',
data: [...data],
$binary: {
base64: data.toString('base64'),
},
}
);
}
@@ -1413,7 +1417,11 @@
function handleGridWheel(event) {
if (event.shiftKey) {
scrollHorizontal(event.deltaY, event.deltaX);
if (isMac()) {
scrollHorizontal(event.deltaX, event.deltaY);
} else {
scrollHorizontal(event.deltaY, event.deltaX);
}
} else {
scrollHorizontal(event.deltaX, event.deltaY);
scrollVertical(event.deltaX, event.deltaY);
@@ -1788,15 +1796,15 @@
{ command: 'dataGrid.refresh' },
{ placeTag: 'copy' },
{
text: 'Copy advanced',
text: _t('datagrid.copyAdvanced', { defaultMessage: 'Copy advanced'}),
submenu: [
_.keys(copyRowsFormatDefs).map(format => ({
text: copyRowsFormatDefs[format].label,
text: _tval(copyRowsFormatDefs[format].label),
onClick: () => copyToClipboardCore(format),
})),
{ divider: true },
_.keys(copyRowsFormatDefs).map(format => ({
text: `Set format: ${copyRowsFormatDefs[format].name}`,
text: _t('datagrid.setFormat', { defaultMessage: 'Set format: ' }) + (_tval(copyRowsFormatDefs[format].name)),
onClick: () => ($copyRowsFormat = format),
})),
@@ -1866,7 +1874,7 @@
return [
menu,
{
text: copyRowsFormatDefs[$copyRowsFormat].label,
text: _tval(copyRowsFormatDefs[$copyRowsFormat].label),
onClick: () => copyToClipboardCore($copyRowsFormat),
keyText: 'CtrlOrCommand+C',
tag: 'copy',
@@ -3,8 +3,8 @@
registerCommand({
id: 'jslTableGrid.export',
category: 'Data grid',
name: 'Export',
category: __t('command.dataGrid', { defaultMessage: 'Data grid' }),
name: __t('command.dataGrid.export', { defaultMessage: 'Export' }),
icon: 'icon export',
keyText: 'CtrlOrCommand+E',
testEnabled: () => getCurrentEditor() != null,
@@ -56,6 +56,7 @@
import LoadingDataGridCore from './LoadingDataGridCore.svelte';
import { openImportExportTab } from '../utility/importExportTools';
import { __t } from '../translations';
export let jslid;
export let display;
@@ -11,6 +11,8 @@
import FontIcon from '../icons/FontIcon.svelte';
import TokenizedFilteredText from '../widgets/TokenizedFilteredText.svelte';
import { _t } from '../translations';
export let managerSize;
export let display: GridDisplay;
export let onReferenceClick = ref => {};
@@ -24,12 +26,12 @@
</script>
<SearchBoxWrapper>
<SearchInput placeholder="Search references" bind:value={filter} />
<SearchInput placeholder={_t('dataGrid.searchReferences', { defaultMessage: 'Search references' })} bind:value={filter} />
<CloseSearchButton bind:filter />
</SearchBoxWrapper>
<ManagerInnerContainer width={managerSize}>
{#if foreignKeys.length > 0}
<div class="bold nowrap ml-1">References tables ({foreignKeys.length})</div>
<div class="bold nowrap ml-1">{_t('dataGrid.referencesTables', { defaultMessage: 'References tables' })} ({foreignKeys.length})</div>
{#each foreignKeys.filter(fk => filterName(filter, fk.refTableName)) as fk}
<div
class="link"
@@ -53,7 +55,7 @@
{/if}
{#if dependencies.length > 0}
<div class="bold nowrap ml-1">Dependent tables ({dependencies.length})</div>
<div class="bold nowrap ml-1">{_t('dataGrid.dependentTables', { defaultMessage: 'Dependent tables' })} ({dependencies.length})</div>
{#each dependencies.filter(fk => filterName(filter, fk.pureName)) as fk}
<div
class="link"
@@ -1,18 +1,19 @@
<script context="module" lang="ts">
import { __t } from '../translations'
const getCurrentEditor = () => getActiveComponent('SqlDataGridCore');
registerCommand({
id: 'sqlDataGrid.openQuery',
category: 'Data grid',
name: 'Open query',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('command.openQuery', { defaultMessage : 'Open query' }),
testEnabled: () => getCurrentEditor() != null && hasPermission('dbops/query'),
onClick: () => getCurrentEditor().openQuery(),
});
registerCommand({
id: 'sqlDataGrid.export',
category: 'Data grid',
name: 'Export',
category: __t('command.datagrid', { defaultMessage: 'Data grid' }),
name: __t('common.export', { defaultMessage : 'Export' }),
icon: 'icon export',
keyText: 'CtrlOrCommand+E',
testEnabled: () => getCurrentEditor() != null && hasPermission('dbops/export'),
+9 -8
View File
@@ -3,9 +3,9 @@
registerCommand({
id: 'designer.arrange',
category: 'Designer',
category: __t('command.designer', { defaultMessage: 'Designer' }),
icon: 'icon arrange',
name: 'Arrange',
name: __t('command.designer.arrange', { defaultMessage: 'Arrange' }),
toolbar: true,
isRelatedToTab: true,
testEnabled: () => getCurrentEditor()?.canArrange(),
@@ -15,9 +15,9 @@
registerCommand({
id: 'diagram.export',
category: 'Designer',
toolbarName: 'Export diagram',
name: 'Export diagram',
category: __t('command.designer', { defaultMessage: 'Designer' }),
toolbarName: __t('command.designer.exportDiagram', { defaultMessage: 'Export diagram' }),
name: __t('command.designer.exportDiagram', { defaultMessage: 'Export diagram' }),
icon: 'icon report',
toolbar: true,
isRelatedToTab: true,
@@ -27,9 +27,9 @@
registerCommand({
id: 'diagram.deleteSelectedTables',
category: 'Designer',
toolbarName: 'Remove',
name: 'Remove selected tables',
category: __t('command.designer', { defaultMessage: 'Designer' }),
toolbarName: __t('command.designer.remove', { defaultMessage: 'Remove' }),
name: __t('command.designer.removeSelectedTables', { defaultMessage: 'Remove selected tables' }),
icon: 'icon delete',
toolbar: true,
isRelatedToTab: true,
@@ -67,6 +67,7 @@
import { isProApp } from '../utility/proTools';
import dragScroll from '../utility/dragScroll';
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import { __t } from '../translations';
export let value;
export let onChange;
@@ -17,6 +17,7 @@
import moveDrag from '../utility/moveDrag';
import ColumnLine from './ColumnLine.svelte';
import DomTableRef from './DomTableRef';
import { _t } from '../translations';
export let conid;
export let database;
@@ -185,8 +186,8 @@
const handleSetTableAlias = () => {
showModal(InputTextModal, {
value: alias || '',
label: 'New alias',
header: 'Set table alias',
label: _t('designerTable.newAlias', { defaultMessage: 'New alias' }),
header: _t('designerTable.setTableAlias', { defaultMessage: 'Set table alias' }),
onConfirm: newAlias => {
onChangeTable({
...table,
@@ -210,13 +211,13 @@
return settings?.tableMenu({ designer, designerId, onRemoveTable });
}
return [
{ text: 'Remove', onClick: () => onRemoveTable({ designerId }) },
{ text: _t('common.remove', { defaultMessage: 'Remove' }), onClick: () => onRemoveTable({ designerId }) },
{ divider: true },
settings?.allowTableAlias &&
!isMultipleTableSelection && [
{ text: 'Set table alias', onClick: handleSetTableAlias },
{ text: _t('designerTable.setTableAlias', { defaultMessage: 'Set table alias' }), onClick: handleSetTableAlias },
alias && {
text: 'Remove table alias',
text: _t('designerTable.removeTableAlias', { defaultMessage: 'Remove table alias' }),
onClick: () =>
onChangeTable({
...table,
@@ -225,11 +226,11 @@
},
],
settings?.allowAddAllReferences &&
!isMultipleTableSelection && { text: 'Add references', onClick: () => onAddAllReferences(table) },
settings?.allowChangeColor && { text: 'Change color', onClick: () => onChangeTableColor(table) },
!isMultipleTableSelection && { text: _t('designerTable.addReferences', { defaultMessage: 'Add references' }), onClick: () => onAddAllReferences(table) },
settings?.allowChangeColor && { text: _t('designerTable.changeColor', { defaultMessage: 'Change color' }), onClick: () => onChangeTableColor(table) },
settings?.allowDefineVirtualReferences &&
!isMultipleTableSelection && {
text: 'Define virtual foreign key',
text: _t('designerTable.defineVirtualForeignKey', { defaultMessage: 'Define virtual foreign key' }),
onClick: () => handleDefineVirtualForeignKey(table),
},
settings?.appendTableSystemMenu &&
@@ -5,6 +5,7 @@
import ObjectListControl from '../elements/ObjectListControl.svelte';
import Link from './Link.svelte';
import { _t } from '../translations';
export let collection;
export let title;
@@ -24,18 +25,18 @@
columns={[
{
fieldName: 'baseColumns',
header: 'Base columns',
header: _t('foreignKey.baseColumns', { defaultMessage: 'Base columns' }),
slot: 0,
sortable: true,
},
{
fieldName: 'refTableName',
header: 'Referenced table',
header: _t('foreignKey.refTableName', { defaultMessage: 'Referenced table' }),
sortable: true,
},
{
fieldName: 'refColumns',
header: 'Referenced columns',
header: _t('foreignKey.refColumns', { defaultMessage: 'Referenced columns' }),
slot: 1,
sortable: true,
},
@@ -60,5 +61,5 @@
<svelte:fragment slot="name" let:row><ConstraintLabel {...row} /></svelte:fragment>
<svelte:fragment slot="0" let:row>{row?.columns.map(x => x.columnName).join(', ')}</svelte:fragment>
<svelte:fragment slot="1" let:row>{row?.columns.map(x => x.refColumnName).join(', ')}</svelte:fragment>
<svelte:fragment slot="2" let:row><Link onClick={() => onRemove(row)}>Remove</Link></svelte:fragment>
<svelte:fragment slot="2" let:row><Link onClick={() => onRemove(row)}>{_t('common.remove', { defaultMessage: 'Remove' })}</Link></svelte:fragment>
</ObjectListControl>
@@ -4,6 +4,7 @@
import Link from './Link.svelte';
import TableControl from './TableControl.svelte';
import { writable } from 'svelte/store';
import { _t } from '../translations';
export let title;
export let collection;
@@ -39,7 +40,7 @@
</span>
<span class="title mr-1">{title}</span>
{#if onAddNew}
<Link onClick={onAddNew}><FontIcon icon="icon add" /> Add new</Link>
<Link onClick={onAddNew}><FontIcon icon="icon add" />{_t('common.addNew', { defaultMessage: 'Add new' })}</Link>
{/if}
{#if multipleItemsActions && activeMultipleSelection && activeMultipleSelection?.length > 0}
{#each multipleItemsActions as item}
@@ -65,7 +66,7 @@
columns={_.compact([
!hideDisplayName && {
fieldName: displayNameFieldName || 'displayName',
header: 'Name',
header: _t('common.name', { defaultMessage: 'Name' }),
slot: -1,
sortable: true,
filterable: !!displayNameFieldName,
@@ -0,0 +1,165 @@
<script lang="ts">
import _ from 'lodash';
import HorizontalSplitter from './HorizontalSplitter.svelte';
interface MenuItemDef {
label: string;
slot?: number;
component?: any;
props?: any;
testid?: string;
identifier?: string;
}
export let items: MenuItemDef[];
export let value: string | number = 0;
export let containerMaxWidth = undefined;
export let containerMaxHeight = undefined;
export let flex1 = true;
export let flexColContainer = false;
export let maxHeight100 = false;
export let scrollableContentContainer = false;
export let contentTestId = undefined;
export let onUserChange = null;
export function setValue(index) {
value = index;
}
export function getValue() {
return value;
}
</script>
<div class="main" class:maxHeight100 class:flex1>
<HorizontalSplitter initialValue="20%">
<svelte:fragment slot="1">
<div class="menu">
{#each _.compact(items) as item, index}
<div
class="menu-item"
class:selected={value == (item.identifier ?? index)}
on:click={() => {
value = item.identifier ?? index;
onUserChange?.(item.identifier ?? index);
}}
data-testid={item.testid}
>
<span class="ml-2 noselect">
{item.label}
</span>
</div>
{/each}
</div>
</svelte:fragment>
<svelte:fragment slot="2">
<div
class="content-container"
class:scrollableContentContainer
style:max-height={containerMaxHeight}
data-testid={contentTestId}
>
{#each _.compact(items) as item, index}
<div
class="container"
class:flexColContainer
class:maxHeight100
class:itemVisible={(item.identifier ?? index) == value}
style:max-width={containerMaxWidth}
>
<svelte:component
this={item.component}
{...item.props}
itemVisible={(item.identifier ?? index) == value}
menuControlHiddenItem={(item.identifier ?? index) != value}
/>
</div>
{/each}
</div>
</svelte:fragment>
</HorizontalSplitter>
</div>
<style>
.main {
display: flex;
flex: 1;
}
.main.flex1 {
flex: 1;
max-height: 100%;
}
.main.maxHeight100 {
max-height: 100%;
}
.menu {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
background-color: var(--theme-bg-2);
overflow-x: auto;
}
.menu::-webkit-scrollbar {
width: 7px;
}
.menu-item {
white-space: nowrap;
padding: 12px 20px;
display: flex;
align-items: center;
cursor: pointer;
border-bottom: 1px solid var(--theme-border);
transition: background-color 0.2s ease;
}
.menu-item:hover {
background-color: var(--theme-bg-hover);
}
.menu-item.selected {
background-color: var(--theme-bg-1);
font-weight: 600;
border-left: 3px solid var(--theme-font-link);
}
.content-container {
flex: 1;
position: relative;
overflow: hidden;
height: 100%;
}
.scrollableContentContainer {
overflow-y: auto;
}
.container.maxHeight100 {
max-height: 100%;
}
.container.flexColContainer {
display: flex;
flex-direction: column;
}
.container {
position: absolute;
display: flex;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow-y: auto;
padding: 20px;
}
.container:not(.itemVisible) {
visibility: hidden;
}
</style>
@@ -5,6 +5,8 @@
import { onMount, afterUpdate } from 'svelte';
export let code = '';
export let inline = false;
export let onClick = null;
let domCode;
@@ -29,7 +31,11 @@
The `sql` class hints the language; highlight.js will
read it even though we register the grammar explicitly.
-->
<pre bind:this={domCode} class="sql">{code}</pre>
{#if inline}
<span bind:this={domCode} class="sql" class:clickable={!!onClick} on:click={onClick}>{code}</span>
{:else}
<pre bind:this={domCode} class="sql" class:clickable={!!onClick} on:click={onClick}>{code}</pre>
{/if}
{/key}
<style>
@@ -38,4 +44,8 @@
padding: 0;
padding: 0.5em;
}
.clickable {
cursor: pointer;
}
</style>
@@ -27,6 +27,7 @@
import { evaluateCondition } from 'dbgate-sqltree';
import { compileCompoudEvalCondition } from 'dbgate-filterparser';
import { chevronExpandIcon } from '../icons/expandIcons';
import { _tval } from '../translations';
export let columns: (TableControlColumn | false)[];
export let rows = null;
@@ -368,7 +369,7 @@
{/if}
{/key}
{:else}
{row[col.fieldName] || ''}
{ _tval(row[col.fieldName]) || '' }
{/if}
</td>
{/each}
@@ -7,6 +7,7 @@
import { getFormContext } from './FormProviderCore.svelte';
import FormSelectField from './FormSelectField.svelte';
import { _t } from '../translations';
export let folderName;
export let name;
@@ -28,10 +29,10 @@
<div>
<FormStyledButton
type="button"
value="All files"
value={_t('common.allFiles', { defaultMessage: "All files" })}
on:click={() => setFieldValue(name, _.uniq([...($values[name] || []), ...($files && $files.map(x => x.name))]))}
/>
<FormStyledButton type="button" value="Remove all" on:click={() => setFieldValue(name, [])} />
<FormStyledButton type="button" value={_t('common.removeAll', { defaultMessage: "Remove all" })} on:click={() => setFieldValue(name, [])} />
</div>
</div>
@@ -5,6 +5,7 @@
import { getFormContext } from './FormProviderCore.svelte';
import TextField from './TextField.svelte';
import { _t } from '../translations';
export let name;
export let disabled = false;
@@ -29,7 +30,7 @@
setFieldValue(name, e.target['value']);
}
}}
placeholder={isCrypted ? '(Password is encrypted)' : undefined}
placeholder={isCrypted ? _t('common.passwordEncrypted', { defaultMessage: 'Password is encrypted' }) : undefined}
type={isCrypted || showPassword ? 'text' : 'password'}
/>
{#if !isCrypted}
@@ -1,6 +1,7 @@
<script lang="ts">
import { getFormContext } from './FormProviderCore.svelte';
import TextField from './TextField.svelte';
import { _tval } from '../translations';
export let name;
export let defaultValue;
@@ -11,7 +12,7 @@
<TextField
{...$$restProps}
value={$values?.[name] ?? defaultValue}
value={$values?.[name] ? _tval($values[name]) : defaultValue}
on:input={e => setFieldValue(name, e.target['value'])}
on:input={e => {
if (saveOnInput) {
@@ -3,8 +3,8 @@
registerCommand({
id: 'collectionJsonView.expandAll',
category: 'Collection data',
name: 'Expand all',
category: __t('command.collectionData', { defaultMessage: 'Collection data' }),
name: __t('command.collectionData.expandAll', { defaultMessage: 'Expand all' }),
isRelatedToTab: true,
icon: 'icon expand-all',
onClick: () => getCurrentEditor().handleExpandAll(),
@@ -12,8 +12,8 @@
});
registerCommand({
id: 'collectionJsonView.collapseAll',
category: 'Collection data',
name: 'Collapse all',
category: __t('command.collectionData', { defaultMessage: 'Collection data' }),
name: __t('command.collectionData.collapseAll', { defaultMessage: 'Collapse all' }),
isRelatedToTab: true,
icon: 'icon collapse-all',
onClick: () => getCurrentEditor().handleCollapseAll(),
@@ -37,6 +37,7 @@
import CollectionJsonRow from './CollectionJsonRow.svelte';
import { getIntSettingsValue } from '../settings/settingsTools';
import invalidateCommands from '../commands/invalidateCommands';
import { __t } from '../translations';
export let conid;
export let database;
+35 -39
View File
@@ -14,8 +14,8 @@
registerCommand({
id: 'dataForm.refresh',
category: 'Data form',
name: _t('common.refresh', { defaultMessage: 'Refresh' }),
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('common.refresh', { defaultMessage: 'Refresh' }),
keyText: 'F5 | CtrlOrCommand+R',
toolbar: true,
isRelatedToTab: true,
@@ -26,8 +26,8 @@
registerCommand({
id: 'dataForm.copyToClipboard',
category: 'Data form',
name: 'Copy to clipboard',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.copyToClipboard', { defaultMessage: 'Copy to clipboard' }),
keyText: 'CtrlOrCommand+C',
disableHandleKeyText: 'CtrlOrCommand+C',
testEnabled: () => getCurrentDataForm() != null,
@@ -36,8 +36,8 @@
registerCommand({
id: 'dataForm.revertRowChanges',
category: 'Data form',
name: 'Revert row changes',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.revertRowChanges', { defaultMessage: 'Revert row changes' }),
keyText: 'CtrlOrCommand+U',
testEnabled: () => getCurrentDataForm()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataForm().getGrider().revertRowChanges(0),
@@ -45,8 +45,8 @@
registerCommand({
id: 'dataForm.setNull',
category: 'Data form',
name: 'Set NULL',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.setNull', { defaultMessage: 'Set NULL' }),
keyText: 'CtrlOrCommand+0',
testEnabled: () => getCurrentDataForm() != null && !getCurrentDataForm()?.getEditorTypes()?.supportFieldRemoval,
onClick: () => getCurrentDataForm().setFixedValue(null),
@@ -54,8 +54,8 @@
registerCommand({
id: 'dataForm.removeField',
category: 'Data form',
name: 'Remove field',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.removeField', { defaultMessage: 'Remove field' }),
keyText: 'CtrlOrCommand+0',
testEnabled: () => getCurrentDataForm() != null && getCurrentDataForm()?.getEditorTypes()?.supportFieldRemoval,
onClick: () => getCurrentDataForm().setFixedValue(undefined),
@@ -63,8 +63,8 @@
registerCommand({
id: 'dataForm.undo',
category: 'Data form',
name: 'Undo',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.undo', { defaultMessage: 'Undo' }),
group: 'undo',
icon: 'icon undo',
toolbar: true,
@@ -75,8 +75,8 @@
registerCommand({
id: 'dataForm.redo',
category: 'Data form',
name: 'Redo',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.redo', { defaultMessage: 'Redo' }),
group: 'redo',
icon: 'icon redo',
toolbar: true,
@@ -87,16 +87,16 @@
registerCommand({
id: 'dataForm.reconnect',
category: 'Data grid',
name: 'Reconnect',
category: __t('command.dataGrid', { defaultMessage: 'Data grid' }),
name: __t('command.dataGrid.reconnect', { defaultMessage: 'Reconnect' }),
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().reconnect(),
});
registerCommand({
id: 'dataForm.filterSelected',
category: 'Data form',
name: 'Filter this value',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.filterSelected', { defaultMessage: 'Filter this value' }),
keyText: 'CtrlOrCommand+Shift+F',
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().filterSelectedValue(),
@@ -104,16 +104,16 @@
registerCommand({
id: 'dataForm.addToFilter',
category: 'Data form',
name: 'Add to filter',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.addToFilter', { defaultMessage: 'Add to filter' }),
testEnabled: () => getCurrentDataForm() != null,
onClick: () => getCurrentDataForm().addToFilter(),
});
registerCommand({
id: 'dataForm.goToFirst',
category: 'Data form',
name: 'First',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.goToFirst', { defaultMessage: 'First' }),
keyText: 'CtrlOrCommand+Home',
toolbar: true,
isRelatedToTab: true,
@@ -124,8 +124,8 @@
registerCommand({
id: 'dataForm.goToPrevious',
category: 'Data form',
name: 'Previous',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.goToPrevious', { defaultMessage: 'Previous' }),
keyText: 'CtrlOrCommand+ArrowUp',
toolbar: true,
isRelatedToTab: true,
@@ -136,8 +136,8 @@
registerCommand({
id: 'dataForm.goToNext',
category: 'Data form',
name: 'Next',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.goToNext', { defaultMessage: 'Next' }),
keyText: 'CtrlOrCommand+ArrowDown',
toolbar: true,
isRelatedToTab: true,
@@ -148,8 +148,8 @@
registerCommand({
id: 'dataForm.goToLast',
category: 'Data form',
name: 'Last',
category: __t('command.dataForm', { defaultMessage: 'Data form' }),
name: __t('command.dataForm.goToLast', { defaultMessage: 'Last' }),
keyText: 'CtrlOrCommand+End',
toolbar: true,
isRelatedToTab: true,
@@ -197,7 +197,7 @@
import resizeObserver from '../utility/resizeObserver';
import openReferenceForm from './openReferenceForm';
import { useSettings } from '../utility/metadataLoaders';
import { _t } from '../translations';
import { _t, __t } from '../translations';
export let conid;
export let database;
@@ -243,20 +243,16 @@
function getRowCountInfo(allRowCount) {
if (rowCountNotAvailable) {
return `Row: ${((display.config.formViewRecordNumber || 0) + 1).toLocaleString()} / ???`;
return _t('dataForm.rowCount', { defaultMessage: 'Row: {rowCount} / ???', values: { rowCount: ((display.config.formViewRecordNumber || 0) + 1).toLocaleString() } });
}
if (rowData == null) {
if (allRowCount != null) {
return `Out of bounds: ${(
(display.config.formViewRecordNumber || 0) + 1
).toLocaleString()} / ${allRowCount.toLocaleString()}`;
return _t('dataForm.outOfBounds', { defaultMessage: 'Out of bounds: {current} / {total}', values: { current: ((display.config.formViewRecordNumber || 0) + 1).toLocaleString(), total: allRowCount.toLocaleString() } });
}
return 'No data';
return _t('dataForm.noData', { defaultMessage: 'No data' });
}
if (allRowCount == null || display == null) return 'Loading row count...';
return `Row: ${(
(display.config.formViewRecordNumber || 0) + 1
).toLocaleString()} / ${allRowCount.toLocaleString()}`;
if (allRowCount == null || display == null) return _t('dataForm.loadingRowCount', { defaultMessage: 'Loading row count...' });
return _t('dataForm.rowCount', { defaultMessage: 'Row: {current} / {total}', values: { current: ((display.config.formViewRecordNumber || 0) + 1).toLocaleString(), total: allRowCount.toLocaleString() } });
}
export function getGrider() {
@@ -720,7 +716,7 @@
</div>
{#if isLoading}
<LoadingInfo wrapper message="Loading data" />
<LoadingInfo wrapper message={_t('common.loadingData', { defaultMessage: 'Loading data' })} />
{/if}
<style>
@@ -9,6 +9,7 @@
import FormViewFilterColumn from './FormViewFilterColumn.svelte';
import { stringFilterBehaviour } from 'dbgate-tools';
import CheckboxField from '../forms/CheckboxField.svelte';
import { _t } from '../translations';
// import PrimaryKeyFilterEditor from './PrimaryKeyFilterEditor.svelte';
export let managerSize;
@@ -36,7 +37,7 @@
{#if isFormView}
<div class="m-1">
<div>Column name filter</div>
<div>{_t('datagrid.columnNameFilter', { defaultMessage: 'Column name filter' })}</div>
<div class="flex">
<input
type="text"
@@ -63,7 +64,7 @@
{#if hasMultiColumnFilter}
<div class="m-1">
<div class="space-between">
<span>Multi column filter</span>
<span>{_t('dataGrid.multiColumnFilter', { defaultMessage: 'Multi column filter' })}</span>
{#if multiColumnFilter}
<div class="flex items-center gap-2">
<CheckboxField
+1
View File
@@ -353,6 +353,7 @@
'img data-deploy': 'mdi mdi-database-settings color-icon-green',
'img arrow-start-here': 'mdi mdi-arrow-down-bold-circle color-icon-green',
'img team-file': 'mdi mdi-account-file color-icon-red',
'img table-backup': 'mdi mdi-cube color-icon-yellow',
};
</script>
+3 -2
View File
@@ -23,6 +23,7 @@
import ElectronFilesInput from './ElectronFilesInput.svelte';
import { addFilesToSourceList } from './ImportExportConfigurator.svelte';
import UploadButton from '../buttons/UploadButton.svelte';
import { _t } from '../translations';
export let setPreviewSource = undefined;
@@ -55,10 +56,10 @@
{:else}
<UploadButton />
{/if}
<FormStyledButton value="Add web URL" on:click={handleAddUrl} />
<FormStyledButton value={_t('importExport.addWebUrl', { defaultMessage: "Add web URL" })} on:click={handleAddUrl} />
</div>
<div class="wrapper">Drag &amp; drop imported files here</div>
<div class="wrapper">{_t('importExport.dragDropImportedFilesHere', { defaultMessage: "Drag & drop imported files here" })}</div>
</div>
<style>
@@ -6,6 +6,7 @@
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
import { _t } from '../translations';
export let conidName;
export let databaseName;
@@ -41,7 +42,7 @@
{#if $dbinfo && $dbinfo[field]?.length > 0}
<FormStyledButton
type="button"
value={`All ${field}`}
value={_t('common.allFields', { defaultMessage: 'All {field}', values: { field } })}
data-testid={`FormTablesSelect_buttonAll_${field}`}
on:click={() =>
setFieldValue(
@@ -52,7 +53,7 @@
{/if}
{/each}
<FormStyledButton type="button" value="Remove all" on:click={() => setFieldValue(name, [])} />
<FormStyledButton type="button" value={_t('common.removeAll', { defaultMessage: "Remove all" })} on:click={() => setFieldValue(name, [])} />
</div>
</div>
@@ -77,6 +77,7 @@
import createRef from '../utility/createRef';
import DropDownButton from '../buttons/DropDownButton.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import { _t } from '../translations';
// export let uploadedFile = undefined;
// export let openedFile = undefined;
@@ -211,7 +212,7 @@
</div>
<div class="m-2">
<div class="title"><FontIcon icon="icon tables" /> Map source tables/files</div>
<div class="title"><FontIcon icon="icon tables" /> {_t('importExport.mapSourceTablesFiles', { defaultMessage: "Map source tables/files" })}</div>
{#key targetEditKey}
{#key progressHolder}
@@ -220,34 +221,34 @@
columns={[
{
fieldName: 'source',
header: 'Source',
header: _t('importExport.source', { defaultMessage: "Source" }),
component: SourceName,
getProps: row => ({ name: row }),
},
{
fieldName: 'action',
header: 'Action',
header: _t('importExport.action', { defaultMessage: "Action" }),
component: SourceAction,
getProps: row => ({ name: row, targetDbinfo }),
},
{
fieldName: 'target',
header: 'Target',
header: _t('importExport.target', { defaultMessage: "Target" }),
slot: 1,
},
supportsPreview && {
fieldName: 'preview',
header: 'Preview',
header: _t('importExport.preview', { defaultMessage: "Preview" }),
slot: 0,
},
!!progressHolder && {
fieldName: 'status',
header: 'Status',
header: _t('importExport.status', { defaultMessage: "Status" }),
slot: 3,
},
{
fieldName: 'columns',
header: 'Columns',
header: _t('importExport.columns', { defaultMessage: "Columns" }),
slot: 2,
},
]}
@@ -73,19 +73,19 @@
<div class="column">
{#if direction == 'source'}
<div class="title">
<FontIcon icon="icon import" /> Source configuration
<FontIcon icon="icon import" /> {_t('importExport.sourceConfiguration', { defaultMessage: 'Source configuration' })}
</div>
{/if}
{#if direction == 'target'}
<div class="title">
<FontIcon icon="icon export" /> Target configuration
<FontIcon icon="icon export" /> {_t('importExport.targetConfiguration', { defaultMessage: 'Target configuration' })}
</div>
{/if}
<div class="buttons">
{#if $currentDatabase}
<FormStyledButton
value="Current DB"
value={_t('importExport.currentDatabase', { defaultMessage: "Current DB" })}
on:click={() => {
values.update(x => ({
...x,
@@ -97,7 +97,7 @@
/>
{/if}
<FormStyledButton
value="Current archive"
value={_t('importExport.currentArchive', { defaultMessage: "Current archive" })}
data-testid={direction == 'source'
? 'SourceTargetConfig_buttonCurrentArchive_source'
: 'SourceTargetConfig_buttonCurrentArchive_target'}
@@ -111,7 +111,7 @@
/>
{#if direction == 'target'}
<FormStyledButton
value="New archive"
value={_t('importExport.newArchive', { defaultMessage: "New archive" })}
on:click={() => {
showModal(InputTextModal, {
header: 'Archive',
@@ -133,7 +133,7 @@
<FormSelectField
options={types.filter(x => x.directions.includes(direction))}
name={storageTypeField}
label="Storage type"
label={_t('importExport.storageType', { defaultMessage: "Storage type" })}
/>
{#if format && isProApp()}
@@ -172,9 +172,9 @@
{/if}
{#if storageType == 'database' || storageType == 'query'}
<FormConnectionSelect name={connectionIdField} label="Server" {direction} />
<FormConnectionSelect name={connectionIdField} label={_t('common.server', { defaultMessage: 'Server' })} {direction} />
{#if !$connectionInfo?.singleDatabase}
<FormDatabaseSelect conidName={connectionIdField} name={databaseNameField} label="Database" />
<FormDatabaseSelect conidName={connectionIdField} name={databaseNameField} label={_t('common.database', { defaultMessage: 'Database' })} />
{/if}
{/if}
{#if storageType == 'database'}
@@ -210,7 +210,7 @@
{#if storageType == 'archive'}
<FormArchiveFolderSelect
label="Archive folder"
label={_t('importExport.archiveFolder', { defaultMessage: "Archive folder" })}
name={archiveFolderField}
additionalFolders={_.compact([$values[archiveFolderField]])}
allowCreateNew={direction == 'target'}

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