Compare commits

...

863 Commits

Author SHA1 Message Date
Jan Prochazka 8489c171f3 AD_ALLOWED_LOGINS support 2022-11-27 18:32:01 +01:00
Jan Prochazka 592865b16e configurable token lifetime 2022-11-27 11:06:33 +01:00
Jan Prochazka 012d3ec2e1 logout button from not logged page 2022-11-27 10:56:50 +01:00
Jan Prochazka d84adcca5d more robust oauth 2022-11-27 10:43:25 +01:00
Jan Prochazka b1ae7d53b9 forms login 2022-11-26 11:21:37 +01:00
Jan Prochazka 9a5287725b login WIP 2022-11-25 16:59:41 +01:00
Jan Prochazka 5ccd724166 support for acticve directory #261 2022-11-25 16:38:17 +01:00
Jan Prochazka 5e4c286427 ignore auth .env 2022-11-25 16:15:41 +01:00
Jan Prochazka 70413b954b login page 2022-11-25 13:36:18 +01:00
Jan Prochazka 07b2a3e923 oauth disabling API 2022-11-17 20:09:27 +01:00
Jan Prochazka 94a91d5fed better oauth handle 2022-11-17 19:55:01 +01:00
Jan Prochazka 576fc2062c fix 2022-11-17 19:26:39 +01:00
Jan Prochazka 37a8783751 oauth working, but cycling sometimes 2022-11-17 12:43:38 +01:00
Jan Prochazka f42d78b2fb oauth returns access token 2022-11-14 21:20:58 +01:00
Jan Prochazka 792fa75ccd v5.1.6-beta.7 2022-11-13 18:39:30 +01:00
Jan Prochazka cbd3f1bae9 fixed number format 2022-11-13 18:39:13 +01:00
Jan Prochazka cd92231769 v5.1.6-beta.6 2022-11-13 17:56:19 +01:00
Jan Prochazka ecad1ae01b imrpoved closing inactive sessions 2022-11-13 17:21:47 +01:00
Jan Prochazka dc576e6ced changed timeouts for connection cleanup 2022-11-13 11:59:57 +01:00
Jan Prochazka 6cca81f8f1 cleanup of not used sessions 2022-11-13 11:52:31 +01:00
Jan Prochazka a9f1f19696 wincert renamed 2022-11-12 20:17:21 +01:00
Jan Prochazka 390ddac75b v5.1.6-beta.5 2022-11-12 19:43:30 +01:00
Jan Prochazka e2e7c6f06b cert update 2022-11-12 19:43:20 +01:00
Jan Prochazka 3a3d0683d5 v5.1.6-beta.4 2022-11-12 18:49:08 +01:00
Jan Prochazka d5534dcf07 added win.publisherName 2022-11-12 18:48:30 +01:00
Jan Prochazka b0a86f9f4a v5.1.6-beta.3 2022-11-12 18:11:54 +01:00
Jan Prochazka b833a30148 wincert changed 2022-11-12 18:11:42 +01:00
Jan Prochazka d9c1bbaa39 v5.1.6-beta.2 2022-11-10 16:43:14 +01:00
Jan Prochazka 4b74dbbd68 fixed #416: Double click does not maximize window do on MacOS 2022-11-10 13:41:55 +01:00
Jan Prochazka 9bcc61551c #406 show/hide reult window 2022-11-10 12:35:25 +01:00
Jan Prochazka ed71ef312d #406 keyboard shortcut to show/hide sidebar 2022-11-10 11:36:31 +01:00
Jan Prochazka 4fa043b7e5 fix 2022-11-10 11:06:40 +01:00
Jan Prochazka 83725dd349 fixed loading perspective 2022-11-10 10:51:51 +01:00
Jan Prochazka 4e25b71b06 removed folder text field 2022-11-10 10:11:47 +01:00
Jan Prochazka 607ae7c872 #274 allow to create folder 2022-11-10 10:10:53 +01:00
Jan Prochazka 66ade5823f ts fix 2022-11-10 09:46:54 +01:00
Jan Prochazka ebfa0a1939 allow drop on group #274 2022-11-10 09:45:41 +01:00
Jan Prochazka 909591404f v5.1.6-beta.1 2022-11-07 07:43:09 +01:00
Jan Prochazka 7a5f2a70ad fixed/removed svelte warnings 2022-11-06 13:32:17 +01:00
Jan Prochazka d41b254058 import type refactor 2022-11-06 13:31:13 +01:00
Jan Prochazka 435d06ffb9 rollup config - ignore some svelte warnings 2022-11-06 13:29:58 +01:00
Jan Prochazka f4a4eb7f9e ts const fix 2022-11-06 13:29:00 +01:00
Jan Prochazka 9910bbead3 Merge pull request #411 from qlaffont/master
FEAT: Folders support
2022-11-05 10:45:10 +01:00
Jan Prochazka cb619a0fe0 drag & drop into/from connection folder 2022-11-05 10:36:41 +01:00
Quentin Laffont b0d61f974c feat(app): able to set a parent 2022-11-04 10:05:17 +01:00
Quentin Laffont 8c051ff5f7 Merge pull request #1 from dbgate/master
update
2022-11-04 08:08:05 +01:00
Jan Prochazka f713a4b183 import type refactor 2022-11-03 16:45:28 +01:00
Jan Prochazka 6c7e263f0e Merge branch 'master' of github.com:dbgate/dbgate 2022-11-03 16:45:05 +01:00
Jan Prochazka ec3bfb4fae Screen postcss fix 2022-11-03 16:41:31 +01:00
Jan Prochazka 712ec8e6ee Merge pull request #409 from notz/fix-mongodb-url-with-ssh
Fix connection to mongodb via database url if a ssh tunnel is used
2022-11-03 13:41:42 +01:00
Gernot Pansy 4da0b25f44 Fix connection to mongodb via database url if a ssh tunnel is used
* Replaces the the port with the tunnel port in the url
2022-11-03 11:01:24 +01:00
Jan Prochazka 9b60b7a003 fix perspective error 2022-11-03 09:18:41 +01:00
Quentin Laffont 8ed73195c5 chore(app): add node version 2022-11-03 09:13:54 +01:00
Quentin Laffont c69fcd5eff feat(connections): able to save parent Id 2022-11-03 08:35:49 +01:00
Jan Prochazka 310774db3b v5.1.5 2022-10-15 22:10:11 +02:00
Jan Prochazka 1dd166b563 Merge branch 'develop' 2022-10-15 22:09:45 +02:00
Jan Prochazka 0497f541cb changelog 2022-10-15 22:08:57 +02:00
Jan Prochazka 42333a97b8 v5.1.5-beta.4 2022-10-13 15:36:24 +02:00
Jan Prochazka 494c3c8e4a remap Command+H on mac #390 2022-10-13 15:28:50 +02:00
Jan Prochazka 69a87bc076 perspective expand fix 2022-10-13 15:22:23 +02:00
Jan Prochazka bf4eb19ef5 perspective fixes 2022-10-13 15:01:45 +02:00
Jan Prochazka 225518df3e show json icon in perspectives 2022-10-13 14:09:08 +02:00
Jan Prochazka 0028240552 perspective fix 2022-10-13 13:49:48 +02:00
Jan Prochazka 44be1bdd11 menu label 2022-10-13 12:36:48 +02:00
Jan Prochazka e0703b1bae Merge branch 'master' into develop 2022-10-13 11:02:40 +02:00
Jan Prochazka a240681d6d auto view json #395 2022-10-13 11:02:25 +02:00
Jan Prochazka f5906587db perspectives: prevent multi-load 2022-10-13 10:52:10 +02:00
Jan Prochazka dc0001a8cd sql case configuration #389 2022-10-08 21:14:18 +02:00
Jan Prochazka f19835203f fixed pager component #388 2022-10-08 09:08:42 +02:00
Jan Prochazka 2a2debbb88 fix nested mongo id as $oid #387 2022-10-08 09:00:19 +02:00
Jan Prochazka 23cb3a4b12 table&database ctx menu improvement 2022-10-08 08:34:31 +02:00
Jan Prochazka 13d4d34453 cond-disable ER diagram and query design #386 2022-10-08 08:09:45 +02:00
Jan Prochazka 2adca64159 socketPath configurable with env variables #358 2022-10-04 20:58:10 +02:00
Jan Prochazka 18519b5519 v5.1.5-beta.3 2022-10-02 21:04:41 +02:00
Jan Prochazka 4ddea55d23 Merge branch 'master' into develop 2022-10-02 21:04:25 +02:00
Jan Prochazka 5858061349 v5.1.5-beta.2 2022-10-02 21:03:22 +02:00
Jan Prochazka d86a5c0cb4 fix 2022-10-02 21:02:23 +02:00
Jan Prochazka c712005e33 v5.1.5-beta.1 2022-10-02 21:00:29 +02:00
Jan Prochazka 7e28e2257e Merge branch 'master' into develop 2022-10-02 20:59:54 +02:00
Jan Prochazka d0c7d591c8 don't tag BETA docker images with version 2022-10-02 20:58:52 +02:00
Jan Prochazka 17b73a58c8 changelog 2022-10-02 20:56:05 +02:00
Jan Prochazka d765591e8c v5.1.4 2022-10-02 20:52:53 +02:00
Jan Prochazka be0aeeb2c8 perspective - pattern for SQL sources 2022-10-02 20:52:22 +02:00
Jan Prochazka 23b345c898 perspective mongo fixes 2022-10-02 17:48:03 +02:00
Jan Prochazka 1d85a17533 fix 2022-10-02 15:43:00 +02:00
Jan Prochazka 7a3c46b691 perspective display - mongo nested objects 2022-10-02 12:01:07 +02:00
Jan Prochazka d647d30258 perspective nosql test 2022-10-02 11:30:05 +02:00
Jan Prochazka 8b511a0532 removed commented code 2022-10-02 10:19:53 +02:00
Jan Prochazka ccb52e9b58 fix 2022-10-02 10:19:01 +02:00
Jan Prochazka f60e1190c8 perspectives: mongo join works 2022-10-02 09:44:52 +02:00
Jan Prochazka da5dd7ac62 perspective mongo sort 2022-10-01 19:18:18 +02:00
Jan Prochazka 08abec7c3e perspective mongo condition 2022-10-01 18:50:54 +02:00
Jan Prochazka b3839def32 mongo perspective stuff - basic skeleton works 2022-10-01 17:48:47 +02:00
Jan Prochazka efe15bf0bb mongo perspective fixes 2022-10-01 16:44:34 +02:00
Jan Prochazka f9e167fc7b perspective data pattern 2022-10-01 14:43:25 +02:00
Jan Prochazka b35e8fcdf4 v5.1.4-beta.11 2022-09-29 19:42:50 +02:00
Jan Prochazka 4bdd988682 fix 2022-09-29 19:42:34 +02:00
Jan Prochazka 94f21472be v5.1.4-beta.10 2022-09-29 19:36:18 +02:00
Jan Prochazka dd33d96ef6 close tabs question 2022-09-29 19:35:58 +02:00
Jan Prochazka 7604889b72 unsaved file marker 2022-09-29 13:58:09 +02:00
Jan Prochazka 1382461bdc current query part fix 2022-09-29 11:01:17 +02:00
Jan Prochazka 833f029ab5 drop database #384 2022-09-29 09:58:35 +02:00
Jan Prochazka 04d39f6646 single docker builder 2022-09-28 20:47:32 +02:00
Jan Prochazka 4de8a5b038 v5.1.4-docker.9 2022-09-28 20:44:32 +02:00
Jan Prochazka 1dfdeed018 actions fix 2022-09-28 20:42:59 +02:00
Jan Prochazka 4892e46795 v5.1.4-docker.8 2022-09-28 20:37:42 +02:00
Jan Prochazka 5aff68d313 single docker build file 2022-09-28 20:37:32 +02:00
Jan Prochazka cdd4382266 v5.1.4-docker.7 2022-09-28 20:12:37 +02:00
Jan Prochazka bbd00ac94d multi platform 2022-09-28 20:12:25 +02:00
Jan Prochazka dba3183c94 v5.1.4-docker.6 2022-09-28 20:09:19 +02:00
Jan Prochazka a2906cca9d docker build fix 2022-09-28 20:09:05 +02:00
Jan Prochazka 140291696b v5.1.4-docker.5 2022-09-28 19:58:29 +02:00
Jan Prochazka 975643fb24 fix 2022-09-28 19:58:14 +02:00
Jan Prochazka bf9a933fb1 v5.1.4-docker.4 2022-09-28 19:44:09 +02:00
Jan Prochazka 643b792069 docker for arm platform #383 2022-09-28 19:43:54 +02:00
Jan Prochazka b4d0ccbd8c v5.1.4-docker.3 2022-09-28 19:40:06 +02:00
Jan Prochazka c9bf949d02 version fix 2022-09-28 19:37:57 +02:00
Jan Prochazka 074390ac11 v5.1.4-docker.2 2022-09-28 19:22:56 +02:00
Jan Prochazka 45e54475d0 docker build 2022-09-28 19:22:41 +02:00
Jan Prochazka f157fc77d4 docker fix 2022-09-28 19:18:30 +02:00
Jan Prochazka dac1110404 v5.1.4-docker.1 2022-09-28 19:02:43 +02:00
Jan Prochazka da00e1c228 docker build with tags 2022-09-28 19:02:13 +02:00
Jan Prochazka 9ed1cdf4b7 redis key separator fix #379 2022-09-28 18:18:03 +02:00
Jan Prochazka 18b7792370 customizable redis key separator #379 2022-09-28 18:11:46 +02:00
Jan Prochazka 53b6b71a29 non default schema name in tab title 2022-09-28 16:56:47 +02:00
Jan Prochazka b2204e1d77 using gutte3r decorations for active query part 2022-09-28 13:21:21 +02:00
Jan Prochazka e7ac7558ca better UX of code editor 2022-09-28 13:04:50 +02:00
Jan Prochazka c5a7f458ba better editor SQL splitting 2022-09-28 12:24:06 +02:00
Jan Prochazka 8ce5e68c0d typo 2022-09-28 09:19:53 +02:00
Jan Prochazka e9256fe20e changelog 2022-09-26 20:19:07 +02:00
Jan Prochazka 5913788035 v5.1.3 2022-09-26 19:53:21 +02:00
Jan Prochazka 6c9c4be311 v5.1.3-beta.2 2022-09-25 20:11:22 +02:00
Jan Prochazka 1454ddacb8 fix 2022-09-25 20:10:56 +02:00
Jan Prochazka 2b26779ea8 fixes + sqlite error line number 2022-09-25 20:06:34 +02:00
Jan Prochazka 7781ad69cf sql error line number - postgres 2022-09-25 19:50:31 +02:00
Jan Prochazka 1a7f06342f query error markers 2022-09-25 19:45:47 +02:00
Jan Prochazka 2f820d8dac sql editor - play icon to execute sql fragment 2022-09-25 14:43:10 +02:00
Jan Prochazka 1535dfd407 youtube link 2022-09-25 11:42:30 +02:00
Jan Prochazka 3fe7d652b2 multiline json editing 2022-09-25 09:29:38 +02:00
Jan Prochazka 7fc8b2901b multiline cell editor #378 #371 #359 2022-09-25 08:58:39 +02:00
Jan Prochazka a56f59ceba readme 2022-09-23 21:36:24 +02:00
Jan Prochazka 2ac1072357 v5.1.3-beta.1 2022-09-22 18:46:33 +02:00
Jan Prochazka 24c26a6d87 UX fix 2022-09-22 18:46:14 +02:00
Jan Prochazka 83693e9f2c perspectives: show row count 2022-09-22 18:23:04 +02:00
Jan Prochazka 59efdd735c truncate table context menu #333 2022-09-22 16:01:52 +02:00
Jan Prochazka 41afd177ef editing multiline cell value #378 #371 #359 2022-09-22 15:05:05 +02:00
Jan Prochazka 0137b191b9 changelog 2022-09-19 19:36:59 +02:00
Jan Prochazka 054b90c90d changelog 2022-09-19 19:35:47 +02:00
Jan Prochazka a46526cbc8 v5.1.2 2022-09-19 19:29:28 +02:00
Jan Prochazka 35c42d0a83 v5.1.2-beta.5 2022-09-18 19:50:59 +02:00
Jan Prochazka 6e2ecd0b05 perspective: show undefined
cells
2022-09-18 18:51:10 +02:00
Jan Prochazka a98a4617ae #371 wip 2022-09-18 18:43:06 +02:00
Jan Prochazka 1a716f0bce sql condition in filter dialog #369 2022-09-18 14:57:30 +02:00
Jan Prochazka 973f64f4d7 custom SQL condition #369 2022-09-17 21:42:20 +02:00
Jan Prochazka a89c6810aa query design ordering more posibilities #372 2022-09-17 10:06:23 +02:00
Jan Prochazka 3d45b00a7c form view cursor commands on toolbar #370 2022-09-17 09:59:37 +02:00
Jan Prochazka f93524e24f condition editor-allow combine NULL,NOT NULL #368 2022-09-17 09:48:54 +02:00
Jan Prochazka 9aded740ca #373 fixed mongodb export 2022-09-17 09:25:12 +02:00
Jan Prochazka 66f30ff26e v5.1.2-beta.4 2022-09-15 16:49:12 +02:00
Jan Prochazka 4ced94f070 perspective image display 2022-09-15 16:48:57 +02:00
Jan Prochazka fe61e5e631 json view in perspective improvement 2022-09-15 16:04:44 +02:00
Jan Prochazka 24b0d278fd v5.1.2-beta.3 2022-09-12 20:46:42 +02:00
Jan Prochazka de5b075ba5 perspective inline json view 2022-09-12 20:45:26 +02:00
Jan Prochazka 1665c014e1 perspective fix 2022-09-12 20:16:45 +02:00
Jan Prochazka 586a06da91 v5.1.2-beta.2 2022-09-11 20:14:31 +02:00
Jan Prochazka eb1eb18163 reorder query design columns #362 2022-09-11 10:24:10 +02:00
Jan Prochazka 1983576b2f fixed editing sort order in query designer #363 2022-09-11 08:42:32 +02:00
Jan Prochazka ffbb91678c v5.1.2-beta.1 2022-09-08 15:49:54 +02:00
Jan Prochazka 0293766bad connecting via socket for mysql and postgres #358 2022-09-08 14:23:13 +02:00
Jan Prochazka 5eda39cb62 rows affected info for postgresql 2022-09-08 11:04:43 +02:00
Jan Prochazka b7c8a60c19 affected rows info for MySQL & MariaDB #361 2022-09-08 10:51:06 +02:00
Jan Prochazka 51101d91ea screenshot 2022-09-05 20:53:46 +02:00
Jan Prochazka cc9acf71ce readm screenshot 2022-09-05 20:51:12 +02:00
Jan Prochazka d27f8644d8 readme screenshot 2022-09-05 20:43:23 +02:00
Jan Prochazka 347448e3c2 changelog 2022-09-05 20:13:31 +02:00
Jan Prochazka 0a008a760b v5.1.1 2022-09-05 20:08:45 +02:00
Jan Prochazka 462be9e2bd v5.1.1-beta.5 2022-09-04 20:31:42 +02:00
Jan Prochazka f078872c5b postgre rename column fixed #350 2022-09-04 11:00:36 +02:00
Jan Prochazka fdecef7e78 analyse computed columns on ms sql #354 2022-09-04 10:04:24 +02:00
Jan Prochazka 8acafbbd6e Clear filter hotkey 2022-09-04 08:55:42 +02:00
Jan Prochazka 5b8d70747f fixed datetime null condition #356 2022-09-04 08:47:58 +02:00
Jan Prochazka c9a9c7d0f7 v5.1.1-beta.4 2022-09-01 19:19:23 +02:00
Jan Prochazka 50eb5012b1 perspective: place nodes not in tree 2022-09-01 19:18:46 +02:00
Jan Prochazka 917c2f49a0 temp root in perspectives 2022-09-01 19:12:03 +02:00
Jan Prochazka 5724067974 fix 2022-09-01 18:35:50 +02:00
Jan Prochazka 428de38b41 grayed nodes in perspective designer 2022-09-01 17:51:40 +02:00
Jan Prochazka 9e73e16b7f parent filter icon in designer 2022-09-01 17:38:43 +02:00
Jan Prochazka 1e91097bf2 splitter doesn't recreate children on collapse 2022-09-01 16:20:35 +02:00
Jan Prochazka 61f82be9f3 fix 2022-09-01 15:53:44 +02:00
Jan Prochazka 91e1c83a91 perspective - fixed work with specific DB 2022-09-01 15:50:03 +02:00
Jan Prochazka e8452704eb perspective collapsible splitters 2022-09-01 14:55:20 +02:00
Jan Prochazka 357fcbdf47 collapsible vertical splitter 2022-09-01 14:48:29 +02:00
Jan Prochazka 02abb4f512 add fk reference from designer 2022-09-01 14:22:54 +02:00
Jan Prochazka 14f71e80d3 skip loading data without columns 2022-09-01 13:35:51 +02:00
Jan Prochazka fdcf1c4c9a fixed perspective tests 2022-09-01 12:03:19 +02:00
Jan Prochazka 97e96aaba6 some perspective tests fixed 2022-09-01 11:59:25 +02:00
Jan Prochazka 174b0efd2e perspective checked fix 2022-09-01 11:21:31 +02:00
Jan Prochazka eab5f4fe5e new perspective command 2022-09-01 11:18:25 +02:00
Jan Prochazka a910e91a91 fix perspective 2022-09-01 10:56:58 +02:00
Jan Prochazka 3e83a69ef7 handle invalid perspective format 2022-09-01 10:10:19 +02:00
Jan Prochazka e3b833927d v5.1.1-beta.3 2022-08-30 21:40:40 +02:00
Jan Prochazka 6582c7831e perspective: fixed menu not not rooted nodes 2022-08-30 21:40:27 +02:00
Jan Prochazka 0d2169c996 v5.1.1-beta.2 2022-08-29 22:40:14 +02:00
Jan Prochazka e64d013fee perspective: view fix, UX 2022-08-29 22:37:04 +02:00
Jan Prochazka c1627b8546 v5.1.1-beta.1 2022-08-28 14:10:24 +02:00
Jan Prochazka 2f74eab048 better paint perspective 2022-08-28 14:08:13 +02:00
Jan Prochazka f7a269383f perspective designer table icon 2022-08-28 13:35:22 +02:00
Jan Prochazka 5f9156995b perspective set root command 2022-08-28 13:22:41 +02:00
Jan Prochazka f886b8c95d perspective alias 2022-08-28 13:11:42 +02:00
Jan Prochazka 2284264a92 perspective filter menu 2022-08-28 12:10:53 +02:00
Jan Prochazka f405db7685 show sort in perspective deisgner and tree 2022-08-28 12:02:38 +02:00
Jan Prochazka 14110cb6db reimplemented filter, sort for new model 2022-08-28 10:50:12 +02:00
Jan Prochazka 1e347f6535 perspective fixes 2022-08-28 08:42:07 +02:00
Jan Prochazka 0813f4387d arrange fix 2022-08-28 08:09:54 +02:00
Jan Prochazka 894a864110 perspective fixes 2022-08-28 07:52:36 +02:00
Jan Prochazka 4e799885b5 perspective default columns - before refactor 2022-08-28 07:25:02 +02:00
Jan Prochazka 650f9a3db9 fix 2022-08-27 20:11:20 +02:00
Jan Prochazka 6b5e33d97e default columns processor 2022-08-27 19:50:51 +02:00
Jan Prochazka 24923db199 ensure node config 2022-08-27 19:17:49 +02:00
Jan Prochazka 80faf0fd68 alias fix 2022-08-27 18:19:54 +02:00
Jan Prochazka 33b11eef38 custom joins 2022-08-27 18:07:49 +02:00
Jan Prochazka b6a0fe6713 node checked & column checked distuingish 2022-08-27 16:02:15 +02:00
Jan Prochazka 2b68a6e1de FK secondary checkbox 2022-08-27 15:26:11 +02:00
Jan Prochazka e124291267 perspective designer - checking columns 2022-08-27 12:27:07 +02:00
Jan Prochazka 1a16d7c69e changed perspective checked logic 2022-08-27 11:57:54 +02:00
Jan Prochazka 6cb2616d87 designer customization 2022-08-27 10:42:58 +02:00
Jan Prochazka 395863da3f simplify designer settings 2022-08-27 10:17:11 +02:00
Jan Prochazka fec2df9d2f perspective tree layout 2022-08-27 10:06:06 +02:00
Jan Prochazka 9e3a457ef5 perspective designer auto arrange 2022-08-27 09:19:17 +02:00
Jan Prochazka 728ad21d2f perspective arrange button 2022-08-26 19:17:35 +02:00
Jan Prochazka d2f18bc048 checkedNodes => checkedColumns 2022-08-26 18:25:40 +02:00
Jan Prochazka 0ae7939f93 table designer checkbox 2022-08-26 18:23:43 +02:00
Jan Prochazka 7ac0b907e2 perspective designer 2022-08-25 21:11:07 +02:00
Jan Prochazka 1bd4b77744 fix 2022-08-25 18:31:55 +02:00
Jan Prochazka 5e4ae3208b fixed bug in perspective display + fixed test 2022-08-25 18:01:00 +02:00
Jan Prochazka daf7629f5f perspective designer WIP 2022-08-25 15:20:16 +02:00
Jan Prochazka aeceb34d19 perspective refactor WIP 2022-08-25 13:18:55 +02:00
Jan Prochazka 2a98918857 open qdesign and perspective file #349 2022-08-25 09:13:02 +02:00
Jan Prochazka ce9d583989 added restore-terminals config 2022-08-19 15:47:55 +02:00
Jan Prochazka 7c87baf451 custom editor size #345 2022-08-19 15:10:04 +02:00
Jan Prochazka f80c6fec99 readme 2022-08-08 20:49:32 +02:00
Jan Prochazka b04af4c5e3 typo 2022-08-08 20:41:06 +02:00
Jan Prochazka fe65193189 typo 2022-08-08 20:40:32 +02:00
Jan Prochazka a75e463ef5 v5.1.0 2022-08-08 20:20:31 +02:00
Jan Prochazka 7eb59ad3a0 changelog - docs link 2022-08-08 19:50:07 +02:00
Jan Prochazka 7a9f8a460f v5.1.0-beta.4 2022-08-08 19:47:03 +02:00
Jan Prochazka 289752c023 Merge branch 'develop' 2022-08-08 19:46:39 +02:00
Jan Prochazka 98f2c06c21 perspectives: default column algorithm 2022-08-08 19:46:12 +02:00
Jan Prochazka 530b1cade3 perspective UX 2022-08-08 19:40:50 +02:00
Jan Prochazka 65aa8fb4e3 fixed multi - database structure store 2022-08-08 19:37:40 +02:00
Jan Prochazka 4c0f17a0b2 changelog 2022-08-07 20:35:04 +02:00
Jan Prochazka e4371c526b v5.1.0-beta.3 2022-08-07 20:29:04 +02:00
Jan Prochazka e39f0a1f4b perspective parent filter fix 2022-08-07 20:28:41 +02:00
Jan Prochazka 842f77d02b v5.1.0-beta.2 2022-08-07 19:37:04 +02:00
Jan Prochazka 2571e6ac7e fixed tests 2022-08-07 19:36:37 +02:00
Jan Prochazka 1599a7ea01 v5.1.0-beta.1 2022-08-07 19:30:25 +02:00
Jan Prochazka cb1d81b586 perspectives: parent filter switch in filters 2022-08-07 19:30:00 +02:00
Jan Prochazka 339588b8a0 parent filter implementation 2022-08-07 19:16:23 +02:00
Jan Prochazka 1731b7e4a3 parentFilter - declarative support 2022-08-07 18:12:10 +02:00
Jan Prochazka 5418bb932c removed commented code 2022-08-07 16:49:16 +02:00
Jan Prochazka 6154b4c780 perspective:removed filterInfos,using only filters 2022-08-07 16:48:27 +02:00
Jan Prochazka 3f9bd100e1 perspective refactor 2022-08-07 16:40:37 +02:00
Jan Prochazka b5c6ddce59 perspective: filter this value, open filtered table 2022-08-07 16:03:20 +02:00
Jan Prochazka 51c72efb34 fixed NTLM auth in SQL server #305 2022-08-07 15:13:10 +02:00
Jan Prochazka 00df20e350 imrpoved editing data with keyboard #331 2022-08-07 12:01:02 +02:00
Jan Prochazka f3a7e3af74 option to skip table save confirmation #329 2022-08-07 11:21:08 +02:00
Jan Prochazka 04c37c2b4f v5.0.10-beta.14 2022-08-07 10:42:39 +02:00
Jan Prochazka 12df0993c0 fixed sqlite3 native module version 2022-08-07 10:42:27 +02:00
Jan Prochazka ac3ec5c11e #324 fixed column type syntax for mysql 2022-08-07 10:17:32 +02:00
Jan Prochazka b565e981e4 v5.0.10-beta.13 2022-08-07 10:05:17 +02:00
Jan Prochazka f7ada698e4 fix 2022-08-07 10:04:32 +02:00
Jan Prochazka bc4c146389 remove msnodesqlv8 from mac+linux build 2022-08-07 10:02:11 +02:00
Jan Prochazka 7c80ca1374 Revert "try to fix mac build"
This reverts commit 1974243ed5.
2022-08-07 09:52:59 +02:00
Jan Prochazka 8c5cc7dcc1 v5.0.10-beta.12 2022-08-07 09:03:18 +02:00
Jan Prochazka 1974243ed5 try to fix mac build 2022-08-07 09:02:51 +02:00
Jan Prochazka 71c9071cb8 default action on connection click: connect #332 2022-08-07 08:44:31 +02:00
Jan Prochazka c28e55132a v5.0.10-beta.11 2022-08-07 08:28:38 +02:00
Jan Prochazka 2b2a4debd4 sqlite prebuild for mac 2022-08-07 08:28:21 +02:00
Jan Prochazka 563a35560b save perspective to file 2022-08-06 17:43:49 +02:00
Jan Prochazka cc019281d4 perspective custom joins supports views 2022-08-06 17:03:48 +02:00
Jan Prochazka 86d7d61cc5 perspectives: custom join over different databases 2022-08-06 16:44:37 +02:00
Jan Prochazka aff1fe0b3d perspectives: prefer not circular lookups 2022-08-06 15:30:49 +02:00
Jan Prochazka 137631b5b5 sort references 2022-08-06 14:37:00 +02:00
Jan Prochazka 090ffa064d perspective: open table ctx menu 2022-08-06 14:05:18 +02:00
Jan Prochazka f77cc1023b perspective column filter 2022-08-06 13:49:05 +02:00
Jan Prochazka c6dbb31748 perspective filters supports lookup 2022-08-06 13:24:51 +02:00
Jan Prochazka ae6c486db5 perspective load fix 2022-08-06 11:37:44 +02:00
Jan Prochazka 9a2c12d558 perspective context menu 2022-08-05 20:55:04 +02:00
Jan Prochazka 1ed01e9839 perspective cell highlight 2022-08-05 20:17:49 +02:00
Jan Prochazka 25d2c129cd perspective ctx menu 2022-08-05 19:55:14 +02:00
Jan Prochazka 7dc7af0cdb v5.0.10-beta.10 2022-08-04 21:32:20 +02:00
Jan Prochazka 80fea3b01b style 2022-08-04 21:32:06 +02:00
Jan Prochazka 97dc92e413 perspectives:add to filter ctx menu 2022-08-04 08:26:35 +02:00
Jan Prochazka 9051ba2ee1 filter list in perspective 2022-08-04 08:16:22 +02:00
Jan Prochazka 7dcbe6c7c1 v5.0.10-beta.9 2022-08-03 20:51:22 +02:00
Jan Prochazka e6fe8a6379 persp: fixed loading 2022-08-03 20:31:29 +02:00
Jan Prochazka b793e4131d perspectives: scroll optimalization 2022-08-03 20:23:36 +02:00
Jan Prochazka b737eaac13 v5.0.10-beta.8 2022-07-31 21:10:14 +02:00
Jan Prochazka cb5cce2ea3 custom joins working on the same DB 2022-07-31 21:09:58 +02:00
Jan Prochazka b05d260caa perspective custom join editing & removing 2022-07-31 20:53:22 +02:00
Jan Prochazka 091e91556d custom join dialog 2022-07-31 20:09:48 +02:00
Jan Prochazka 2b4120435b perspectives support views 2022-07-31 16:56:09 +02:00
Jan Prochazka c8d031e2c4 removed debug code 2022-07-31 16:10:57 +02:00
Jan Prochazka ac07b7e1ba code cleanup 2022-07-31 15:30:06 +02:00
Jan Prochazka bf51f45934 removed perspective intersection observer 2022-07-31 15:28:04 +02:00
Jan Prochazka fe31cfb552 css fix 2022-07-31 12:28:08 +02:00
Jan Prochazka d505be09ca perspectives - sort 2022-07-31 12:24:06 +02:00
Jan Prochazka 44668b8017 perspective sort - divided by table 2022-07-31 12:22:13 +02:00
Jan Prochazka 452dba7f32 perspective sorting 2022-07-31 12:10:56 +02:00
Jan Prochazka 7694864fe7 perspective loading indicator 2022-07-31 10:12:22 +02:00
Jan Prochazka 37d5c6fbf9 cell data formatting in perspectives 2022-07-31 09:40:20 +02:00
Jan Prochazka 802f231e43 ts fix 2022-07-31 08:52:10 +02:00
Jan Prochazka 53c39e6a43 run perspectives test on CI 2022-07-31 08:49:25 +02:00
Jan Prochazka 65f550023a removed obsolete code 2022-07-31 08:47:32 +02:00
Jan Prochazka abe7a20960 perspective - changed display table algorithm 2022-07-31 08:46:24 +02:00
Jan Prochazka d686206fe2 perspective display test WIP 2022-07-31 08:11:04 +02:00
Jan Prochazka 27b2fdb507 Copy as JSON in JSON tab 2022-07-31 08:10:19 +02:00
Jan Prochazka 88f522084d show table name in perspective 2022-07-30 09:21:04 +02:00
Jan Prochazka 8472c8be79 fixed filter parser test (upgraded jestm, ts-jest) 2022-07-30 08:39:35 +02:00
Jan Prochazka 03f8a93dd0 perspective fix 2022-07-30 08:16:07 +02:00
Jan Prochazka 2889f79120 v5.0.10-beta.7 2022-07-30 08:08:12 +02:00
Jan Prochazka 8a312181a3 upgraded all dependencies 2022-07-30 08:07:23 +02:00
Jan Prochazka e7236de078 v5.0.10-beta.6 2022-07-30 07:35:44 +02:00
Jan Prochazka 1fe2269b11 upgraded better-sqlite3 2022-07-30 07:35:34 +02:00
Jan Prochazka 10ea8ca3a6 v5.0.10-beta.5 2022-07-29 21:32:54 +02:00
Jan Prochazka 491d24984d upgraded electron to v17 2022-07-29 21:31:45 +02:00
Jan Prochazka b0279dd315 display fix 2022-07-29 21:16:07 +02:00
Jan Prochazka 9d6b581809 remove commented code 2022-07-29 21:08:50 +02:00
Jan Prochazka 3f748df1ec perspective: fixed some table scenarios 2022-07-29 21:04:09 +02:00
Jan Prochazka 7ca835765c v5.0.10-beta.4 2022-07-28 21:41:01 +02:00
Jan Prochazka a76530155d filter child tables 2022-07-28 21:02:24 +02:00
Jan Prochazka 96b82b690e v5.0.10-beta.3 2022-07-28 20:43:26 +02:00
Jan Prochazka d3a40e52fc perspective defaults - FK columns 2022-07-28 20:43:03 +02:00
Jan Prochazka 513b2ba42f default checked columns 2022-07-28 20:35:39 +02:00
Jan Prochazka d23371f642 ref loading ref column 2022-07-28 20:03:48 +02:00
Jan Prochazka 5ac6e12c3e v5.0.10-beta.2 2022-07-28 19:24:26 +02:00
Jan Prochazka 4468c0ed3b fix perspective refresh 2022-07-28 19:23:17 +02:00
Jan Prochazka 06bd9bcabe perspective - show error, ability to reset filters 2022-07-28 18:57:15 +02:00
Jan Prochazka 66d15abcab last row render fix 2022-07-28 18:46:33 +02:00
Jan Prochazka 3bdb5c0152 perspective filters 2022-07-25 21:42:01 +02:00
Jan Prochazka f504283002 use position:sticky for table header 2022-07-25 20:48:33 +02:00
Jan Prochazka f07c7909ef fix 2022-07-25 20:37:15 +02:00
Jan Prochazka c809f58349 v5.0.10-beta.1 2022-07-24 21:25:06 +02:00
Jan Prochazka 3e91ecd141 perspective filters control 2022-07-24 21:17:52 +02:00
Jan Prochazka 857185a78b Merge branch 'master' into develop 2022-07-24 21:10:19 +02:00
Jan Prochazka c189c12cae changelog 2022-07-24 21:07:02 +02:00
Jan Prochazka 96106e6aac refresh perspective command 2022-07-24 15:56:29 +02:00
Jan Prochazka 088ca231f3 uniqe binding values 2022-07-24 15:34:26 +02:00
Jan Prochazka 5395d1343b nested incomplete loading fix 2022-07-24 15:16:02 +02:00
Jan Prochazka d48c34a4a5 perspctives: nested incremental loading 2022-07-24 14:23:56 +02:00
Jan Prochazka 53ee1d87c2 Merge branch 'master' into develop 2022-07-24 10:17:47 +02:00
Jan Prochazka b5d97c8181 v5.0.9 2022-07-24 10:17:17 +02:00
Jan Prochazka 28e06166e0 perspectives - prepare for nested incremental load 2022-07-21 18:10:43 +02:00
Jan Prochazka 8f1343bc42 perspectives: fixed incremental loading 2022-07-21 17:14:27 +02:00
Jan Prochazka 2080a23b69 incremental loading 2022-07-21 17:05:07 +02:00
Jan Prochazka d71294621b perspective cache - basic design 2022-07-21 15:43:17 +02:00
Jan Prochazka 0f6ec420d2 delete commented code 2022-07-21 12:33:44 +02:00
Jan Prochazka 35152a2796 perspective loader class 2022-07-21 12:33:29 +02:00
Jan Prochazka 1abfab950e perspectives: added data provider layer 2022-07-21 11:26:44 +02:00
Jan Prochazka 6e6d0bb616 Merge branch 'master' into develop 2022-07-21 09:33:26 +02:00
Jan Prochazka 93e264e9ec v5.0.9-beta.1 2022-07-21 09:33:11 +02:00
Jan Prochazka 29257f9bf9 added missing dependency 2022-07-21 09:32:03 +02:00
Jan Prochazka 8dd90ce5e4 fixed problem with SSE #323 2022-07-21 09:31:58 +02:00
Jan Prochazka f2f7421971 new diagram, new query design added to menu 2022-07-21 09:31:52 +02:00
Jan Prochazka 8a10beef52 added missing dependency 2022-07-21 09:31:02 +02:00
Jan Prochazka df33b43e90 fixed problem with SSE #323 2022-07-21 07:49:55 +02:00
Jan Prochazka 153cba3779 new diagram, new query design added to menu 2022-07-21 07:27:28 +02:00
Jan Prochazka 8f110355c4 Merge branch 'master' into develop 2022-07-18 22:46:31 +02:00
Jan Prochazka b570f873fe changelog 2022-07-18 20:51:38 +02:00
Jan Prochazka c07e26c036 v5.0.8 2022-07-18 20:46:40 +02:00
Jan Prochazka 995bc6f16a v5.0.8-beta.4 2022-07-17 19:16:27 +02:00
Jan Prochazka 5b4339889f OR in group filter 2022-07-17 19:15:42 +02:00
Jan Prochazka ae963d7a3b v5.0.8-beta.3 2022-07-17 17:28:17 +02:00
Jan Prochazka c426cd825f configurable editor font #308 2022-07-17 17:26:58 +02:00
Jan Prochazka 62c2b3f5f4 settings could be set from env variables #304 2022-07-17 16:57:56 +02:00
Jan Prochazka ab3584dc23 v5.0.8-beta.2 2022-07-17 10:07:13 +02:00
Jan Prochazka 3a5301af6b permissions for connections 2022-07-17 10:03:17 +02:00
Jan Prochazka 55efdef181 v5.0.8-beta.1 2022-07-17 08:51:42 +02:00
Jan Prochazka e9ea1edd21 fixed adding tables to empty designer 2022-07-17 08:51:02 +02:00
Jan Prochazka d9b91f2122 or conditions in query designer #321 2022-07-17 08:38:27 +02:00
Jan Prochazka 15da5fb95e table control - noCellPadding option 2022-07-17 07:59:16 +02:00
Jan Prochazka d563a40d0f qury designer - improved style 2022-07-16 21:03:08 +02:00
Jan Prochazka a4e5630f89 custom expressions in query designer #306 2022-07-16 20:53:11 +02:00
Jan Prochazka c368ad8d54 support specifying windows domain #305 2022-07-16 11:41:08 +02:00
Jan Prochazka 01d1f08597 changelog 2022-07-16 07:28:43 +02:00
Jan Prochazka 8c934355ab v5.0.7 2022-07-16 07:21:54 +02:00
Jan Prochazka c6e3b52bc6 v5.0.7-beta.5 2022-07-16 07:21:35 +02:00
Jan Prochazka e117caf708 typo 2022-07-16 07:21:23 +02:00
Jan Prochazka 2b4d5c026e Merge branch 'master' into develop 2022-07-14 21:26:07 +02:00
Jan Prochazka 93a736f1f8 v5.0.7-beta.4 2022-07-14 19:22:53 +02:00
Jan Prochazka 1f8ef8e20e fixed changing editor theme #300 2022-07-14 19:22:37 +02:00
Jan Prochazka bef8cdbee4 removed log 2022-07-14 16:50:00 +02:00
Jan Prochazka 763391e73b datagrid: clone rows #309 2022-07-14 16:27:36 +02:00
Jan Prochazka b1cd16b095 v5.0.7-beta.3 2022-07-14 15:25:49 +02:00
Jan Prochazka 2ee1b3105f #315 ssh2 client upgrade 2022-07-14 15:25:22 +02:00
Jan Prochazka 51fa652851 v5.0.7-beta.2 2022-07-14 14:21:07 +02:00
Jan Prochazka 755781bca6 trust server certificate option #305 2022-07-14 14:03:50 +02:00
Jan Prochazka 1a90729f66 date time interval filtering #311 2022-07-14 08:51:31 +02:00
Jan Prochazka 9e520e04b2 refactor: datetime filter parsed extracted 2022-07-14 07:57:06 +02:00
Jan Prochazka ded0c8398c mongo better UX 2022-07-14 07:31:11 +02:00
Jan Prochazka dc31552f9e fixed read mongo query #312 2022-07-14 07:27:38 +02:00
Jan Prochazka e0376a708c ssh tunnel logging #315 2022-07-14 05:38:59 +02:00
Jan Prochazka 1becb89ff0 code format 2022-07-14 05:10:11 +02:00
Jan Prochazka 4d7365828e perspective - styles 2022-07-01 14:54:41 +02:00
Jan Prochazka 29ccb09ba6 perspectives: loading only neccessary columns 2022-07-01 10:24:35 +02:00
Jan Prochazka eadd3feba0 fixed header fixes 2022-07-01 09:55:54 +02:00
Jan Prochazka 93269fe314 perspectives: fixed table header 2022-07-01 08:00:21 +02:00
Jan Prochazka 34ca4c501a fixed table header 2022-06-30 21:46:45 +02:00
Jan Prochazka 34084d0e94 perspective styling 2022-06-30 21:14:56 +02:00
Jan Prochazka 07fc551383 perspective row spans 2022-06-30 21:01:27 +02:00
Jan Prochazka b0eed05a1a perspective rows 2022-06-30 19:13:01 +02:00
Jan Prochazka 8228afd725 perspective rows WIP 2022-06-30 18:10:50 +02:00
Jan Prochazka 301222d118 perspectives: show nested columns 2022-06-30 10:38:03 +02:00
Jan Prochazka 9b741b415a v5.0.7-beta.1 2022-06-30 09:09:54 +02:00
Jan Prochazka cc8438ef66 configurable auto refresh inteval 2022-06-30 08:57:20 +02:00
Jan Prochazka 179bd1f6b1 table data auto refresh 2022-06-30 08:53:01 +02:00
Jan Prochazka 08b7b1870c refresh with ctrl+r #303 2022-06-30 07:40:36 +02:00
Jan Prochazka 2c7da1d3f8 changelog 2022-06-27 20:26:20 +02:00
Jan Prochazka 2a8a2c8652 v5.0.6 2022-06-27 20:22:48 +02:00
Jan Prochazka b6b75f0743 perspectives WIP 2022-06-23 16:50:56 +02:00
Jan Prochazka aca92f3889 perspectives: render simple table 2022-06-23 16:04:05 +02:00
Jan Prochazka 4672540f82 Merge branch 'master' into develop 2022-06-23 15:33:14 +02:00
Jan Prochazka 261cec7ec2 v5.0.6-beta.6 2022-06-23 14:58:41 +02:00
Jan Prochazka de444e8485 changed table ctx menu for redonly connections 2022-06-23 14:58:26 +02:00
Jan Prochazka f4fb92be91 v5.0.6-beta.5 2022-06-23 14:42:28 +02:00
Jan Prochazka 571c928234 handler script errors 2022-06-23 14:32:34 +02:00
Jan Prochazka 2fcc4b1ff0 perspectives WIP 2022-06-23 14:24:06 +02:00
Jan Prochazka c0b0ca22aa Merge branch 'master' of https://github.com/dbgate/dbgate 2022-06-23 14:23:53 +02:00
Jan Prochazka d862762758 runscript WIP 2022-06-23 14:23:46 +02:00
Jan Prochazka 7ca8880c3c Merge branch 'master' into develop 2022-06-23 11:18:36 +02:00
Jan Prochazka 21ccc55e3f v5.0.6-beta.4 2022-06-23 10:44:25 +02:00
Jan Prochazka 8662353071 removed incorrent readonly check 2022-06-23 10:42:12 +02:00
Jan Prochazka faedcfa64d v5.0.6-beta.3 2022-06-23 10:09:05 +02:00
Jan Prochazka 7ad1796db5 filtering by XML columsn in MSSQL 2022-06-23 10:06:09 +02:00
Jan Prochazka 717ec5293b Merge branch 'master' of https://github.com/dbgate/dbgate 2022-06-23 09:57:50 +02:00
Jan Prochazka d437e171fb fixed connection tab styling 2022-06-23 09:57:36 +02:00
Jan Prochazka 97ae7ae0d6 filtering works for complex columns 2022-06-23 09:52:41 +02:00
Jan Prochazka e9a8f3ee84 ability to reset view when grid load error occurs 2022-06-23 09:08:43 +02:00
Jan Prochazka 1fb237417a v5.0.6-alpha.2 2022-06-23 08:49:39 +02:00
Jan Prochazka cd65fa16ed fixes 2022-06-23 08:48:27 +02:00
Jan Prochazka 1e5a740a52 upgraded mongodb driver 2022-06-23 08:32:12 +02:00
Jan Prochazka 42badf17eb perspective - load hiearchic JSON 2022-06-20 22:14:48 +02:00
Jan Prochazka 2ec3c2c24f perspective tre shows dependencies 2022-06-18 08:46:40 +02:00
Jan Prochazka f3ab06d3b8 refactor 2022-06-18 08:00:00 +02:00
Jan Prochazka 2b78a8dcae perspective WIP 2022-06-17 22:30:10 +02:00
Jan Prochazka 389ef98c66 v5.0.6-beta.1 2022-06-16 17:06:06 +02:00
Jan Prochazka 75bf0e53fc perspectives WIP 2022-06-16 17:05:42 +02:00
Jan Prochazka ff4dd18c1b Merge branch 'master' into develop 2022-06-16 13:37:12 +02:00
Jan Prochazka 4c535289a4 connection type label 2022-06-16 13:36:50 +02:00
Jan Prochazka d24886c73b fix 2022-06-16 13:29:51 +02:00
Jan Prochazka 9883a2982a search in columns 2022-06-16 13:07:24 +02:00
Jan Prochazka 24191870e8 Merge branch 'master' into develop 2022-06-13 19:47:06 +02:00
Jan Prochazka b9dae8928e version fixed 2022-06-13 19:36:08 +02:00
Jan Prochazka 7bed880003 v5.0.5 2022-06-13 19:35:49 +02:00
Jan Prochazka e2b95ad372 changelog 2022-06-13 19:35:31 +02:00
Jan Prochazka 18710bc67d v5.0.4 2022-06-13 19:31:31 +02:00
Jan Prochazka 02e8bba999 Merge branch 'master' into develop 2022-06-12 20:20:37 +02:00
Jan Prochazka e770ca3eef v5.0.4-beta.9 2022-06-12 20:09:35 +02:00
Jan Prochazka aaa72426c3 v5.0.4-alpha.8 2022-06-12 20:02:58 +02:00
Jan Prochazka 53e5f1378c shell scripts blocked by default only when listen-api 2022-06-12 20:02:48 +02:00
Jan Prochazka 773abc6dff v5.0.4-alpha.7 2022-06-12 19:46:35 +02:00
Jan Prochazka 8abb311623 v5.0.4-beta.6 2022-06-12 19:45:55 +02:00
Jan Prochazka 2d83fb7dc4 start api => listen api 2022-06-12 19:45:27 +02:00
Jan Prochazka ae69ca9ebd explicit start api 2022-06-12 19:42:51 +02:00
Jan Prochazka 0cb4ec54bc perspective WIP 2022-06-12 19:30:54 +02:00
Jan Prochazka d34cff234c v5.0.4-beta.5 2022-06-12 17:59:05 +02:00
Jan Prochazka 50abead104 map fixes 2022-06-12 17:58:22 +02:00
Jan Prochazka 3b0ed7df8b v5.0.4-beta.4 2022-06-12 11:28:31 +02:00
Jan Prochazka ce925337f1 fix 2022-06-12 11:27:57 +02:00
Jan Prochazka a911f5048f v5.0.4-beta.3 2022-06-12 11:22:56 +02:00
Jan Prochazka 096cbc13d8 fixed filter bool values in postgres 2022-06-12 11:14:39 +02:00
Jan Prochazka a2cf1cd340 v5.0.4-alpha.2 2022-06-12 09:47:22 +02:00
Jan Prochazka 44827ea504 cacth error when reading archive 2022-06-12 09:16:10 +02:00
Jan Prochazka 13b549ca2c Merge branch 'develop' 2022-06-12 08:19:24 +02:00
Jan Prochazka c104122a50 default value support in table yaml files #296 2022-06-12 08:15:35 +02:00
Jan Prochazka 6794b79d0e postgre fix 2022-06-12 07:30:44 +02:00
Jan Prochazka 42200ec04a v5.0.4-beta.1 2022-06-11 22:21:35 +02:00
Jan Prochazka 2944d0fa39 postgis - analyse geo columns, show in map 2022-06-11 22:21:09 +02:00
Jan Prochazka 34496ced0e support for geograpghy view in mssql 2022-06-11 19:19:50 +02:00
Jan Prochazka fa0680a8ee changed export map name 2022-06-11 18:43:19 +02:00
Jan Prochazka f2402cadb0 show tooltip on map 2022-06-11 18:41:17 +02:00
Jan Prochazka ffe82a82fa export map to file 2022-06-11 18:34:57 +02:00
Jan Prochazka 6e1a1edac0 map on standalone tab 2022-06-11 17:57:18 +02:00
Jan Prochazka 427e25b3c0 map invalidate size 2022-06-11 17:24:01 +02:00
Jan Prochazka fca2bf8ddb show popup on map 2022-06-11 17:14:22 +02:00
Jan Prochazka f65c15d2e5 map - show points 2022-06-11 16:06:49 +02:00
Jan Prochazka 343cf84a58 map - show geometry in MySQL 2022-06-11 09:45:23 +02:00
Jan Prochazka e67a94b5d7 changelog 2022-06-10 20:29:41 +02:00
Jan Prochazka cc1916eba3 v5.0.3 2022-06-10 20:28:59 +02:00
Jan Prochazka 0a0ce6ad98 v5.0.3 2022-06-10 20:25:55 +02:00
Jan Prochazka fd21157c2d v5.0.3-beta.5 2022-06-09 15:11:39 +02:00
Jan Prochazka 8b3697e71e v5.0.3-beta.4 2022-06-09 15:10:18 +02:00
Jan Prochazka f3bebcfa8f fix 2022-06-09 15:10:11 +02:00
Jan Prochazka 4c145f1f0a Merge branch 'master' of github.com:dbgate/dbgate 2022-06-09 15:09:20 +02:00
Jan Prochazka cfce4e6ece v5.0.3-beta.4 2022-06-09 15:08:21 +02:00
Jan Prochazka 13d778586e fix mssql import (+integration test) 2022-06-09 14:57:08 +02:00
Jan Prochazka 77b85fa42b changelog 2022-06-09 14:17:45 +02:00
Jan Prochazka fb89c47563 v5.0.3-beta.3 2022-06-09 14:01:38 +02:00
Jan Prochazka 8ffbdfa01d open JSON file 2022-06-09 13:39:48 +02:00
Jan Prochazka 94788454a9 multiple sort criteria #235 2022-06-09 13:12:31 +02:00
Jan Prochazka a92bd1c840 configurable object actions #255 2022-06-09 11:31:31 +02:00
Jan Prochazka 610e9f4e60 settings - default connection action 2022-06-09 10:13:05 +02:00
Jan Prochazka 6e9dace360 fix 2022-06-09 09:37:26 +02:00
Jan Prochazka 148222e239 code style 2022-06-09 09:25:47 +02:00
Jan Prochazka 5e2279cd10 unsaved connection workflow fix 2022-06-09 09:24:05 +02:00
Jan Prochazka b54026b039 connection tabs - improved UX 2022-06-09 09:16:40 +02:00
Jan Prochazka 6f3076fddb #294 fixed statusbar doesn't match active tab 2022-06-09 08:04:09 +02:00
Jan Prochazka 92c336624a v5.0.3-beta.2 2022-06-02 19:18:29 +02:00
Jan Prochazka 07d4b248bf fix 2022-06-02 19:18:15 +02:00
Jan Prochazka 1534099dc4 v5.0.3-beta.1 2022-06-02 17:32:37 +02:00
Jan Prochazka d483869aa6 reorder pinned tables #227 2022-06-02 17:32:07 +02:00
Jan Prochazka 8bb40e991b drag & drop - change order in pinned dbs #227 2022-06-02 17:26:45 +02:00
Jan Prochazka 5c6989bf91 fix 2022-06-02 16:57:23 +02:00
Jan Prochazka 5b503ae802 reset pk name in duplicate table 2022-06-02 16:52:45 +02:00
Jan Prochazka 5feb018e22 upgraded tedious driver 2022-06-02 16:47:46 +02:00
Jan Prochazka 97d259cd1e app object menu from tab 2022-06-02 16:09:20 +02:00
Jan Prochazka fa357cf8ce better UX when define SSH port #291 2022-06-02 15:48:45 +02:00
Jan Prochazka 7a0f5e171e correct handling null values in update keys 2022-06-02 15:44:03 +02:00
Jan Prochazka 24cfb23b39 fix 2022-06-02 15:42:38 +02:00
Jan Prochazka 06b6a5d3ae ability to close file uploader 2022-06-02 15:31:25 +02:00
Jan Prochazka 301ba1df60 upgraded mysql driver #293 2022-06-02 14:56:36 +02:00
Jan Prochazka 591c105e53 mssql analyser feedback messages 2022-06-02 12:13:48 +02:00
Jan Prochazka ee7198a913 analyse mysql views optimalization #273 2022-06-02 12:02:54 +02:00
Jan Prochazka 0209780f1c changelog 2022-06-02 11:50:38 +02:00
Jan Prochazka 5825e67a14 mysql analyser - loading messages 2022-06-02 11:39:11 +02:00
Jan Prochazka eb0a1221e4 postgreSQL loading structure optimalization #273 2022-06-02 11:03:40 +02:00
Jan Prochazka ca3f1d720d postgresql analyse optyimalization #273 2022-06-02 10:57:53 +02:00
Jan Prochazka a6f6680788 full refresh model can be called from command 2022-06-02 08:40:05 +02:00
Jan Prochazka a8047560af Merge branch 'release-5.0.1' 2022-06-02 08:30:51 +02:00
Jan Prochazka d63bc714eb v5.0.2 2022-06-02 08:29:18 +02:00
Jan Prochazka bce744a7bf v5.0.2-beta.3 2022-06-02 08:10:04 +02:00
Jan Prochazka b2694868a9 fix ssh tunnel #291 2022-06-02 08:09:52 +02:00
Jan Prochazka 3f22960849 load db structure progress (postgresql) #273 2022-05-26 16:32:05 +02:00
Jan Prochazka affb935f63 v5.0.2-beta.2 2022-05-25 20:34:08 +02:00
Jan Prochazka 3df2e1a445 portal connection fix 2022-05-25 20:33:56 +02:00
Jan Prochazka 0906bad235 v5.0.2-beta.1 2022-05-25 20:14:04 +02:00
Jan Prochazka 50a91516b6 v5.0.1-beta.1 2022-05-25 20:13:48 +02:00
Jan Prochazka 966a6e02c1 portal connect fix 2022-05-25 20:13:37 +02:00
Jan Prochazka e279569466 v5.0.1 2022-05-24 09:43:34 +02:00
Jan Prochazka 13017b9c9d v5.0.1-beta.1 2022-05-24 09:43:30 +02:00
Jan Prochazka 3d49fd7719 fix #287 2022-05-24 09:43:01 +02:00
Jan Prochazka c9987bdc98 changelog 2022-05-23 19:17:31 +02:00
Jan Prochazka d9a9f97d3a Merge branch 'develop' 2022-05-23 19:16:09 +02:00
Jan Prochazka 79b3444121 changelog 2022-05-23 19:15:53 +02:00
Jan Prochazka 8e323874b5 v5.0.0 2022-05-23 19:15:38 +02:00
Jan Prochazka 5a439f2cac v5.0.0-beta.7 2022-05-22 13:21:41 +02:00
Jan Prochazka 09e3be9ec3 more data types in table editor #285 2022-05-22 12:04:59 +02:00
Jan Prochazka 6a35107c5f fixed SQL export table name #277 2022-05-22 11:14:29 +02:00
Jan Prochazka 9ecf021199 native menu fix for mac #281 2022-05-22 10:35:16 +02:00
Jan Prochazka fb61f263a6 single database fixes 2022-05-22 10:17:15 +02:00
Jan Prochazka 4098c4e504 v5.0.0-beta.6 2022-05-21 22:07:47 +02:00
Jan Prochazka 2d0e595ef7 try to fix sqlite 2022-05-21 22:07:28 +02:00
Jan Prochazka 36cc41ebf3 v5.0.0-beta.5 2022-05-21 21:16:03 +02:00
Jan Prochazka 6ce62b9738 fix 2022-05-21 21:15:48 +02:00
Jan Prochazka 79e22bbe9c v5.0.0-beta.4 2022-05-21 11:30:49 +02:00
Jan Prochazka 6ee5f5d44d fix 2022-05-21 11:30:35 +02:00
Jan Prochazka e4835b505a v5.0.0-beta.3 2022-05-21 08:26:52 +02:00
Jan Prochazka d6d7ad99df test fix 2022-05-21 08:20:23 +02:00
Jan Prochazka ddf186ee6b Merge branch 'master' into develop 2022-05-21 08:05:39 +02:00
Jan Prochazka 5a54af71a8 port docs 2022-05-21 07:51:30 +02:00
Jan Prochazka 03950ef57e Merge pull request #282 from susnick/dragwindow
Dragwindow
2022-05-21 07:48:22 +02:00
Jan Prochazka bd7cc1580a Merge pull request #280 from susnick/portchange
Portchange
2022-05-21 07:47:48 +02:00
Scott Usnick 140e05bc85 allow drag on macos using the menu sidebar 2022-05-19 19:27:26 -04:00
Scott Usnick 07060218b1 update readme for new port 2022-05-19 19:08:04 -04:00
Scott Usnick 23546468bc change to port 5001 as 5000 conflicts on macos with ControlCenter 2022-05-19 19:03:31 -04:00
Jan Prochazka fa0a243418 v5.0.0-beta.2 2022-05-19 21:04:46 +02:00
Jan Prochazka 9ab1ddc182 fixed sqlite test 2022-05-19 21:04:06 +02:00
Jan Prochazka bd79e96035 updated version 2022-05-19 20:52:43 +02:00
Jan Prochazka 0a1fe0df10 better sqlite - added mac arm64 binary prebuild 2022-05-19 20:47:10 +02:00
Jan Prochazka 5b9c27023c v5.0.0-beta.1 2022-05-19 16:16:38 +02:00
Jan Prochazka ce7c734265 v5.0.0-alpha.1 2022-05-19 16:16:05 +02:00
Jan Prochazka 32e4e36258 load diagram file #278 2022-05-19 14:59:42 +02:00
Jan Prochazka 2a3b4fe4d8 removed socket.io references 2022-05-19 13:43:07 +02:00
Jan Prochazka 1aa1d09c8b redis - disable ssl tab 2022-05-19 13:18:06 +02:00
Jan Prochazka 00c9ac61c4 refactor 2022-05-19 13:12:11 +02:00
Jan Prochazka 1d013f96fb connection workflow 2022-05-19 13:05:59 +02:00
Jan Prochazka b3a2197820 close tab group with middle button 2022-05-19 12:42:05 +02:00
Jan Prochazka 8e5584e90f connection workflow 2022-05-19 12:36:15 +02:00
Jan Prochazka 566082d40f open server connection when opening DB connection 2022-05-19 12:26:28 +02:00
Jan Prochazka 96b2c7280d connection workflow 2022-05-19 12:13:46 +02:00
Jan Prochazka 2f8282cbce connect from connection tab 2022-05-19 09:42:53 +02:00
Jan Prochazka e59eb4b8e6 connection tab 2022-05-19 08:26:51 +02:00
Jan Prochazka a799f9b9c9 v4.8.9-beta.1 2022-05-17 21:28:50 +02:00
Jan Prochazka c925ce9652 better app loading progress 2022-05-17 21:25:00 +02:00
Jan Prochazka ce4124caef renamed dbgate-data to .dbgate #248 2022-05-17 21:05:48 +02:00
Jan Prochazka eeb52b9a41 changelog 2022-04-29 17:53:21 +02:00
Jan Prochazka babe6d6d1b v4.8.8 2022-04-29 17:47:42 +02:00
Jan Prochazka e6d0faf273 v4.8.8-beta.6 2022-04-28 16:08:48 +02:00
Jan Prochazka 10b803d901 fixed changing tabs with ctrl+tab #245 2022-04-28 16:08:32 +02:00
Jan Prochazka 39cb665b32 fix 2022-04-28 15:42:32 +02:00
Jan Prochazka 4c9ae46577 import table wizard 2022-04-28 15:31:41 +02:00
Jan Prochazka 9e25a45090 import simplify/fix 2022-04-28 14:43:04 +02:00
Jan Prochazka 51bd5c228b better import/export dump modals 2022-04-28 14:20:55 +02:00
Jan Prochazka 97c2dcbaf6 fix 2022-04-28 14:02:20 +02:00
Jan Prochazka cd8698fac9 create table backup popup menu 2022-04-28 13:43:10 +02:00
Jan Prochazka bc49435fbf better DB export UI 2022-04-28 11:54:31 +02:00
Jan Prochazka 4e32646ab8 upgrade mysql dumper 2022-04-28 11:35:36 +02:00
Jan Prochazka d79c9e159a icon 2022-04-28 08:16:27 +02:00
Jan Prochazka 3eab120aaf v4.8.8-beta.5 2022-04-27 08:11:16 +02:00
Jan Prochazka 5b48e0251a next icon attempt 2022-04-27 08:11:04 +02:00
Jan Prochazka a97788eefd gradient top 2022-04-27 07:55:39 +02:00
Jan Prochazka 4e27a1ab0f generate icon script 2022-04-27 07:47:48 +02:00
Jan Prochazka a0059698b0 v4.8.8-beta.4 2022-04-25 19:58:39 +02:00
Jan Prochazka 4bf3296042 icon fix 2022-04-25 19:58:24 +02:00
Jan Prochazka 31edd48257 v4.8.8-beta.3 2022-04-25 19:03:01 +02:00
Jan Prochazka 8e9a14665b icon 2022-04-25 19:02:24 +02:00
Jan Prochazka 793bc6b494 icon 2022-04-25 19:01:11 +02:00
Jan Prochazka 864b9c9333 icon 2022-04-25 18:37:19 +02:00
Jan Prochazka fb4dd06578 v4.8.8-beta.2 2022-04-24 23:11:26 +02:00
Jan Prochazka 3c8a0ebd22 transparent icons + icon converter 2022-04-24 23:11:10 +02:00
Jan Prochazka 3a20f24f7c app startup fix 2022-04-24 22:28:04 +02:00
Jan Prochazka aa8854da93 v4.8.8-beta.1 2022-04-24 15:35:28 +02:00
Jan Prochazka 82ae8e23e0 import db from local files 2022-04-24 15:11:46 +02:00
Jan Prochazka 4d7887a379 export sql dump - can export to files 2022-04-24 15:03:04 +02:00
Jan Prochazka 30b054dbec fixed object destroyed error 2022-04-24 13:20:49 +02:00
Jan Prochazka df743e8ade changed app icon 2022-04-24 10:11:17 +02:00
Jan Prochazka 7cc70dc5f8 changelog 2022-04-22 20:40:23 +02:00
Jan Prochazka 10491868a0 v4.8.7 2022-04-22 20:27:58 +02:00
Jan Prochazka 8f945dc13f v4.8.7-beta.2 2022-04-21 19:08:57 +02:00
Jan Prochazka d041f88a47 dockerhost hint on GUI 2022-04-21 19:08:33 +02:00
Jan Prochazka e5bbf5eca3 dockerhost name support 2022-04-21 18:59:07 +02:00
Jan Prochazka 66da21804b cmd+backspace for delete rows on mac 2022-04-21 17:44:00 +02:00
Jan Prochazka 5315a549b0 import SQL dump fixed 2022-04-21 17:30:16 +02:00
Jan Prochazka 82304f13e7 Merge branch 'master' of github.com:dbgate/dbgate 2022-04-21 10:04:50 +02:00
Jan Prochazka 5bcd5d57ba fix 2022-04-21 10:04:47 +02:00
Jan Prochazka b6464dc119 Merge branch 'master' of github.com:dbgate/dbgate 2022-04-21 09:48:26 +02:00
Jan Prochazka 4182132dde mssql: fix (varchar(-1) => varchar(max)) 2022-04-21 09:48:21 +02:00
Jan Prochazka 32228d542a fixed crash #268 2022-04-21 08:41:53 +02:00
Jan Prochazka 72f5710dfd removed additional info from issue templates 2022-04-21 08:37:16 +02:00
Jan Prochazka 539c383b21 #270 2022-04-21 08:34:21 +02:00
Jan Prochazka c3289d09c0 fix system commands 2022-04-21 08:29:41 +02:00
Jan Prochazka 233fed30cb Merge pull request #269 from janpio/patch-1
fix(postgresql): Fix driver UI label "Postgre SQL" => "PostgreSQL"
2022-04-21 08:12:57 +02:00
Jan Piotrowski 63521002cc fix(postgresql): Fix driver UI label "Postgre SQL" => "PostgreSQL" 2022-04-19 17:00:55 +02:00
Jan Prochazka 21642e0a3e v4.8.7-beta.1 2022-04-18 20:00:50 +02:00
Jan Prochazka 4945b71c58 fix dependency 2022-04-18 20:00:11 +02:00
Jan Prochazka ed0d63d135 import sql dump 2022-04-18 19:59:19 +02:00
Jan Prochazka 2c25669bc7 shortcut fix 2022-04-18 19:37:56 +02:00
Jan Prochazka 0c94145b18 runner messages dialog 2022-04-18 19:27:37 +02:00
Jan Prochazka 95fb5d51c5 import SQL dump 2022-04-18 14:52:01 +02:00
Jan Prochazka a75e931fd5 import SQL dump POC 2022-04-18 14:22:16 +02:00
Jan Prochazka c7c667bbe0 Merge branch 'master' into develop 2022-04-18 11:10:12 +02:00
Jan Prochazka 97eff2b113 fix keybindings 2022-04-18 11:08:15 +02:00
Jan Prochazka 0122b0accc mac - fixed command+C, command+v 2022-04-18 10:42:50 +02:00
Jan Prochazka 6c718981d6 mysql dumper POC 2022-04-15 20:12:40 +02:00
Jan Prochazka f78d37159e v4.8.6 2022-04-14 17:34:55 +02:00
Jan Prochazka bf1881595c don't fail whole pipeline if one platforms fails 2022-04-14 17:19:03 +02:00
Jan Prochazka 4e8c92eb36 v4.8.5 2022-04-14 16:52:40 +02:00
Jan Prochazka 34a0cb095b build fix 2022-04-14 16:52:10 +02:00
Jan Prochazka f606d0c41c fix 2022-04-14 16:13:35 +02:00
Jan Prochazka 8002d734bc fix build script 2022-04-14 16:03:33 +02:00
Jan Prochazka be6d572ce2 changelog 2022-04-14 15:40:07 +02:00
Jan Prochazka c3baa88d9e v4.8.4 2022-04-14 15:26:47 +02:00
Jan Prochazka 5ef06abd1a v4.8.4-beta.8 2022-04-14 14:47:51 +02:00
Jan Prochazka e86a34ab53 apple notarize 2022-04-14 14:47:29 +02:00
Jan Prochazka c2b715e3f7 v4.8.4-beta.7 2022-04-14 13:49:12 +02:00
Jan Prochazka 666f1a3159 app build 2022-04-14 13:48:52 +02:00
Jan Prochazka 1ee66047d4 Merge branch 'develop' 2022-04-14 13:45:41 +02:00
Jan Prochazka 8032bf272b product name 2022-04-14 13:27:26 +02:00
Jan Prochazka d52cfadfc4 mac menu 2022-04-14 13:21:06 +02:00
Jan Prochazka 374c820567 invoke commands from menu on mac 2022-04-14 12:33:03 +02:00
Jan Prochazka cc639df566 handle ctrl & command key 2022-04-14 11:35:09 +02:00
Jan Prochazka 5a42e8e963 app exit - mac 2022-04-14 11:05:33 +02:00
Jan Prochazka 0187bb74ee v4.8.4-beta.6 2022-04-14 08:10:33 +02:00
Jan Prochazka bf4b7beadb mac universal build 2022-04-14 08:10:18 +02:00
Jan Prochazka b254c90f33 v4.8.4-beta.5 2022-04-14 08:08:30 +02:00
Jan Prochazka 89fdfbe8c1 arm build 2022-04-14 08:08:17 +02:00
Jan Prochazka a37c81be88 Merge pull request #267 from moalamri/master
Fixes misplaced tab close icon
2022-04-14 07:43:19 +02:00
M. Hassan abe9694d05 Fixes misplaced tab close icon
To fix #260
I think there's no need to change the close button to `close-button-right` since the `file-name` span would flex correctly same as `db-name`
2022-04-14 01:11:00 +03:00
Jan Prochazka c55c1f3aaf v4.8.4-beta.4 2022-04-12 22:35:24 +02:00
Jan Prochazka ce6b750a1c build only mac 2022-04-12 22:35:10 +02:00
Jan Prochazka f83d45356f v4.8.4-beta.3 2022-04-12 21:53:16 +02:00
Jan Prochazka 589ff1ad38 apple code signing 2022-04-12 21:52:56 +02:00
Jan Prochazka ba97f50273 Merge branch 'master' of github.com:dbgate/dbgate 2022-04-11 20:48:42 +02:00
Jan Prochazka e52fbd5034 keyboard fixes 2022-04-11 20:48:39 +02:00
Jan Prochazka e29d3a6143 v4.8.4-beta.2 2022-04-11 20:04:28 +02:00
Jan Prochazka 7313fa16f6 #264 fix 2022-04-11 20:03:56 +02:00
Jan Prochazka 18437d1be7 Revert "mac code signing"
This reverts commit 5135b985c9.
2022-04-10 19:24:40 +02:00
Jan Prochazka 2b39c85918 v4.8.4-beta.1 2022-04-10 18:26:54 +02:00
Jan Prochazka 5135b985c9 mac code signing 2022-04-10 18:26:15 +02:00
Jan Prochazka 05619faa7a fixed opening files on mac #206 #243 2022-04-10 10:57:31 +02:00
Jan Prochazka 12a638af3b custom window title works on mac 2022-04-10 09:41:55 +02:00
Jan Prochazka 38e05bf8e0 recent database switch in main menu 2022-04-10 08:33:13 +02:00
Jan Prochazka 6d92de6930 mac main menu 2022-04-10 08:30:39 +02:00
Jan Prochazka 90f8d349fc mac specific keyboard shortcuts #199 2022-04-09 20:00:26 +02:00
Jan Prochazka 5379e86d6e build fix 2022-04-09 09:30:01 +02:00
Jan Prochazka 85e449953f query splitter extracted into separate repository 2022-04-07 08:17:38 +02:00
Jan Prochazka 30e52723dd changelog 2022-04-05 22:15:06 +02:00
Jan Prochazka 467918bcbb v4.8.3 2022-04-05 22:09:15 +02:00
Jan Prochazka 73d17504c1 v4.8.3-beta.3 2022-04-04 21:09:11 +02:00
Jan Prochazka 7a3007deb2 clickable fk links in column manager 2022-04-04 21:08:43 +02:00
Jan Prochazka 2a46ff78bb fix 2022-04-04 20:53:39 +02:00
Jan Prochazka fa193f0e57 theme plugins info 2022-04-04 20:50:45 +02:00
Jan Prochazka f702513bb9 #244 2022-04-04 19:46:18 +02:00
Jan Prochazka 72462376b1 fix 2022-04-04 19:23:37 +02:00
Jan Prochazka a46ef7f0d0 v4.8.3-beta.2 2022-04-03 13:13:49 +02:00
Jan Prochazka 9f5013c6da handle plugin icon 2022-04-03 13:13:27 +02:00
Jan Prochazka 5ea6c56752 fixed theme selector 2022-04-03 11:21:38 +02:00
Jan Prochazka cbb38b8edc dataty pe in column manager and in form view 2022-04-03 10:35:29 +02:00
Jan Prochazka 045f6c6a47 SSH reconnect #253 2022-04-03 10:02:32 +02:00
Jan Prochazka 334ab504cf process api resp 2022-04-03 09:53:02 +02:00
Jan Prochazka 66db28010c api error handling 2022-04-03 09:50:24 +02:00
Jan Prochazka 807392fc57 fix 2022-04-03 09:41:19 +02:00
Jan Prochazka 1a32d88312 ssh forward moved to extra process #253 2022-04-03 09:40:46 +02:00
Jan Prochazka 1a76cc0979 v4.8.3-beta.1 2022-04-03 07:34:11 +02:00
Jan Prochazka bcdaf84739 api logging 2022-04-03 07:33:53 +02:00
Jan Prochazka 39296a852e #254 keyboard shortcuts in main menu 2022-03-31 16:03:38 +02:00
Jan Prochazka 1a035ca168 #254 tab navigation in datagrid 2022-03-31 16:01:06 +02:00
Jan Prochazka c0b365602b read json lines field values 2022-03-31 15:35:38 +02:00
Jan Prochazka 5aac142e4c fixed evaluated filters 2022-03-31 15:15:15 +02:00
Jan Prochazka 25380ee0a8 v4.8.2 2022-03-31 11:26:37 +02:00
Jan Prochazka 0b3b18ceda v4.8.2-beta.2 2022-03-31 10:37:11 +02:00
Jan Prochazka 9cecebe8bc redis key tab name & icon 2022-03-31 10:36:55 +02:00
Jan Prochazka c0227ecce1 changelog 2022-03-31 09:57:45 +02:00
Jan Prochazka 1d37950b37 v4.8.2-beta.1 2022-03-31 09:49:39 +02:00
Jan Prochazka fe277f5ffa redis search keys 2022-03-31 09:44:50 +02:00
Jan Prochazka 1b52a2a0fc v4.8.1 2022-03-29 22:00:05 +02:00
Jan Prochazka a062073a5f changelog 2022-03-29 21:56:51 +02:00
Jan Prochazka 44e52dfa9c v4.8.1-beta.1 2022-03-29 21:44:14 +02:00
Jan Prochazka 0323264bbd fixed crash 2022-03-29 21:43:50 +02:00
Jan Prochazka aacedba450 v4.8.0 2022-03-28 19:30:42 +02:00
Jan Prochazka aac768b158 changelog 2022-03-28 19:11:22 +02:00
Jan Prochazka d4a7ae13e1 v4.8.0-beta.1 2022-03-28 19:06:20 +02:00
Jan Prochazka b8206a7a02 open dev tools on crash, when not reloading 2022-03-28 19:05:15 +02:00
Jan Prochazka 4c2f6c9b65 upload ndjson to web app 2022-03-28 18:58:02 +02:00
Jan Prochazka d58d46feac v4.7.5-beta.1 2022-03-27 20:37:35 +02:00
Jan Prochazka 760edc7eca redis - removed experimental status 2022-03-27 20:37:17 +02:00
Jan Prochazka 7c0f33383f ndjson direct support 2022-03-27 20:35:30 +02:00
Jan Prochazka a20a34680d redis: hide write operations when connection is readonly 2022-03-27 18:39:42 +02:00
Jan Prochazka 0e8166577f redis: support readonly and database url 2022-03-27 18:34:22 +02:00
Jan Prochazka 11c82b1aac redis json view 2022-03-27 17:45:05 +02:00
Jan Prochazka 61f24c3408 json view in redis 2022-03-27 17:34:02 +02:00
Jan Prochazka e25657bd43 redis: support for redis streams 2022-03-27 17:16:17 +02:00
Jan Prochazka 4bd7cd26d0 redis db context menu 2022-03-27 13:42:08 +02:00
Jan Prochazka e06894372f redis: rename key command 2022-03-27 13:06:39 +02:00
Jan Prochazka 1f0ae98c88 redis export keys 2022-03-27 12:57:44 +02:00
Jan Prochazka c0fdcf2fd1 redis: execute commands 2022-03-26 10:36:44 +01:00
Jan Prochazka 8d31130737 redis query splitter 2022-03-26 09:56:28 +01:00
Jan Prochazka 9e3991556a delete branch operation 2022-03-26 08:12:56 +01:00
Jan Prochazka fc08353225 changelog 2022-03-25 18:38:51 +01:00
Jan Prochazka 25556f0d3e changelog 2022-03-25 18:35:56 +01:00
Jan Prochazka 0fb3817af6 v4.7.4 2022-03-25 18:23:08 +01:00
Jan Prochazka d8e840f127 v4.7.4-beta.17 2022-03-24 18:59:35 +01:00
Jan Prochazka 4270722557 v4.7.4-alpha.16 2022-03-24 18:59:15 +01:00
Jan Prochazka b3cfff0ae8 redis marked as experimental 2022-03-24 18:58:57 +01:00
Jan Prochazka 2f5f0ab54c Revert "don't include redis in output bundle"
This reverts commit 074a75075d.
2022-03-24 18:52:34 +01:00
Jan Prochazka 4c856c5e36 refresh after delete 2022-03-24 18:51:46 +01:00
Jan Prochazka 5c8ae85c54 redis: refresh after create key 2022-03-24 18:49:45 +01:00
Jan Prochazka 5b39576e61 redis: add key modal style 2022-03-24 18:41:39 +01:00
Jan Prochazka 735c48902f redis: reload keys 2022-03-24 18:32:17 +01:00
Jan Prochazka 613ac3f0e5 redis: delete key 2022-03-24 18:24:10 +01:00
Jan Prochazka 1aecda6d9f add new key works 2022-03-24 17:58:54 +01:00
Jan Prochazka 38dfad4dfc #246 omit sngle-database dbs in ctrl+p seach 2022-03-24 16:25:36 +01:00
Jan Prochazka 25ae5bf048 fuzzy search #246 2022-03-24 15:48:21 +01:00
Jan Prochazka f3bfe58c58 dbgate-serve package refs 2022-03-24 14:09:34 +01:00
Jan Prochazka ff714b1f8a v4.7.4-alpha.15 2022-03-24 14:02:15 +01:00
Jan Prochazka 93552585f7 fixes 2022-03-24 14:02:02 +01:00
Jan Prochazka ec7641dbd6 v4.7.4-alpha.14 2022-03-24 09:55:57 +01:00
Jan Prochazka e2308f501b renamed package dbgate to dbgate-serve 2022-03-24 09:55:39 +01:00
Jan Prochazka 45277e34c9 try to fix npm build 2022-03-24 09:49:14 +01:00
Jan Prochazka ba77b32e9a v4.7.4-beta.13 2022-03-24 09:14:04 +01:00
Jan Prochazka c05ef42bf9 v4.7.4-alpha.12 2022-03-24 09:13:49 +01:00
Jan Prochazka b0e0197346 fixed docker container 2022-03-24 09:13:33 +01:00
Jan Prochazka 4c411b048d fixed npm dist subprocess problem 2022-03-24 09:00:51 +01:00
Jan Prochazka a3bc1e577a v4.7.4-beta.11 2022-03-21 20:55:22 +01:00
Jan Prochazka ef533671a2 v4.7.4-alpha.10 2022-03-21 20:55:06 +01:00
Jan Prochazka 77612cc6fb logout functionality 2022-03-21 20:54:40 +01:00
Jan Prochazka 26881a3e39 better permission compiler 2022-03-21 20:37:04 +01:00
Jan Prochazka a1b7ad18af multi user auth 2022-03-21 20:21:07 +01:00
Jan Prochazka 487d4afd70 v4.7.4-beta.9 2022-03-20 13:45:34 +01:00
Jan Prochazka 39f7508136 v4.7.4-alpha.8 2022-03-20 13:34:53 +01:00
Jan Prochazka 153bc6ddde permissions refactor 2022-03-20 13:34:38 +01:00
Jan Prochazka 73d4c43571 v4.7.4-alpha.7 2022-03-20 13:30:35 +01:00
Jan Prochazka a73168b7e1 query tab - ability to stop loading 2022-03-20 12:14:36 +01:00
Jan Prochazka f10f863940 query data refresh 2022-03-20 11:47:28 +01:00
Jan Prochazka 5df0204450 mask portal connetions - FE needs no passwords 2022-03-20 11:33:44 +01:00
Jan Prochazka 2bec053809 disallow shell scripting in web by default 2022-03-20 11:17:49 +01:00
Jan Prochazka 6fb582249c correct export from read-only connection 2022-03-20 09:47:39 +01:00
Jan Prochazka 1a81952ce7 fix 2022-03-20 08:48:48 +01:00
Jan Prochazka 04f25c4535 typo 2022-03-20 08:43:31 +01:00
Jan Prochazka 8824262395 safe read-only when using shell scripts 2022-03-19 10:09:27 +01:00
Jan Prochazka ff661ec89b v4.7.4-beta.6 2022-03-17 20:40:40 +01:00
Jan Prochazka 0221c30716 build on win 2022 2022-03-17 20:40:34 +01:00
Jan Prochazka 913896d8bc v4.7.4-beta.5 2022-03-17 20:36:51 +01:00
Jan Prochazka 9b449527fd build on windows-2021 2022-03-17 20:36:41 +01:00
Jan Prochazka 6dff481dbf v4.7.4-beta.4 2022-03-17 20:34:26 +01:00
Jan Prochazka 649626975c v4.7.4-alpha.3 2022-03-17 20:20:22 +01:00
Jan Prochazka c135a068a2 dbconfig support in env variables 2022-03-17 20:19:53 +01:00
Jan Prochazka 728a2c6a9f v4.7.4-alpha.2 2022-03-17 19:54:08 +01:00
Jan Prochazka 6e041e9eed isGeneratedScript TODO 2022-03-17 19:53:51 +01:00
Jan Prochazka 6c8eccd369 v4.7.4-alpha.1 2022-03-17 19:47:21 +01:00
Jan Prochazka bf1a89ee21 ad hoc permissions (TODO improve) 2022-03-17 19:46:09 +01:00
Jan Prochazka d888feeaf8 support app queries 2022-03-17 19:32:56 +01:00
Jan Prochazka e181318e24 readonly support in portal connections 2022-03-17 13:52:32 +01:00
Jan Prochazka a9038984d8 mssql readonly (emulated, not supported natively) 2022-03-17 13:48:54 +01:00
Jan Prochazka 4acce560ad sqlite supports readonly 2022-03-17 13:33:38 +01:00
Jan Prochazka 29591a613a postgres - readonly connection 2022-03-17 13:27:33 +01:00
Jan Prochazka 8f1d76fd2a readonly sessions on mongo (+checks on BE) 2022-03-17 13:17:30 +01:00
Jan Prochazka 7d196c7c62 build fix 2022-03-17 12:45:02 +01:00
Jan Prochazka 267e687e2b handle readonly connection in UI 2022-03-17 12:37:17 +01:00
Jan Prochazka 34658e134f readonly support for mysql 2022-03-17 11:26:38 +01:00
Jan Prochazka 4efcef192a fix dependency 2022-03-17 10:34:30 +01:00
Jan Prochazka 9c7a130ee4 using sql-select instead of query-data 2022-03-17 10:32:57 +01:00
Jan Prochazka 0d7bfd5f90 mongo distinct field values 2022-03-17 10:00:11 +01:00
Jan Prochazka 5c4794deae load field values logic moved to backend 2022-03-17 08:40:09 +01:00
Jan Prochazka 074a75075d don't include redis in output bundle 2022-03-16 18:44:10 +01:00
Jan Prochazka 4ce2ed06e1 Merge branch 'redis' 2022-03-16 18:41:17 +01:00
Jan Prochazka 61c5ac6a47 mongo filtersing fixes 2022-03-16 18:34:44 +01:00
Jan Prochazka 4a0bd14dfe v4.7.3 2022-03-14 20:09:42 +01:00
Jan Prochazka 85bdbd503b v4.7.3-beta.8 2022-03-14 19:49:48 +01:00
Jan Prochazka aec9c796b2 back to windows-2016 2022-03-14 19:49:35 +01:00
Jan Prochazka 6c317b0cf7 v4.7.3-beta.7 2022-03-14 19:46:03 +01:00
Jan Prochazka 170f213024 build on windows-2021 2022-03-14 19:45:52 +01:00
Jan Prochazka 050c15994b changelog 2022-03-14 19:45:01 +01:00
Jan Prochazka 5e73c75bb5 v4.7.3-beta.6 2022-03-14 19:39:07 +01:00
Jan Prochazka 09bb8f0874 v4.7.3-alpha.5 2022-03-14 19:28:30 +01:00
Jan Prochazka 651dd09b15 fix 2022-03-14 19:27:59 +01:00
Jan Prochazka 900fdc56f4 export fix 2022-03-14 19:19:16 +01:00
Jan Prochazka 5bda092a51 add db key modal 2022-03-13 22:30:45 +01:00
Jan Prochazka dc34898cd8 redis: add item to key 2022-03-13 20:04:52 +01:00
Jan Prochazka 6590830344 Merge branch 'master' into redis 2022-03-13 17:33:35 +01:00
Jan Prochazka cf734a26ee v4.7.3-beta.4 2022-03-13 17:33:19 +01:00
Jan Prochazka 32c06fdf4d test config refactor 2022-03-13 17:32:26 +01:00
Jan Prochazka cbe0ea7c9b v4.7.3-alpha.3 2022-03-13 17:14:32 +01:00
Jan Prochazka b6cc77c7fe dotenv config in dbgate-serve 2022-03-13 17:14:04 +01:00
Jan Prochazka 25015f35d5 dbgate-serve fix 2022-03-13 17:05:50 +01:00
Jan Prochazka ae719157c0 v4.7.3-alpha.2 2022-03-13 16:50:45 +01:00
Jan Prochazka 772a72dfd8 dbgate.js => dbgate-serve.js 2022-03-13 16:49:33 +01:00
Jan Prochazka 3ccb00854c quick export from free table editor 2022-03-13 16:47:20 +01:00
Jan Prochazka cf047cb7b5 quick export respect shown columns 2022-03-13 14:44:33 +01:00
Jan Prochazka 84725f0586 export preserves column settings 2022-03-13 14:33:21 +01:00
Jan Prochazka 34dae68a62 export/import column map support 2022-03-13 14:02:09 +01:00
Jan Prochazka 750a37a27f grid columns display fix 2022-03-13 11:35:04 +01:00
Jan Prochazka cd7864b889 column manager fix 2022-03-13 10:56:01 +01:00
Jan Prochazka 7efd4be401 faxed db group close buttpm style 2022-03-12 21:12:20 +01:00
Jan Prochazka 0629123cc1 apps improvements 2022-03-12 20:45:12 +01:00
Jan Prochazka 6138cfc2da redis add item prepare 2022-03-10 17:54:57 +01:00
Jan Prochazka 730fd38b9e redis: dont show all keys in tree (show more...) 2022-03-10 17:21:04 +01:00
Jan Prochazka 3d72df424f redis: set ttl 2022-03-10 17:12:21 +01:00
Jan Prochazka 98a9859216 Merge branch 'master' into redis 2022-03-10 11:22:39 +01:00
Jan Prochazka 0b6042c3cb v4.7.3-beta.1 2022-03-10 11:16:39 +01:00
Jan Prochazka 35792a024a export menu refactor 2022-03-10 11:13:25 +01:00
Jan Prochazka ddff3d2b89 quick export on web 2022-03-10 10:23:33 +01:00
Jan Prochazka c26bc6d0e9 xml export fix 2022-03-10 10:23:18 +01:00
Jan Prochazka 8c3708fc8c quick export from web 2022-03-10 10:15:05 +01:00
Jan Prochazka 008a09cc81 exportElectronFile => exportFileTools 2022-03-10 09:47:28 +01:00
Jan Prochazka 7497e2684c fixed quick export handler from mongo 2022-03-10 09:34:05 +01:00
Jan Prochazka c4b0b185e6 find by schema name in db widget 2022-03-10 09:24:19 +01:00
Jan Prochazka 8b91c69f5f vfk editor fix (svelte bug) 2022-03-10 09:17:03 +01:00
Jan Prochazka f57624ef24 tabs panel style fix 2022-03-10 08:49:09 +01:00
Jan Prochazka 64c8d4bdca vfk editor - auto select PK 2022-03-10 08:48:52 +01:00
Jan Prochazka 9b396e7431 redis key browser works 2022-03-07 20:55:29 +01:00
Jan Prochazka 78faa94d77 Merge branch 'master' into redis 2022-03-07 18:35:38 +01:00
Jan Prochazka 7953186e03 changelog 2022-03-07 18:34:56 +01:00
Jan Prochazka ccfbe2cccb key detail tab, API 2022-03-06 20:59:01 +01:00
Jan Prochazka 74ad345ba5 redis key sizes 2022-03-05 21:38:36 +01:00
Jan Prochazka 750e929d1e show redis keys icons 2022-03-05 20:51:59 +01:00
Jan Prochazka 5eba93559d redis key tree 2022-03-05 18:58:13 +01:00
Jan Prochazka 51942be0a6 loading redis keys 2022-03-05 18:46:18 +01:00
Jan Prochazka 425841bb38 removed logging 2022-03-05 12:30:29 +01:00
Jan Prochazka 2202ae5aab Merge branch 'master' into redis 2022-03-05 12:29:04 +01:00
Jan Prochazka e8d24e177b fix in cache loader 2022-03-05 12:21:05 +01:00
Jan Prochazka d7a2bf3ac0 refactor:dialect.nosql=>driver.databaseEngineTypes 2022-03-05 12:12:02 +01:00
Jan Prochazka 8692283cb8 redis connection 2022-03-05 11:14:07 +01:00
478 changed files with 25802 additions and 8436 deletions
-6
View File
@@ -28,9 +28,3 @@ If applicable, add screenshots to help explain your problem.
- Install source [e.g. installer/SNAP/Docker/NPM]
- Type - Web/Application
- Database engine: [e.g. MySQL/PostgreSQL/SQL Server]
**Additional info**
You could provide additional context, to better understand your case.
- How looks your typical DbGate usage?
- What other DB software do you use?
- Anything else you think might be helpful
@@ -15,9 +15,3 @@ A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional info**
You could provide additional context, to better understand your case.
- How looks your typical DbGate usage?
- What other DB software do you use?
- Anything else you think might be helpful
-6
View File
@@ -16,9 +16,3 @@ App Version [help -> about]:
**Screenshot [if appropriate]**:
A screenshot of the app if that helps
**Additional info**
You could provide additional context, to better understand your case.
- How looks your typical DbGate usage?
- What other DB software do you use?
- Anything else you think might be helpful
+17 -4
View File
@@ -10,9 +10,10 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# os: [ubuntu-18.04, windows-2016]
os: [macOS-10.15, windows-2019, ubuntu-18.04]
os: [macOS-10.15, windows-2022, ubuntu-18.04]
# os: [macOS-10.15]
steps:
- name: Context
@@ -26,6 +27,9 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: 14.x
- name: yarn adjustPackageJson
run: |
yarn adjustPackageJson
- name: yarn install
run: |
yarn install
@@ -46,8 +50,17 @@ jobs:
yarn run build:app
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }} # token for electron publish
WIN_CSC_LINK: ${{ secrets.WINCERT_CERTIFICATE }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_PASSWORD }}
WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }}
# WIN_CSC_LINK: ${{ secrets.WINCERT_CERTIFICATE }}
# WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_PASSWORD }}
CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
- name: Save snap login
if: matrix.os == 'ubuntu-18.04'
+19 -6
View File
@@ -14,9 +14,10 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# os: [ubuntu-18.04, windows-2016]
os: [macOS-10.15, windows-2019, ubuntu-18.04]
os: [macOS-10.15, windows-2022, ubuntu-18.04]
steps:
- name: Context
@@ -30,6 +31,9 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: 14.x
- name: yarn adjustPackageJson
run: |
yarn adjustPackageJson
- name: yarn install
run: |
# yarn --version
@@ -52,8 +56,17 @@ jobs:
yarn run build:app
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }} # token for electron publish
WIN_CSC_LINK: ${{ secrets.WINCERT_CERTIFICATE }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_PASSWORD }}
WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }}
# WIN_CSC_LINK: ${{ secrets.WINCERT_CERTIFICATE }}
# WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_PASSWORD }}
CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
- name: generatePadFile
run: |
@@ -83,8 +96,8 @@ jobs:
cp app/dist/*.exe artifacts/dbgate-latest.exe || true
cp app/dist/*win_x64.zip artifacts/dbgate-windows-latest.zip || true
cp app/dist/*win_arm64.zip artifacts/dbgate-windows-latest-arm64.zip || true
cp app/dist/*-mac_x64.dmg artifacts/dbgate-latest.dmg || true
cp app/dist/*-mac_arm64.dmg artifacts/dbgate-latest-arm64.dmg || true
cp app/dist/*-mac_universal.dmg artifacts/dbgate-latest.dmg || true
cp app/dist/*-mac_x64.dmg artifacts/dbgate-latest-x64.dmg || true
mv app/dist/*.exe artifacts/ || true
mv app/dist/*.zip artifacts/ || true
@@ -118,7 +131,7 @@ jobs:
# mv app/dist/latest.yml artifacts/latest.yml || true
- name: Copy latest.yml (windows)
if: matrix.os == 'windows-2019'
if: matrix.os == 'windows-2022'
run: |
mv app/dist/latest.yml artifacts/latest.yml || true
mv app/dist/dbgate-pad.xml artifacts/ || true
-58
View File
@@ -1,58 +0,0 @@
name: Docker image BETA
# on: [push]
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-docker.[0-9]+'
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04]
steps:
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 14.x
uses: actions/setup-node@v1
with:
node-version: 14.x
- name: yarn install
run: |
# yarn --version
# yarn config set network-timeout 300000
yarn install
- name: setCurrentVersion
run: |
yarn setCurrentVersion
- name: Prepare docker image
run: |
yarn run prepare:docker
- name: Build docker image
run: |
docker build ./docker -t dbgate
- name: Push docker image
run: |
docker tag dbgate dbgate/dbgate:beta
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker push dbgate/dbgate:beta
- name: Build alpine docker image
run: |
docker build ./docker -t dbgate -f docker/Dockerfile-alpine
- name: Push alpine docker image
run: |
docker tag dbgate dbgate/dbgate:beta-alpine
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker push dbgate/dbgate:beta-alpine
+58 -24
View File
@@ -1,17 +1,11 @@
name: Docker image
# on: [push]
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
# - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
# on:
# push:
# branches:
# - production
- 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-docker.[0-9]+'
jobs:
build:
@@ -30,12 +24,43 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
dbgate/dbgate
flavor: |
latest=false
tags: |
type=raw,value=beta,enable=${{ contains(github.ref_name, '-docker.') || contains(github.ref_name, '-beta.') }}
type=match,pattern=\d+.\d+.\d+,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
type=raw,value=latest,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
- name: Docker alpine meta
id: alpmeta
uses: docker/metadata-action@v4
with:
images: |
dbgate/dbgate
flavor: |
latest=false
tags: |
type=raw,value=beta-alpine,enable=${{ contains(github.ref_name, '-docker.') || contains(github.ref_name, '-beta.') }}
type=match,pattern=\d+.\d+.\d+,suffix=-alpine,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
type=raw,value=alpine,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
- name: Use Node.js 14.x
uses: actions/setup-node@v1
with:
node-version: 14.x
- name: yarn install
run: |
# yarn --version
# yarn config set network-timeout 300000
yarn install
- name: setCurrentVersion
run: |
@@ -43,19 +68,28 @@ jobs:
- name: Prepare docker image
run: |
yarn run prepare:docker
- name: Build docker image
run: |
docker build ./docker -t dbgate
- name: Push docker image
run: |
docker tag dbgate dbgate/dbgate
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker push dbgate/dbgate
- name: Build alpine docker image
run: |
docker build ./docker -t dbgate -f docker/Dockerfile-alpine
- name: Push alpine docker image
run: |
docker tag dbgate dbgate/dbgate:alpine
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker push dbgate/dbgate:alpine
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v3
with:
push: true
context: ./docker
tags: ${{ steps.meta.outputs.tags }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
- name: Build and push alpine
uses: docker/build-push-action@v3
with:
push: true
context: ./docker
file: ./docker/Dockerfile-alpine
tags: ${{ steps.alpmeta.outputs.tags }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
+12 -7
View File
@@ -79,21 +79,21 @@ jobs:
run: |
npm publish
- name: Publish query-splitter
working-directory: packages/query-splitter
run: |
npm publish
- name: Publish web
working-directory: packages/web
run: |
npm publish
- name: Publish dbgate
- name: Publish dbgate (obsolete)
working-directory: packages/dbgate
run: |
npm publish
- name: Publish dbgate-serve
working-directory: packages/serve
run: |
npm publish
- name: Publish dbgate-plugin-csv
working-directory: plugins/dbgate-plugin-csv
run: |
@@ -133,3 +133,8 @@ jobs:
working-directory: plugins/dbgate-plugin-sqlite
run: |
npm publish
- name: Publish dbgate-plugin-redis
working-directory: plugins/dbgate-plugin-redis
run: |
npm publish
+4 -4
View File
@@ -31,10 +31,10 @@ jobs:
run: |
cd packages/filterparser
yarn test:ci
- name: Query spliiter tests
- name: Datalib (perspective) tests
if: always()
run: |
cd packages/query-splitter
cd packages/datalib
yarn test:ci
- uses: tanmen/jest-reporter@v1
if: always()
@@ -52,8 +52,8 @@ jobs:
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-file: packages/query-splitter/result.json
action-name: Query splitter test results
result-file: packages/datalib/result.json
action-name: Datalib (perspectives) test results
services:
postgres:
+1
View File
@@ -0,0 +1 @@
16.14.2
+20
View File
@@ -0,0 +1,20 @@
{
"terminals": [
{
"splitTerminals": [
{
"name": "lib",
"commands": ["yarn lib"]
},
{
"name": "web",
"commands": ["yarn start:web"]
},
{
"name": "api",
"commands": ["yarn start:api"]
}
]
}
]
}
+4 -1
View File
@@ -1,3 +1,6 @@
{
"jestrunner.jestCommand": "node_modules/.bin/cross-env DEVMODE=1 LOCALTEST=1 node_modules/.bin/jest"
"jestrunner.jestCommand": "node_modules/.bin/cross-env DEVMODE=1 LOCALTEST=1 node_modules/.bin/jest",
"cSpell.words": [
"dbgate"
]
}
+222
View File
@@ -1,5 +1,227 @@
# ChangeLog
Builds:
- docker - build
- npm - npm package dbgate-serve
- app - classic electron app
- mac - application for macOS
- linux - application for linux
- win - application for Windows
### 5.1.5
- ADDED: Support perspectives for MongoDB - MongoDB query designer
- ADDED: Show JSON content directly in the overview #395
- CHANGED: OSX Command H shortcut for hiding window #390
- ADDED: Uppercase Autocomplete Suggestions #389
- FIXED: Record view left/right arrows cause start record number to be treated as string #388
- FIXED: MongoDb ObjectId behaviour not consistent in nested objects #387
- FIXED: demo.dbgate.org - beta version crash 5.1.5-beta.3 #386
- ADDED: connect via socket - configurable via environment variables #358
### 5.1.4
- ADDED: Drop database commands #384
- ADDED: Customizable Redis key separator #379
- ADDED: ARM support for docker images
- ADDED: Version tags for docker images
- ADDED: Better SQL command splitting and highlighting
- ADDED: Unsaved marker for SQL files
### 5.1.3
- ADDED: Editing multiline cell values #378 #371 #359
- ADDED: Truncate table #333
- ADDED: Perspectives - show row count
- ADDED: Query - error markers in gutter area
- ADDED: Query - ability to execute query elements from gutter
- FIXED: Correct error line numbers returned from queries
### 5.1.2
- FIXED: MongoDb any export function does not work. #373
- ADDED: Query Designer short order more flexibility #372
- ADDED: Form View move between records #370
- ADDED: Custom SQL conditions in query designer and table filtering #369
- ADDED: Query Designer filter eq to X or IS NULL #368
- FIXED: Query designer, open a saved query lost sort order #363
- ADDED: Query designer reorder columns #362
- ADDED: connect via socket #358
- FIXED: Show affected rows after UPDATE/DELETE/INSERT #361
- ADDED: Perspective cell formatters - JSON, image
- ADDED: Perspectives - cells without joined data are gray
### 5.1.1
- ADDED: Perspective designer
- FIXED: NULL,NOT NULL filter datatime columns #356
- FIXED: Recognize computed columns on SQL server #354
- ADDED: Hotkey for clear filter #352
- FIXED: Change column type on Postgres #350
- ADDED: Ability to open qdesign file #349
- ADDED: Custom editor font size #345
- ADDED: Ability to open perspective files
### 5.1.0
- ADDED: Perspectives (docs: https://dbgate.org/docs/perspectives.html )
- CHANGED: Upgraded SQLite engine version (driver better-sqlite3: 7.6.2)
- CHANGED: Upgraded ElectronJS version (from version 13 to version 17)
- CHANGED: Upgraded all dependencies with current available minor version updates
- CHANGED: By default, connect on click #332˝
- CHANGED: Improved keyboard navigation, when editing table data #331
- ADDED: Option to skip Save changes dialog #329
- FIXED: Unsigned column doesn't work correctly. #324
- FIXED: Connect to MS SQL with domain user now works also under Linux and Mac #305
### 5.0.9
- FIXED: Fixed problem with SSE events on web version
- ADDED: Added menu command "New query designer"
- ADDED: Added menu command "New ER diagram"
### 5.0.8
- ADDED: SQL Server - support using domain logins under Linux and Mac #305
- ADDED: Permissions for connections #318
- ADDED: Ability to change editor front #308
- ADDED: Custom expression in query designer #306
- ADDED: OR conditions in query designer #321
- ADDED: Ability to configure settings view environment variables #304
### 5.0.7
- FIXED: Fixed some problems with SSH tunnel (upgraded SSH client) #315
- FIXED: Fixed MognoDB executing find query #312
- ADDED: Interval filters for date/time columns #311
- ADDED: Ability to clone rows #309
- ADDED: connecting option Trust server certificate for SQL Server #305
- ADDED: Autorefresh, reload table every x second #303
- FIXED(app): Changing editor theme and font size in Editor Themes #300
### 5.0.6
- ADDED: Search in columns
- CHANGED: Upgraded mongodb driver
- ADDED: Ability to reset view, when data load fails
- FIXED: Filtering works for complex types (geography, xml under MSSQL)
- FIXED: Fixed some NPM package problems
### 5.0.5
- ADDED: Visualisation geographics objects on map #288
- ADDED: Support for native SQL as default value inside yaml files #296
- FIXED: Postgres boolean columns don't filter correctly #298
- FIXED: Importing dbgate-api as NPM package now works correctly
- FIXED: Handle error when reading deleted archive
### 5.0.3
- CHANGED: Optimalization of loading DB structure for PostgreSQL, MySQL #273
- CHANGED: Upgraded mysql driver #293
- CHANGED: Better UX when defining SSH port #291
- ADDED: Database object menu from tab
- CHANGED: Ability to close file uploader
- FIXED: Correct handling of NUL values in update keys
- CHANGED: Upgraded MS SQL tedious driver
- ADDED: Change order of pinned tables & databases #227
- FIXED: #294 Statusbar doesn't match active tab
- CHANGED: Improved connection worklflow, disconnecting shws confirmations, when it leads to close any tabs
- ADDED: Configurable object actions #255
- ADDED: Multiple sort criteria #235
- ADDED(app): Open JSON file
### 5.0.2
- FIXED: Cannot use SSH Tunnel after update #291
### 5.0.1
- FIXED(app): Can't Click Sidebar Menu Item #287
### 5.0.0
- CHANGED: Connection workflow, connections are opened on tabs instead of modals
- ADDED: Posibility to connect to DB without saving connection
- ADDED(mac): Support for SQLite on Mac M1
- FIXED(mac): Unable to drag window on MacOS #281 #283
- CHANGED: Renamed dbgate-data directory to .dbgate #248
- FIXED: Exported SQL has table name undefined #277
- ADDED: More data types in table create dialogt #285
- ADDED(app): Open previously saved ERD diagrams #278
- CHANGED: Better app loading progress UX
- FIXED: Removed SSL tab on Redis connection (SSL is not supported for Redis)
### 4.8.8
- CHANGED: New app icon
- ADDED: SQL dump, SQL import - also from/to saved queries
- FIXED(mac): Fixed crash when reopening main window
- FIXED: MySQL dump now handles correctly dependand views
- FIXED(app): Browse tabs with Ctrl+Tab
- ADDED(app): Browse tabs in reverse order with Ctrl+Shift+Tab #245
### 4.8.7
- ADDED: MySQL dump/backup database
- ADDED: Import SQL dump from file or from URL
- FIXED(mac): Fixed Cmd+C, Cmd+V, Cmd+X - shortcuts for copy/cut/paste #270
- FIXED(mac): Some minor issues on macOS
- FIXED: Analysing MS SQL nvarchar(max)
- ADDED: Support for dockerhost network name under docker #271
### 4.8.4
- FIXED(mac): Fixed build for macOS arm64 #259
- FIXED(mac): Fixed opening SQLite files on macOS #243
- FIXED(mac): Fixed opening PEM certificates on macOS #206
- FIXED(mac): Fixed handling Command key on macOS
- FIXED(mac): Fixed system menu on macOS
- FIXED(mac): Fixed reopening main window on macOS
- CHANGED: Shortcut for net query is now Ctrl+T or Command+T on macOS, former it was Ctrl+Q
- FIXED: Fixed misplaced tab close icon #260
- ADDED: Added menu command "Tools/Change to recent database"
### 4.8.3
- FIXED: filters in query result and NDJSON/archive viewer
- ADDED: Added select values from query result and NDJSON/archive viewer
- ADDED: tab navigation in datagrid #254
- ADDED: Keyboard shortcuts added to help menu #254
- ADDED: API logging (run enableApiLog() in developers console to enable logging)
- ADDED: SSH reconnect + moved SSH forward into separate fork #253
- ADDED: Data type + reference link in column manager
- FIXED(win,linux,mac): Unable to change theme after installing plugin #244
### 4.8.2
- ADDED: implemented missing redis search key logic
### 4.8.1
- FIXED: fixed crash after disconnecting from all DBs
### 4.8.0
- ADDED: Redis support (support stream type), removed experimental status
- ADDED: Redis readonly support
- ADDED: Explicit NDJSON support, when opening NDJSON/JSON lines file, table data are immediately shown, without neccesarity to import
- ADDED(win,linux,mac): Opening developer tools when crashing without reload app
### 4.7.4
- ADDED: Experimental Redis support (full support is planned to version 4.8.0)
- ADDED: Read-only connections
- FIXED: MongoDB filters
- ADDED: MongoDB column value selection
- ADDED: App related queries
- ADDED: Fuzzy search #246
- ADDED(docker, npm): New permissions
- FIXED(npm): NPM build no longer allocates additonal ports
- CHANGED(npm): renamed NPM package dbgate => dbgate-serve
- CHANGED(docker): custom JavaScripts and connections defined in scripts are now prohibited by default, use SHELL_CONNECTION and SHELL_SCRIPTING environment variables for allowing this
- ADDED(docker, npm): Better documentation of environment variables configuration, https://dbgate.org/docs/env-variables.html
- ADDED(docker): support for multiple users with different permissions
- ADDED(docker): logout operation
### 4.7.3
- CHANGED: Export menu redesign, quick export menu merged with old export menu
- REMOVED: Quick export menu
- ADDED: Export column mapping
- ADDED: Export invoked from data grid respects columns choosed in column manager
- ADDED: Quick export (now merged in export menu) is now possible also in web app
- FIXED: Virtual foreign key editor fixes
- FIXED: Tabs panel style fix
- ADDED: Find by schema in databases widget
- FIXED: Column manager selection fix
- FIXED: NPM dist - fixed error when loading plugins
- CHANGED: NPN dist is now executed by dbgate-serve command
- ADDED: NPM dist accepts .env configuration
### 4.7.2
- CHANGED: documentation URL - https://dbgate.org/docs/
- CHANGED: Close button available for all tab groups - #238
- ADDED: Search function for the Keyboard Shortcuts overview - #239
- ADDED: Editor font size settings - #229
- ADDED: Rename MongoDB collection - #223
- FIXED: bug in cache subsystem
### 4.7.1
- FIXED: Fixed connecting to MS SQL server running in docker container from DbGate running in docker container #236
- FIXED: Fixed export MongoDB collections into Excel and CSV #240
+14 -10
View File
@@ -1,4 +1,4 @@
[![NPM version](https://img.shields.io/npm/v/dbgate.svg)](https://www.npmjs.com/package/dbgate)
[![NPM version](https://img.shields.io/npm/v/dbgate-serve.svg)](https://www.npmjs.com/package/dbgate-serve)
![GitHub All Releases](https://img.shields.io/github/downloads/dbgate/dbgate/total)
[![dbgate](https://snapcraft.io/dbgate/badge.svg)](https://snapcraft.io/dbgate)
[![dbgate](https://snapcraft.io/dbgate/trending.svg?name=0)](https://snapcraft.io/dbgate)
@@ -16,13 +16,14 @@ DbGate is licensed under MIT license and is completely free.
* Try it online - [demo.dbgate.org](https://demo.dbgate.org) - online demo application
* **Download** application for Windows, Linux or Mac from [dbgate.org](https://dbgate.org/download/)
* Run web version as [NPM package](https://www.npmjs.com/package/dbgate) or as [docker image](https://hub.docker.com/r/dbgate/dbgate)
* Run web version as [NPM package](https://www.npmjs.com/package/dbgate-serve) or as [docker image](https://hub.docker.com/r/dbgate/dbgate)
## Supported databases
* MySQL
* PostgreSQL
* SQL Server
* MongoDB
* Redis
* SQLite
* Amazon Redshift
* CockroachDB
@@ -63,6 +64,7 @@ DbGate is licensed under MIT license and is completely free.
* SQL code completion
* Add SQL LEFT/INNER/RIGHT join utility
* Mongo JavaScript editor, execute Mongo script (with NodeJs syntax)
* Redis tree view, generate script from keys, run Redis script
* Runs as application for Windows, Linux and Mac. Or in Docker container on server and in web Browser on client.
* Import, export from/to CSV, Excel, JSON, XML
* Free table editor - quick table data editing (cleanup data after import/before export, prototype tables etc.)
@@ -70,6 +72,7 @@ DbGate is licensed under MIT license and is completely free.
* Charts, export chart to HTML page
* For detailed info, how to run DbGate in docker container, visit [docker hub](https://hub.docker.com/r/dbgate/dbgate)
* Extensible plugin architecture
* Perspectives - nested table view over complex relational data
## How to contribute
Any contributions are welcome. If you want to contribute without coding, consider following:
@@ -77,7 +80,8 @@ Any contributions are welcome. If you want to contribute without coding, conside
* Tell your friends about DbGate or share on social networks - when more people will use DbGate, it will grow to be better
* Write review on [Slant.co](https://www.slant.co/improve/options/41086/~dbgate-review) or [G2](https://www.g2.com/products/dbgate/reviews)
* Create issue, if you find problem in app, or you have idea to new feature. If issue already exists, you could leave comment on it, to prioritise most wanted issues.
* Become a backer on [Open collective](https://opencollective.com/dbgate)
* Create some tutorial video on [youtube](https://www.youtube.com/playlist?list=PLCo7KjCVXhr0RfUSjM9wJMsp_ShL1q61A)
* Become a backer on [GitHub sponsors](https://github.com/sponsors/dbgate) or [Open collective](https://opencollective.com/dbgate)
* Where a small coding is acceptable for you, you could [create plugin](https://dbgate.org/docs/plugin-development.html). Plugins for new themes can be created actually without JS coding.
Thank you!
@@ -91,8 +95,8 @@ There are many database managers now, so why DbGate?
## Design goals
* Application simplicity - DbGate takes the best and only the best from old [DbGate](http://www.jenasoft.com/dbgate), [DatAdmin](http://www.jenasoft.com/datadmin) and [DbMouse](http://www.jenasoft.com/dbmouse) .
* Minimal dependencies
* Frontend - Svelte, socket.io
* Backend - NodeJs, ExpressJs, socket.io, database connection drivers
* Frontend - Svelte
* Backend - NodeJs, ExpressJs, database connection drivers
* JavaScript + TypeScript
* App - electron
* Platform independent - runs as web application in single docker container on server, or as application using Electron platform on Linux, Windows and Mac
@@ -124,11 +128,11 @@ yarn # install NPM packages
And than run following 3 commands concurrently in 3 terminals:
```
yarn start:api # run API on port 3000
yarn start:web # run web on port 5000
yarn start:web # run web on port 5001
yarn lib # watch typescript libraries and plugins modifications
```
This runs API on port 3000 and web application on port 5000
Open http://localhost:5000 in your browser
This runs API on port 3000 and web application on port 5001
Open http://localhost:5001 in your browser
If you want to run electron app:
```sh
@@ -139,13 +143,13 @@ yarn # install NPM packages for electron
And than run following 3 commands concurrently in 3 terminals:
```
yarn start:web # run web on port 5000 (only static JS and HTML files)
yarn start:web # run web on port 5001 (only static JS and HTML files)
yarn lib # watch typescript libraries and plugins modifications
yarn start:app # run electron app
```
## How to run built electron app locally
This mode is very similar to production run of electron app. Electron doesn't use localhost:5000.
This mode is very similar to production run of electron app. Electron doesn't use localhost:5001.
```sh
cd app
+12
View File
@@ -0,0 +1,12 @@
const fs = require('fs');
function adjustFile(file) {
const json = JSON.parse(fs.readFileSync(file, { encoding: 'utf-8' }));
if (process.platform != 'win32') {
delete json.optionalDependencies.msnodesqlv8;
}
fs.writeFileSync(file, JSON.stringify(json, null, 2), 'utf-8');
}
adjustFile('packages/api/package.json');
adjustFile('app/package.json');
+1
View File
@@ -0,0 +1 @@
better-sqlite3_local_prebuilds=../../prebuilds
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.disable-library-validation</key><true/>
<key>com.apple.security.cs.allow-jit</key><true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key><true/>
<key>com.apple.security.files.user-selected.read-only</key><true/>
<key>com.apple.security.files.user-selected.read-write</key><true/>
</dict>
</plist>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 192 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 57 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+14 -8
View File
@@ -1,6 +1,6 @@
{
"name": "dbgate",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"private": true,
"author": "Jan Prochazka <jenasoft.database@gmail.com>",
"description": "Opensource database administration tool",
@@ -15,18 +15,23 @@
"url": "https://github.com/dbgate/dbgate.git"
},
"build": {
"artifactName": "${productName}-${version}-${os}_${arch}.${ext}",
"artifactName": "dbgate-${version}-${os}_${arch}.${ext}",
"appId": "org.dbgate",
"productName": "DbGate",
"afterSign": "electron-builder-notarize",
"mac": {
"category": "database",
"icon": "icon512.png",
"hardenedRuntime": true,
"entitlements": "entitlements.mac.plist",
"entitlementsInherit": "entitlements.mac.plist",
"publish": [
"github"
],
"target": {
"target": "default",
"arch": [
"arm64",
"universal",
"x64"
]
}
@@ -89,7 +94,7 @@
},
"homepage": "./",
"scripts": {
"start": "cross-env ELECTRON_START_URL=http://localhost:5000 DEVMODE=1 electron .",
"start": "cross-env ELECTRON_START_URL=http://localhost:5001 DEVMODE=1 electron .",
"start:local": "cross-env electron .",
"dist": "electron-builder",
"build": "cd ../packages/api && yarn build && cd ../web && yarn build && cd ../../app && yarn dist",
@@ -102,11 +107,12 @@
"devDependencies": {
"copyfiles": "^2.2.0",
"cross-env": "^6.0.3",
"electron": "13.6.3",
"electron-builder": "22.14.5"
"electron": "17.4.10",
"electron-builder": "23.1.0",
"electron-builder-notarize": "^1.5.0"
},
"optionalDependencies": {
"better-sqlite3": "7.4.5",
"msnodesqlv8": "^2.4.4"
"better-sqlite3": "7.6.2",
"msnodesqlv8": "^2.6.0"
}
}
+116 -37
View File
@@ -20,6 +20,10 @@ const { settings } = require('cluster');
const configRootPath = path.join(app.getPath('userData'), 'config-root.json');
let initialConfig = {};
let apiLoaded = false;
let mainModule;
const isMac = () => os.platform() == 'darwin';
try {
initialConfig = JSON.parse(fs.readFileSync(configRootPath, { encoding: 'utf-8' }));
@@ -28,19 +32,11 @@ try {
initialConfig = {};
}
// let settingsJson = {};
// try {
// const datadir = path.join(os.homedir(), 'dbgate-data');
// settingsJson = JSON.parse(fs.readFileSync(path.join(datadir, 'settings.json'), { encoding: 'utf-8' }));
// } catch (err) {
// console.log('Error loading settings.json:', err.message);
// settingsJson = {};
// }
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
let mainMenu;
let runCommandOnLoad = null;
log.transports.file.level = 'debug';
autoUpdater.logger = log;
@@ -49,30 +45,72 @@ autoUpdater.logger = log;
let commands = {};
function commandItem(id) {
function formatKeyText(keyText) {
if (!keyText) {
return keyText;
}
if (os.platform() == 'darwin') {
return keyText.replace('CtrlOrCommand+', 'Command+');
}
return keyText.replace('CtrlOrCommand+', 'Ctrl+');
}
function commandItem(item) {
const id = item.command;
const command = commands[id];
if (item.skipInApp) {
return { skip: true };
}
return {
id,
label: command ? command.menuName || command.toolbarName || command.name : id,
accelerator: command ? command.keyText : undefined,
accelerator: formatKeyText(command ? command.keyText : undefined),
enabled: command ? command.enabled : false,
click() {
mainWindow.webContents.send('run-command', id);
if (mainWindow) {
mainWindow.webContents.send('run-command', id);
} else {
runCommandOnLoad = id;
createWindow();
}
},
};
}
function buildMenu() {
const template = _cloneDeepWith(mainMenuDefinition, item => {
let template = _cloneDeepWith(mainMenuDefinition({ editMenu: true }), item => {
if (item.divider) {
return { type: 'separator' };
}
if (item.command) {
return commandItem(item.command);
return commandItem(item);
}
});
template = _cloneDeepWith(template, item => {
if (Array.isArray(item) && item.find(x => x.skip)) {
return item.filter(x => x && !x.skip);
}
});
if (isMac()) {
template = [
{
label: 'DbGate',
submenu: [
commandItem({ command: 'about.show' }),
{ role: 'services' },
{ role: 'hide' },
{ role: 'hideOthers' },
{ role: 'unhide' },
{ role: 'quit' },
],
},
...template,
];
}
return Menu.buildFromTemplate(template);
}
@@ -86,15 +124,21 @@ ipcMain.on('update-commands', async (event, arg) => {
// rebuild menu
if (menu.label != command.text || menu.accelerator != command.keyText) {
mainMenu = buildMenu();
mainWindow.setMenu(mainMenu);
Menu.setApplicationMenu(mainMenu);
// mainWindow.setMenu(mainMenu);
return;
}
menu.enabled = command.enabled;
}
});
ipcMain.on('close-window', async (event, arg) => {
mainWindow.close();
ipcMain.on('quit-app', async (event, arg) => {
if (isMac()) {
app.quit();
} else {
mainWindow.close();
}
});
ipcMain.on('set-title', async (event, arg) => {
mainWindow.setTitle(arg);
@@ -102,7 +146,19 @@ ipcMain.on('set-title', async (event, arg) => {
ipcMain.on('open-link', async (event, arg) => {
electron.shell.openExternal(arg);
});
ipcMain.on('open-dev-tools', () => {
mainWindow.webContents.openDevTools();
});
ipcMain.on('app-started', async (event, arg) => {
if (runCommandOnLoad) {
mainWindow.webContents.send('run-command', runCommandOnLoad);
runCommandOnLoad = null;
}
});
ipcMain.on('window-action', async (event, arg) => {
if (!mainWindow) {
return;
}
switch (arg) {
case 'minimize':
mainWindow.minimize();
@@ -138,6 +194,23 @@ ipcMain.on('window-action', async (event, arg) => {
case 'zoomreset':
mainWindow.webContents.zoomLevel = 0;
break;
// edit
case 'undo':
mainWindow.webContents.undo();
break;
case 'redo':
mainWindow.webContents.redo();
break;
case 'cut':
mainWindow.webContents.cut();
break;
case 'copy':
mainWindow.webContents.copy();
break;
case 'paste':
mainWindow.webContents.paste();
break;
}
});
@@ -161,7 +234,8 @@ function fillMissingSettings(value) {
...value,
};
if (value['app.useNativeMenu'] !== true && value['app.useNativeMenu'] !== false) {
res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false;
res['app.useNativeMenu'] = false;
// res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false;
}
return res;
}
@@ -169,7 +243,7 @@ function fillMissingSettings(value) {
function createWindow() {
let settingsJson = {};
try {
const datadir = path.join(os.homedir(), 'dbgate-data');
const datadir = path.join(os.homedir(), '.dbgate');
settingsJson = fillMissingSettings(
JSON.parse(fs.readFileSync(path.join(datadir, 'settings.json'), { encoding: 'utf-8' }))
);
@@ -236,25 +310,29 @@ function createWindow() {
// mainWindow.webContents.toggleDevTools();
}
const apiPackage = path.join(
__dirname,
process.env.DEVMODE ? '../../packages/api/src/index' : '../packages/api/dist/bundle.js'
);
if (!apiLoaded) {
const apiPackage = path.join(
__dirname,
process.env.DEVMODE ? '../../packages/api/src/index' : '../packages/api/dist/bundle.js'
);
global.API_PACKAGE = apiPackage;
global.NATIVE_MODULES = path.join(__dirname, 'nativeModules');
global.API_PACKAGE = apiPackage;
global.NATIVE_MODULES = path.join(__dirname, 'nativeModules');
// console.log('global.API_PACKAGE', global.API_PACKAGE);
const api = require(apiPackage);
// console.log(
// 'REQUIRED',
// path.resolve(
// path.join(__dirname, process.env.DEVMODE ? '../../packages/api/src/index' : '../packages/api/dist/bundle.js')
// )
// );
const main = api.getMainModule();
main.initializeElectronSender(mainWindow.webContents);
main.useAllControllers(null, electron);
// console.log('global.API_PACKAGE', global.API_PACKAGE);
const api = require(apiPackage);
// console.log(
// 'REQUIRED',
// path.resolve(
// path.join(__dirname, process.env.DEVMODE ? '../../packages/api/src/index' : '../packages/api/dist/bundle.js')
// )
// );
const main = api.getMainModule();
main.useAllControllers(null, electron);
mainModule = main;
apiLoaded = true;
}
mainModule.setElectronSender(mainWindow.webContents);
loadMainWindow();
@@ -264,6 +342,7 @@ function createWindow() {
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
mainModule.setElectronSender(null);
});
}
@@ -283,7 +362,7 @@ app.on('ready', onAppReady);
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
if (!isMac()) {
app.quit();
}
});
+22 -1
View File
@@ -1,4 +1,4 @@
module.exports = [
module.exports = ({ editMenu }) => [
{
label: 'File',
submenu: [
@@ -6,6 +6,9 @@ module.exports = [
{ command: 'new.sqliteDatabase', hideDisabled: true },
{ divider: true },
{ command: 'new.query', hideDisabled: true },
{ command: 'new.queryDesign', hideDisabled: true },
{ command: 'new.diagram', hideDisabled: true },
{ command: 'new.perspective', hideDisabled: true },
{ command: 'new.freetable', hideDisabled: true },
{ command: 'new.shell', hideDisabled: true },
{ command: 'new.jsonl', hideDisabled: true },
@@ -17,6 +20,7 @@ module.exports = [
{ command: 'group.saveAs', hideDisabled: true },
{ divider: true },
{ command: 'file.exit', hideDisabled: true },
{ command: 'app.logout', hideDisabled: true, skipInApp: true },
],
},
{
@@ -33,6 +37,20 @@ module.exports = [
],
},
editMenu
? {
label: 'Edit',
submenu: [
{ command: 'edit.undo' },
{ command: 'edit.redo' },
{ divider: true },
{ command: 'edit.cut' },
{ command: 'edit.copy' },
{ command: 'edit.paste' },
],
}
: null,
// {
// label: 'Edit',
// submenu: [
@@ -51,6 +69,7 @@ module.exports = [
{ command: 'app.toggleDevTools', hideDisabled: true },
{ command: 'app.toggleFullScreen', hideDisabled: true },
{ command: 'app.minimize', hideDisabled: true },
{ command: 'toggle.sidebar' },
{ divider: true },
{ command: 'theme.changeTheme', hideDisabled: true },
{ command: 'settings.show' },
@@ -61,6 +80,7 @@ module.exports = [
submenu: [
{ command: 'database.search', hideDisabled: true },
{ command: 'commandPalette.show', hideDisabled: true },
{ command: 'database.switch', hideDisabled: true },
{ divider: true },
{ command: 'sql.generator', hideDisabled: true },
{ command: 'file.import', hideDisabled: true },
@@ -75,6 +95,7 @@ module.exports = [
{ command: 'app.openIssue', hideDisabled: true },
{ command: 'app.openSponsoring', hideDisabled: true },
{ divider: true },
{ command: 'settings.commands', hideDisabled: true },
{ command: 'tabs.changelog', hideDisabled: true },
{ command: 'about.show', hideDisabled: true },
],
+673 -484
View File
File diff suppressed because it is too large Load Diff
+9 -8
View File
@@ -5,6 +5,7 @@ services:
dbgate:
build: docker
# image: dbgate/dbgate:beta-alpine
# image: dbgate/dbgate:alpine
# image: dbgate/dbgate:beta
restart: always
ports:
@@ -13,10 +14,10 @@ services:
# - /home/jena/dbgate-data:/root/dbgate-data
volumes:
- dbgate-data:/root/dbgate-data
- dbgate-data:/root/.dbgate
environment:
WEB_ROOT: /dbgate
# environment:
# WEB_ROOT: /dbgate
# CONNECTIONS: mssql
# LABEL_mssql: MS Sql
@@ -25,11 +26,11 @@ services:
# PORT_mssql: 1433
# PASSWORD_mssql: Pwd2020Db
# ENGINE_mssql: mssql@dbgate-plugin-mssql
proxy:
# image: nginx
build: test/nginx
ports:
- 8082:80
# proxy:
# # image: nginx
# build: test/nginx
# ports:
# - 8082:80
# volumes:
# - /home/jena/test/chinook:/mnt/sqt
+10 -2
View File
@@ -1,10 +1,18 @@
FROM node:14
RUN apt-get update && apt-get install -y \
iputils-ping \
iproute2 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /home/dbgate-docker
COPY . .
RUN ["chmod", "+x", "/home/dbgate-docker/entrypoint.sh"]
WORKDIR /home/dbgate-docker
EXPOSE 3000
VOLUME /root/dbgate-data
CMD node bundle.js
VOLUME /root/.dbgate
CMD ["/home/dbgate-docker/entrypoint.sh"]
+9 -2
View File
@@ -2,9 +2,16 @@ FROM node:14-alpine
WORKDIR /home/dbgate-docker
RUN apk --no-cache upgrade \
&& apk --no-cache add \
iputils
COPY . .
RUN ["chmod", "+x", "/home/dbgate-docker/entrypoint.sh"]
WORKDIR /home/dbgate-docker
EXPOSE 3000
VOLUME /root/dbgate-data
CMD node bundle.js
VOLUME /root/.dbgate
CMD ["/home/dbgate-docker/entrypoint.sh"]
+11
View File
@@ -0,0 +1,11 @@
#!/bin/sh
HOST_DOMAIN="dockerhost"
ping -q -c1 $HOST_DOMAIN > /dev/null 2>&1
if [ $? != 0 ]
then
HOST_IP=$(ip route | awk 'NR==1 {print $3}')
echo "$HOST_IP $HOST_DOMAIN" >> /etc/hosts
fi
node bundle.js --listen-api
Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 166 KiB

@@ -297,4 +297,33 @@ describe('Deploy database', () => {
expect(res.rows[0].val.toString()).toEqual('5');
})
);
test.each(engines.enginesPostgre.map(engine => [engine.label, engine]))(
'Current timestamp default value - %s',
testWrapper(async (conn, driver, engine) => {
await testDatabaseDeploy(conn, driver, [
[
{
name: 't1.table.yaml',
json: {
name: 't1',
columns: [
{ name: 'id', type: 'int' },
{
name: 'val',
type: 'timestamp',
default: 'current_timestamp',
},
],
primaryKey: ['id'],
},
},
],
]);
await driver.query(conn, `insert into t1 (id) values (1)`);
const res = await driver.query(conn, ` select val from t1 where id = 1`);
expect(res.rows[0].val.toString().substring(0, 2)).toEqual('20');
})
);
});
@@ -14,7 +14,7 @@ const txMatch = (tname, vcolname, nextcol) =>
expect.objectContaining({
columnName: 'id',
notNull: true,
dataType: expect.stringContaining('int'),
dataType: expect.stringMatching(/int/i),
}),
expect.objectContaining({
columnName: vcolname,
+29 -20
View File
@@ -1,21 +1,30 @@
version: '3'
services:
postgres:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: Pwd2020Db
ports:
- 15000:5432
# postgres:
# image: postgres
# restart: always
# environment:
# POSTGRES_PASSWORD: Pwd2020Db
# ports:
# - 15000:5432
mysql:
image: mysql:8.0.18
command: --default-authentication-plugin=mysql_native_password
restart: always
ports:
- 15001:3306
environment:
- MYSQL_ROOT_PASSWORD=Pwd2020Db
# mariadb:
# image: mariadb
# command: --default-authentication-plugin=mysql_native_password
# restart: always
# ports:
# - 15004:3306
# environment:
# - MYSQL_ROOT_PASSWORD=Pwd2020Db
# mysql:
# image: mysql:8.0.18
# command: --default-authentication-plugin=mysql_native_password
# restart: always
# ports:
# - 15001:3306
# environment:
# - MYSQL_ROOT_PASSWORD=Pwd2020Db
mssql:
image: mcr.microsoft.com/mssql/server
@@ -27,11 +36,11 @@ services:
- SA_PASSWORD=Pwd2020Db
- MSSQL_PID=Express
cockroachdb:
image: cockroachdb/cockroach
ports:
- 15003:26257
command: start-single-node --insecure
# cockroachdb:
# image: cockroachdb/cockroach
# ports:
# - 15003:26257
# command: start-single-node --insecure
# mongodb:
# image: mongo:4.0.12
+24 -2
View File
@@ -31,6 +31,23 @@ const engines = [
objects: [views],
dbSnapshotBySeconds: true,
},
{
label: 'MariaDB',
connection: {
engine: 'mariadb@dbgate-plugin-mysql',
password: 'Pwd2020Db',
user: 'root',
server: 'mysql',
port: 3306,
},
local: {
server: 'localhost',
port: 15004,
},
skipOnCI: true,
objects: [views],
dbSnapshotBySeconds: true,
},
{
label: 'PostgreSQL',
connection: {
@@ -117,12 +134,17 @@ const engines = [
const filterLocal = [
// filter local testing
'-MySQL',
'-MariaDB',
'-PostgreSQL',
'-SQL Server',
'SQLite',
'SQL Server',
'-SQLite',
'-CockroachDB',
];
const enginesPostgre = engines.filter(x => x.label == 'PostgreSQL');
module.exports = process.env.CITEST
? engines.filter(x => !x.skipOnCI)
: engines.filter(x => filterLocal.find(y => x.label == y));
module.exports.enginesPostgre = enginesPostgre;
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "dbgate-integration-tests",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",
Binary file not shown.
Binary file not shown.
+106
View File
@@ -0,0 +1,106 @@
# magick icon.svg -resize 1024x1024 -transparent white -background transparent app/icon1024.png
# magick app/icon1024.png -resize 512x512 app/icon512.png
# magick app/icon1024.png -resize 256x256 app/icon.png
# magick app/icon1024.png -resize 32x32 app/icon32.png
# magick icon.svg -define icon:auto-resize="256,128,96,64,48,32,16" -transparent white -background transparent app/icon.ico
# # magick icon.svg -resize 512x512 -transparent white -background transparent app/icon512.png
# # magick icon.svg -resize 256x256 -transparent white -background transparent app/icon.png
# # magick icon.svg -resize 32x32 -transparent white -background transparent app/icon32.png
# # magick icon.svg -define icon:auto-resize="256,128,96,64,48,32,16" -transparent white -background transparent app/icon.ico
# magick app/icon1024.png -resize 512x512 app/icons/512x512.png
# magick app/icon1024.png -resize 256x256 app/icons/256x256.png
# magick app/icon1024.png -resize 128x128 app/icons/128x128.png
# magick app/icon1024.png -resize 64x64 app/icons/64x64.png
# magick app/icon1024.png -resize 48x48 app/icons/48x48.png
# magick app/icon1024.png -resize 32x32 app/icons/32x32.png
# magick app/icon1024.png -resize 16x16 app/icons/16x16.png
# # magick icon.svg -resize 16x16 -transparent white -background transparent app/icons/16x16.png
# # magick icon.svg -resize 32x32 -transparent white -background transparent app/icons/32x32.png
# # magick icon.svg -resize 48x48 -transparent white -background transparent app/icons/48x48.png
# # magick icon.svg -resize 64x64 -transparent white -background transparent app/icons/64x64.png
# # magick icon.svg -resize 128x128 -transparent white -background transparent app/icons/128x128.png
# # magick icon.svg -resize 256x256 -transparent white -background transparent app/icons/256x256.png
# # magick icon.svg -resize 512x512 -transparent white -background transparent app/icons/512x512.png
# magick icon.svg -resize 1024x1024 icon.png
# magick icon.svg -resize 1024x1024 -transparent white -background transparent icon.png
STROKE_WIDTH=30
LEFT=150
RIGHT=850
magick \
\( \
-size 1000x1000 -define gradient:direction=east 'gradient:#0050b3-#1890ff' \
\( +clone -fill Black -colorize 100 \
-fill White -stroke White -draw "arc $LEFT,750 $RIGHT,950 0,360" -draw "rectangle $LEFT,150 $RIGHT,850" \
\) \
-alpha off \
-compose CopyOpacity -composite \
\) \
\( \
-size 1000x1000 -define gradient:direction=east 'gradient:#096dd9-#40a9ff' \
\( +clone -fill Black -colorize 100 \
-fill White -draw "arc $LEFT,50 $RIGHT,250 0,360" \
\) \
-alpha off \
-compose CopyOpacity -composite \
\) \
-compose Over -composite \
-strokewidth $STROKE_WIDTH -stroke '#0050b3' -fill transparent \
-draw "arc $LEFT,225 $RIGHT,425 0,180" \
-draw "arc $LEFT,400 $RIGHT,600 0,180" \
-draw "arc $LEFT,575 $RIGHT,775 0,180" \
-draw "arc $LEFT,750 $RIGHT,950 0,180" \
-draw "arc $LEFT,50 $RIGHT,250 0,360" \
-draw "line $LEFT,150 $LEFT,850" \
-draw "line $RIGHT,150 $RIGHT,850" \
-fill '#fafafa' -stroke '#8c8c8c' -strokewidth 3 \
-pointsize 800 -font './Mcbungus-Regular.ttf' \
-gravity center \
-draw 'text 0,100 "G"' \
icon.png
# magick \
# \( \
# -size 300x300 gradient:red-blue \
# \( +clone -fill Black -colorize 100 \
# -fill White -draw "polygon 50,50 250,50 200,200" \
# \) \
# -alpha off \
# -compose CopyOpacity -composite \
# \) \
# \( \
# -size 300x300 'gradient:#f80-#08f' \
# \( +clone -fill Black -colorize 100 \
# -fill White -draw "polygon 50,150 250,150 200,300" \
# \) \
# -alpha off \
# -compose CopyOpacity -composite \
# \) \
# -compose Over -composite \
# icon.png
magick icon.png -resize 512x512! ../app/icon512.png
magick icon.png -resize 256x256! ../app/icon.png
magick icon.png -resize 32x32! ../app/icon32.png
magick icon.png -define icon:auto-resize="256,128,96,64,48,32,16" ../app/icon.ico
magick icon.png -resize 512x512! ../app/icons/512x512.png
magick icon.png -resize 256x256! ../app/icons/256x256.png
magick icon.png -resize 128x128! ../app/icons/128x128.png
magick icon.png -resize 64x64! ../app/icons/64x64.png
magick icon.png -resize 48x48! ../app/icons/48x48.png
magick icon.png -resize 32x32! ../app/icons/32x32.png
magick icon.png -resize 16x16! ../app/icons/16x16.png
magick icon.png -resize 192x192! ../packages/web/public/logo192.png
magick icon.png -resize 512x512! ../packages/web/public/logo512.png
magick icon.png -define icon:auto-resize="256,128,96,64,48,32,16" ../packages/web/public/favicon.ico
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 17.804 17.804" style="enable-background:new 0 0 17.804 17.804;" xml:space="preserve">
<g>
<g id="c98_play">
<path fill='#ccc' d="M2.067,0.043C2.21-0.028,2.372-0.008,2.493,0.085l13.312,8.503c0.094,0.078,0.154,0.191,0.154,0.313
c0,0.12-0.061,0.237-0.154,0.314L2.492,17.717c-0.07,0.057-0.162,0.087-0.25,0.087l-0.176-0.04
c-0.136-0.065-0.222-0.207-0.222-0.361V0.402C1.844,0.25,1.93,0.107,2.067,0.043z"/>
</g>
<g id="Capa_1_78_">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 733 B

+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 17.804 17.804" style="enable-background:new 0 0 17.804 17.804;" xml:space="preserve">
<g>
<g id="c98_play">
<path fill='#444' d="M2.067,0.043C2.21-0.028,2.372-0.008,2.493,0.085l13.312,8.503c0.094,0.078,0.154,0.191,0.154,0.313
c0,0.12-0.061,0.237-0.154,0.314L2.492,17.717c-0.07,0.057-0.162,0.087-0.25,0.087l-0.176-0.04
c-0.136-0.065-0.222-0.207-0.222-0.361V0.402C1.844,0.25,1.93,0.107,2.067,0.043z"/>
</g>
<g id="Capa_1_78_">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 733 B

+13 -9
View File
@@ -1,6 +1,6 @@
{
"private": true,
"version": "4.7.2",
"version": "5.1.6-beta.7",
"name": "dbgate-all",
"workspaces": [
"packages/*",
@@ -10,20 +10,23 @@
"scripts": {
"start:api": "yarn workspace dbgate-api start",
"start:app": "cd app && yarn start",
"start:api:debug": "cross-env DEBUG=* yarn workspace dbgate-api start",
"start:app:debug": "cd app && cross-env DEBUG=* yarn start",
"start:api:debug:ssh": "cross-env DEBUG=ssh yarn workspace dbgate-api start",
"start:app:debug:ssh": "cd app && cross-env DEBUG=ssh yarn start",
"start:api:portal": "yarn workspace dbgate-api start:portal",
"start:api:covid": "yarn workspace dbgate-api start:covid",
"start:api:singledb": "yarn workspace dbgate-api start:singledb",
"start:api:auth": "yarn workspace dbgate-api start:auth",
"start:web": "yarn workspace dbgate-web dev",
"start:sqltree": "yarn workspace dbgate-sqltree start",
"start:tools": "yarn workspace dbgate-tools start",
"start:datalib": "yarn workspace dbgate-datalib start",
"start:filterparser": "yarn workspace dbgate-filterparser start",
"start:querysplitter": "yarn workspace dbgate-query-splitter start",
"build:sqltree": "yarn workspace dbgate-sqltree build",
"build:datalib": "yarn workspace dbgate-datalib build",
"build:filterparser": "yarn workspace dbgate-filterparser build",
"build:querysplitter": "yarn workspace dbgate-query-splitter build",
"build:tools": "yarn workspace dbgate-tools build",
"build:lib": "yarn build:querysplitter && yarn build:tools && yarn build:sqltree && yarn build:filterparser && yarn build:datalib",
"build:lib": "yarn build:sqltree && yarn build:tools && yarn build:filterparser && yarn build:datalib",
"build:app": "yarn plugins:copydist && cd app && yarn install && yarn build",
"build:api": "yarn workspace dbgate-api build",
"build:web:docker": "yarn workspace dbgate-web build",
@@ -34,6 +37,7 @@
"start:app:local": "cd app && yarn start:local",
"setCurrentVersion": "node setCurrentVersion",
"generatePadFile": "node generatePadFile",
"adjustPackageJson": "node adjustPackageJson",
"fillNativeModules": "node fillNativeModules",
"fillNativeModulesElectron": "node fillNativeModules --electron",
"fillPackagedPlugins": "node fillPackagedPlugins",
@@ -43,16 +47,16 @@
"install:sqlite:docker": "cd docker && yarn init --yes && yarn add better-sqlite3 && cd ..",
"prepare:docker": "yarn plugins:copydist && yarn build:web:docker && yarn build:api && yarn copy:docker:build && yarn install:sqlite:docker",
"start": "concurrently --kill-others-on-fail \"yarn start:api\" \"yarn start:web\"",
"lib": "concurrently --kill-others-on-fail \"yarn start:sqltree\" \"yarn start:filterparser\" \"yarn start:datalib\" \"yarn start:tools\" \"yarn start:querysplitter\" \"yarn build:plugins:frontend:watch\"",
"lib": "concurrently --kill-others-on-fail \"yarn start:sqltree\" \"yarn start:filterparser\" \"yarn start:datalib\" \"yarn start:tools\" \"yarn build:plugins:frontend:watch\"",
"ts:api": "yarn workspace dbgate-api ts",
"ts:web": "yarn workspace dbgate-web ts",
"ts": "yarn ts:api && yarn ts:web",
"postinstall": "yarn resetPackagedPlugins && yarn build:lib && patch-package && yarn fillNativeModules && yarn build:plugins:frontend"
"postinstall": "yarn resetPackagedPlugins && yarn build:lib && patch-package && yarn fillNativeModules && yarn build:plugins:frontend",
"dbgate-serve": "node packages/dbgate/bin/dbgate-serve.js"
},
"dependencies": {
"concurrently": "^5.1.0",
"patch-package": "^6.2.1",
"socket.io": "^2.3.0"
"patch-package": "^6.2.1"
},
"devDependencies": {
"copyfiles": "^2.2.0",
+16
View File
@@ -1 +1,17 @@
DEVMODE=1
SHELL_SCRIPTING=1
# PERMISSIONS=~widgets/app,~widgets/plugins
# DISABLE_SHELL=1
# HIDE_APP_EDITOR=1
# DEVWEB=1
# LOGINS=admin,test
# LOGIN_PASSWORD_admin=admin
# LOGIN_PERMISSIONS_admin=*
# LOGIN_PASSWORD_test=test
# LOGIN_PERMISSIONS_test=~*, widgets/database
# WORKSPACE_DIR=/home/jena/dbgate-data-2
+1
View File
@@ -0,0 +1 @@
.env
+20 -2
View File
@@ -1,6 +1,6 @@
DEVMODE=1
CONNECTIONS=mysql,postgres,mongo,mongo2,mysqlssh,sqlite
CONNECTIONS=mysql,postgres,mongo,mongo2,mysqlssh,sqlite,relational
LABEL_mysql=MySql localhost
SERVER_mysql=localhost
@@ -38,7 +38,25 @@ SSH_LOGIN_mysqlssh=root
SSH_PASSWORD_mysqlssh=xxx
LABEL_sqlite=sqlite
FILE_sqlite=/home/jena/dbgate-data/files/sqlite/feeds.sqlite
FILE_sqlite=/home/jena/.dbgate/files/sqlite/feeds.sqlite
ENGINE_sqlite=sqlite@dbgate-plugin-sqlite
LABEL_relational=Relational dataset repo
SERVER_relational=relational.fit.cvut.cz
USER_relational=guest
PASSWORD_relational=relational
ENGINE_relational=mariadb@dbgate-plugin-mysql
READONLY_relational=1
# SETTINGS_dataGrid.showHintColumns=1
# docker run -p 3000:3000 -e CONNECTIONS=mongo -e URL_mongo=mongodb://localhost:27017 -e ENGINE_mongo=mongo@dbgate-plugin-mongo -e LABEL_mongo=mongo dbgate/dbgate:beta
# LOGINS=x,y
# LOGIN_PASSWORD_x=x
# LOGIN_PASSWORD_y=LOGIN_PASSWORD_y
# LOGIN_PERMISSIONS_x=~*
# LOGIN_PERMISSIONS_y=~*
# PERMISSIONS=~*,connections/relational
# PERMISSIONS=~*
@@ -8,6 +8,8 @@ USER_mysql=root
PASSWORD_mysql=test
PORT_mysql=3307
ENGINE_mysql=mysql@dbgate-plugin-mysql
DBCONFIG_mysql=[{"name":"Chinook","connectionColor":"cyan"}]
SINGLE_CONNECTION=mysql
SINGLE_DATABASE=Chinook
+18 -13
View File
@@ -1,7 +1,7 @@
{
"name": "dbgate-api",
"main": "src/index.js",
"version": "4.1.1",
"version": "5.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",
@@ -17,6 +17,7 @@
"dbgate"
],
"dependencies": {
"activedirectory2": "^2.1.0",
"async-lock": "^1.2.4",
"axios": "^0.21.1",
"body-parser": "^1.19.0",
@@ -25,9 +26,10 @@
"compare-versions": "^3.6.0",
"cors": "^2.8.5",
"cross-env": "^6.0.3",
"dbgate-query-splitter": "^4.1.1",
"dbgate-sqltree": "^4.1.1",
"dbgate-tools": "^4.1.1",
"dbgate-query-splitter": "^4.9.2",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"debug": "^4.3.4",
"diff": "^5.0.0",
"diff2html": "^3.4.13",
"eslint": "^6.8.0",
@@ -41,29 +43,32 @@
"is-electron": "^2.2.1",
"js-yaml": "^4.1.0",
"json-stable-stringify": "^1.0.1",
"jsonwebtoken": "^8.5.1",
"line-reader": "^0.4.0",
"lodash": "^4.17.21",
"ncp": "^2.0.0",
"node-cron": "^2.0.3",
"node-ssh-forward": "^0.7.2",
"on-finished": "^2.4.1",
"portfinder": "^1.0.28",
"simple-encryptor": "^4.0.0",
"ssh2": "^1.11.0",
"tar": "^6.0.5",
"uuid": "^3.4.0"
},
"scripts": {
"start": "env-cmd node src/index.js",
"start:portal": "env-cmd -f .env-portal node src/index.js",
"start:singledb": "env-cmd -f .env-singledb node src/index.js",
"start:filedb": "env-cmd node src/index.js /home/jena/test/chinook/Chinook.db",
"start:singleconn": "env-cmd node src/index.js --server localhost --user root --port 3307 --engine mysql@dbgate-plugin-mysql --password test",
"start": "env-cmd node src/index.js --listen-api",
"start:portal": "env-cmd -f env/portal/.env node src/index.js --listen-api",
"start:singledb": "env-cmd -f env/singledb/.env node src/index.js --listen-api",
"start:auth": "env-cmd -f env/auth/.env node src/index.js --listen-api",
"start:filedb": "env-cmd node src/index.js /home/jena/test/chinook/Chinook.db --listen-api",
"start:singleconn": "env-cmd node src/index.js --server localhost --user root --port 3307 --engine mysql@dbgate-plugin-mysql --password test --listen-api",
"ts": "tsc",
"build": "webpack"
},
"devDependencies": {
"@types/fs-extra": "^9.0.11",
"@types/lodash": "^4.14.149",
"dbgate-types": "^4.1.1",
"dbgate-types": "^5.0.0-alpha.1",
"env-cmd": "^10.1.0",
"node-loader": "^1.0.2",
"nodemon": "^2.0.2",
@@ -72,7 +77,7 @@
"webpack-cli": "^3.3.11"
},
"optionalDependencies": {
"better-sqlite3": "7.4.5",
"msnodesqlv8": "^2.4.4"
"better-sqlite3": "7.6.2",
"msnodesqlv8": "^2.6.0"
}
}
+12
View File
@@ -265,4 +265,16 @@ module.exports = {
return true;
},
createConfigFile_meta: true,
async createConfigFile({ appFolder, fileName, content }) {
const file = path.join(appdir(), appFolder, fileName);
if (!(await fs.exists(file))) {
await fs.writeFile(file, JSON.stringify(content, undefined, 2));
socket.emitChanged(`app-files-changed-${appFolder}`);
socket.emitChanged('used-apps-changed');
return true;
}
return false;
},
};
+26 -24
View File
@@ -1,11 +1,8 @@
const fs = require('fs-extra');
const stream = require('stream');
const readline = require('readline');
const path = require('path');
const { formatWithOptions } = require('util');
const { archivedir, clearArchiveLinksCache, resolveArchiveFolder } = require('../utility/directories');
const socket = require('../utility/socket');
const JsonLinesDatastore = require('../utility/JsonLinesDatastore');
const { saveFreeTableData } = require('../utility/freeTableStorage');
const loadFilesRecursive = require('../utility/loadFilesRecursive');
@@ -45,29 +42,34 @@ module.exports = {
files_meta: true,
async files({ folder }) {
const dir = resolveArchiveFolder(folder);
if (!(await fs.exists(dir))) return [];
const files = await loadFilesRecursive(dir); // fs.readdir(dir);
try {
const dir = resolveArchiveFolder(folder);
if (!(await fs.exists(dir))) return [];
const files = await loadFilesRecursive(dir); // fs.readdir(dir);
function fileType(ext, type) {
return files
.filter(name => name.endsWith(ext))
.map(name => ({
name: name.slice(0, -ext.length),
label: path.parse(name.slice(0, -ext.length)).base,
type,
}));
function fileType(ext, type) {
return files
.filter(name => name.endsWith(ext))
.map(name => ({
name: name.slice(0, -ext.length),
label: path.parse(name.slice(0, -ext.length)).base,
type,
}));
}
return [
...fileType('.jsonl', 'jsonl'),
...fileType('.table.yaml', 'table.yaml'),
...fileType('.view.sql', 'view.sql'),
...fileType('.proc.sql', 'proc.sql'),
...fileType('.func.sql', 'func.sql'),
...fileType('.trigger.sql', 'trigger.sql'),
...fileType('.matview.sql', 'matview.sql'),
];
} catch (err) {
console.log('Error reading archive files', err.message);
return [];
}
return [
...fileType('.jsonl', 'jsonl'),
...fileType('.table.yaml', 'table.yaml'),
...fileType('.view.sql', 'view.sql'),
...fileType('.proc.sql', 'proc.sql'),
...fileType('.func.sql', 'func.sql'),
...fileType('.trigger.sql', 'trigger.sql'),
...fileType('.matview.sql', 'matview.sql'),
];
},
refreshFiles_meta: true,
+142
View File
@@ -0,0 +1,142 @@
const axios = require('axios');
const jwt = require('jsonwebtoken');
const getExpressPath = require('../utility/getExpressPath');
const uuidv1 = require('uuid/v1');
const { getLogins } = require('../utility/hasPermission');
const AD = require('activedirectory2').promiseWrapper;
const tokenSecret = uuidv1();
function shouldAuthorizeApi() {
const logins = getLogins();
return !!process.env.OAUTH_AUTH || !!process.env.AD_URL || (!!logins && !process.env.BASIC_AUTH);
}
function getTokenLifetime() {
return process.env.TOKEN_LIFETIME || '1d';
}
function unauthorizedResponse(req, res, text) {
// if (req.path == getExpressPath('/config/get-settings')) {
// return res.json({});
// }
// if (req.path == getExpressPath('/connections/list')) {
// return res.json([]);
// }
return res.sendStatus(401).send(text);
}
function authMiddleware(req, res, next) {
const SKIP_AUTH_PATHS = ['/config/get', '/auth/oauth-token', '/auth/login', '/stream'];
if (!shouldAuthorizeApi()) {
return next();
}
let skipAuth = !!SKIP_AUTH_PATHS.find(x => req.path == getExpressPath(x));
const authHeader = req.headers.authorization;
if (!authHeader) {
if (skipAuth) {
return next();
}
return unauthorizedResponse(req, res, 'missing authorization header');
}
const token = authHeader.split(' ')[1];
try {
const decoded = jwt.verify(token, tokenSecret);
req.user = decoded;
return next();
} catch (err) {
if (skipAuth) {
return next();
}
console.log('Sending invalid token error', err.message);
return unauthorizedResponse(req, res, 'invalid token');
}
}
module.exports = {
oauthToken_meta: true,
async oauthToken(params) {
const { redirectUri, code } = params;
const resp = await axios.default.post(
`${process.env.OAUTH_TOKEN}`,
`grant_type=authorization_code&code=${encodeURIComponent(code)}&redirect_uri=${encodeURIComponent(
redirectUri
)}&client_id=${process.env.OAUTH_CLIENT_ID}&client_secret=${process.env.OAUTH_CLIENT_SECRET}`
);
const { access_token, refresh_token } = resp.data;
const payload = jwt.decode(access_token);
console.log('User payload returned from OAUTH:', payload);
const login = process.env.OAUTH_LOGIN_FIELD ? payload[process.env.OAUTH_LOGIN_FIELD] : 'oauth';
if (
process.env.OAUTH_ALLOWED_LOGINS &&
!process.env.OAUTH_ALLOWED_LOGINS.split(',').find(x => x.toLowerCase().trim() == login.toLowerCase().trim())
) {
return { error: `Username ${login} not allowed to log in` };
}
if (access_token) {
return {
accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: getTokenLifetime() }),
};
}
return { error: 'Token not found' };
},
login_meta: true,
async login(params) {
const { login, password } = params;
if (process.env.AD_URL) {
const adConfig = {
url: process.env.AD_URL,
baseDN: process.env.AD_BASEDN,
username: process.env.AD_USERNAME,
password: process.env.AD_PASSOWRD,
};
const ad = new AD(adConfig);
try {
const res = await ad.authenticate(login, password);
if (!res) {
return { error: 'Login failed' };
}
if (
process.env.AD_ALLOWED_LOGINS &&
!process.env.AD_ALLOWED_LOGINS.split(',').find(x => x.toLowerCase().trim() == login.toLowerCase().trim())
) {
return { error: `Username ${login} not allowed to log in` };
}
return {
accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: getTokenLifetime() }),
};
} catch (err) {
console.log('Failed active directory authentization', err.message);
return {
error: err.message,
};
}
}
const logins = getLogins();
if (!logins) {
return { error: 'Logins not configured' };
}
if (logins.find(x => x.login == login)?.password == password) {
return {
accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: getTokenLifetime() }),
};
}
return { error: 'Invalid credentials' };
},
authMiddleware,
shouldAuthorizeApi,
};
+49 -16
View File
@@ -3,7 +3,7 @@ const os = require('os');
const path = require('path');
const axios = require('axios');
const { datadir } = require('../utility/directories');
const hasPermission = require('../utility/hasPermission');
const { hasPermission, getLogins } = require('../utility/hasPermission');
const socket = require('../utility/socket');
const _ = require('lodash');
const AsyncLock = require('async-lock');
@@ -26,17 +26,35 @@ module.exports = {
// },
get_meta: true,
async get() {
const permissions = process.env.PERMISSIONS ? process.env.PERMISSIONS.split(',') : null;
async get(_params, req) {
const logins = getLogins();
const login = req.user ? req.user.login : logins ? logins.find(x => x.login == (req.auth && req.auth.user)) : null;
const permissions = login ? login.permissions : process.env.PERMISSIONS;
return {
runAsPortal: !!connections.portalConnections,
singleDatabase: connections.singleDatabase,
// hideAppEditor: !!process.env.HIDE_APP_EDITOR,
allowShellConnection: platformInfo.allowShellConnection,
allowShellScripting: platformInfo.allowShellScripting,
isDocker: platformInfo.isDocker,
permissions,
login,
oauth: process.env.OAUTH_AUTH,
oauthLogout: process.env.OAUTH_LOGOUT,
isLoginForm: !!process.env.AD_URL || (!!logins && !process.env.BASIC_AUTH),
...currentVersion,
};
},
logout_meta: {
method: 'get',
raw: true,
},
logout(req, res) {
res.status(401).send('Logged out<br><a href="../..">Back to DbGate</a>');
},
platformInfo_meta: true,
async platformInfo() {
return platformInfo;
@@ -44,13 +62,10 @@ module.exports = {
getSettings_meta: true,
async getSettings() {
try {
return this.fillMissingSettings(
JSON.parse(await fs.readFile(path.join(datadir(), 'settings.json'), { encoding: 'utf-8' }))
);
} catch (err) {
return this.fillMissingSettings({});
}
const res = await lock.acquire('settings', async () => {
return await this.loadSettings();
});
return res;
},
fillMissingSettings(value) {
@@ -58,17 +73,35 @@ module.exports = {
...value,
};
if (value['app.useNativeMenu'] !== true && value['app.useNativeMenu'] !== false) {
res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false;
// res['app.useNativeMenu'] = os.platform() == 'darwin' ? true : false;
res['app.useNativeMenu'] = false;
}
for (const envVar in process.env) {
if (envVar.startsWith('SETTINGS_')) {
const key = envVar.substring('SETTINGS_'.length);
if (!res[key]) {
res[key] = process.env[envVar];
}
}
}
return res;
},
updateSettings_meta: true,
async updateSettings(values) {
if (!hasPermission(`settings/change`)) return false;
async loadSettings() {
try {
const settingsText = await fs.readFile(path.join(datadir(), 'settings.json'), { encoding: 'utf-8' });
return this.fillMissingSettings(JSON.parse(settingsText));
} catch (err) {
return this.fillMissingSettings({});
}
},
const res = await lock.acquire('update', async () => {
const currentValue = await this.getSettings();
updateSettings_meta: true,
async updateSettings(values, req) {
if (!hasPermission(`settings/change`, req)) return false;
const res = await lock.acquire('settings', async () => {
const currentValue = await this.loadSettings();
try {
const updated = {
...currentValue,
+36 -9
View File
@@ -5,12 +5,15 @@ const fs = require('fs-extra');
const { datadir, filesdir } = require('../utility/directories');
const socket = require('../utility/socket');
const { encryptConnection } = require('../utility/crypting');
const { encryptConnection, maskConnection } = require('../utility/crypting');
const { handleProcessCommunication } = require('../utility/processComm');
const { pickSafeConnectionInfo } = require('../utility/crypting');
const JsonLinesDatabase = require('../utility/JsonLinesDatabase');
const processArgs = require('../utility/processArgs');
const { safeJsonParse } = require('dbgate-tools');
const platformInfo = require('../utility/platformInfo');
const { connectionHasPermission, testConnectionPermission } = require('../utility/hasPermission');
function getNamedArgs() {
const res = {};
@@ -50,11 +53,16 @@ function getPortalCollections() {
databaseUrl: process.env[`URL_${id}`],
useDatabaseUrl: !!process.env[`URL_${id}`],
databaseFile: process.env[`FILE_${id}`],
socketPath: process.env[`SOCKET_PATH_${id}`],
authType: process.env[`AUTH_TYPE_${id}`] || (process.env[`SOCKET_PATH_${id}`] ? 'socket' : undefined),
defaultDatabase:
process.env[`DATABASE_${id}`] ||
(process.env[`FILE_${id}`] ? getDatabaseFileLabel(process.env[`FILE_${id}`]) : null),
singleDatabase: !!process.env[`DATABASE_${id}`] || !!process.env[`FILE_${id}`],
displayName: process.env[`LABEL_${id}`],
isReadOnly: process.env[`READONLY_${id}`],
databases: process.env[`DBCONFIG_${id}`] ? safeJsonParse(process.env[`DBCONFIG_${id}`]) : null,
parent: process.env[`PARENT_${id}`] || undefined,
// SSH tunnel
useSshTunnel: process.env[`USE_SSH_${id}`],
@@ -161,8 +169,12 @@ module.exports = {
},
list_meta: true,
async list() {
return portalConnections || this.datastore.find();
async list(_params, req) {
if (portalConnections) {
if (platformInfo.allowShellConnection) return portalConnections;
return portalConnections.map(maskConnection).filter(x => connectionHasPermission(x, req));
}
return (await this.datastore.find()).filter(x => connectionHasPermission(x, req));
},
test_meta: true,
@@ -199,6 +211,9 @@ module.exports = {
}
socket.emitChanged('connection-list-changed');
socket.emitChanged('used-apps-changed');
if (this._closeAll) {
this._closeAll(connection._id);
}
// for (const db of connection.databases || []) {
// socket.emitChanged(`db-apps-changed-${connection._id}-${db.name}`);
// }
@@ -206,16 +221,18 @@ module.exports = {
},
update_meta: true,
async update({ _id, values }) {
async update({ _id, values }, req) {
if (portalConnections) return;
testConnectionPermission(_id, req);
const res = await this.datastore.patch(_id, values);
socket.emitChanged('connection-list-changed');
return res;
},
updateDatabase_meta: true,
async updateDatabase({ conid, database, values }) {
async updateDatabase({ conid, database, values }, req) {
if (portalConnections) return;
testConnectionPermission(conid, req);
const conn = await this.datastore.get(conid);
let databases = (conn && conn.databases) || [];
if (databases.find(x => x.name == database)) {
@@ -231,20 +248,30 @@ module.exports = {
},
delete_meta: true,
async delete(connection) {
async delete(connection, req) {
if (portalConnections) return;
testConnectionPermission(connection, req);
const res = await this.datastore.remove(connection._id);
socket.emitChanged('connection-list-changed');
return res;
},
get_meta: true,
async get({ conid }) {
if (portalConnections) return portalConnections.find(x => x._id == conid) || null;
async getCore({ conid, mask = false }) {
if (!conid) return null;
if (portalConnections) {
const res = portalConnections.find(x => x._id == conid) || null;
return mask && !platformInfo.allowShellConnection ? maskConnection(res) : res;
}
const res = await this.datastore.get(conid);
return res || null;
},
get_meta: true,
async get({ conid }, req) {
testConnectionPermission(conid, req);
return this.getCore({ conid, mask: true });
},
newSqliteDatabase_meta: true,
async newSqliteDatabase({ file }) {
const sqliteDir = path.join(filesdir(), 'sqlite');
@@ -26,6 +26,7 @@ const generateDeploySql = require('../shell/generateDeploySql');
const { createTwoFilesPatch } = require('diff');
const diff2htmlPage = require('../utility/diff2htmlPage');
const processArgs = require('../utility/processArgs');
const { testConnectionPermission } = require('../utility/hasPermission');
module.exports = {
/** @type {import('dbgate-types').OpenedDatabaseConnection[]} */
@@ -33,6 +34,10 @@ module.exports = {
closed: {},
requests: {},
async _init() {
connections._closeAll = conid => this.closeAll(conid);
},
handle_structure(conid, database, { structure }) {
const existing = this.opened.find(x => x.conid == conid && x.database == database);
if (!existing) return;
@@ -75,7 +80,7 @@ module.exports = {
async ensureOpened(conid, database) {
const existing = this.opened.find(x => x.conid == conid && x.database == database);
if (existing) return existing;
const connection = await connections.get({ conid });
const connection = await connections.getCore({ conid });
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
'--is-forked-api',
'--start-process',
@@ -126,7 +131,8 @@ module.exports = {
},
queryData_meta: true,
async queryData({ conid, database, sql }) {
async queryData({ conid, database, sql }, req) {
testConnectionPermission(conid, req);
console.log(`Processing query, conid=${conid}, database=${database}, sql=${sql}`);
const opened = await this.ensureOpened(conid, database);
// if (opened && opened.status && opened.status.name == 'error') {
@@ -136,8 +142,17 @@ module.exports = {
return res;
},
sqlSelect_meta: true,
async sqlSelect({ conid, database, select }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype: 'sqlSelect', select });
return res;
},
runScript_meta: true,
async runScript({ conid, database, sql }) {
async runScript({ conid, database, sql }, req) {
testConnectionPermission(conid, req);
console.log(`Processing script, conid=${conid}, database=${database}, sql=${sql}`);
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype: 'runScript', sql });
@@ -145,21 +160,92 @@ module.exports = {
},
collectionData_meta: true,
async collectionData({ conid, database, options }) {
async collectionData({ conid, database, options }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype: 'collectionData', options });
return res.result;
return res.result || null;
},
async loadDataCore(msgtype, { conid, database, ...args }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype, ...args });
if (res.errorMessage) {
console.error(res.errorMessage);
return {
errorMessage: res.errorMessage,
};
}
return res.result || null;
},
loadKeys_meta: true,
async loadKeys({ conid, database, root, filter }, req) {
testConnectionPermission(conid, req);
return this.loadDataCore('loadKeys', { conid, database, root, filter });
},
exportKeys_meta: true,
async exportKeys({ conid, database, options }, req) {
testConnectionPermission(conid, req);
return this.loadDataCore('exportKeys', { conid, database, options });
},
loadKeyInfo_meta: true,
async loadKeyInfo({ conid, database, key }, req) {
testConnectionPermission(conid, req);
return this.loadDataCore('loadKeyInfo', { conid, database, key });
},
loadKeyTableRange_meta: true,
async loadKeyTableRange({ conid, database, key, cursor, count }, req) {
testConnectionPermission(conid, req);
return this.loadDataCore('loadKeyTableRange', { conid, database, key, cursor, count });
},
loadFieldValues_meta: true,
async loadFieldValues({ conid, database, schemaName, pureName, field, search }, req) {
testConnectionPermission(conid, req);
return this.loadDataCore('loadFieldValues', { conid, database, schemaName, pureName, field, search });
},
callMethod_meta: true,
async callMethod({ conid, database, method, args }, req) {
testConnectionPermission(conid, req);
return this.loadDataCore('callMethod', { conid, database, method, args });
// const opened = await this.ensureOpened(conid, database);
// const res = await this.sendRequest(opened, { msgtype: 'callMethod', method, args });
// if (res.errorMessage) {
// console.error(res.errorMessage);
// }
// return res.result || null;
},
updateCollection_meta: true,
async updateCollection({ conid, database, changeSet }) {
async updateCollection({ conid, database, changeSet }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
return res.result;
if (res.errorMessage) {
return {
errorMessage: res.errorMessage,
};
}
return res.result || null;
},
status_meta: true,
async status({ conid, database }) {
async status({ conid, database }, req) {
if (!conid) {
return {
name: 'error',
message: 'No connection',
};
}
testConnectionPermission(conid, req);
const existing = this.opened.find(x => x.conid == conid && x.database == database);
if (existing) {
return {
@@ -181,7 +267,8 @@ module.exports = {
},
ping_meta: true,
async ping({ conid, database }) {
async ping({ conid, database }, req) {
testConnectionPermission(conid, req);
let existing = this.opened.find(x => x.conid == conid && x.database == database);
if (existing) {
@@ -197,7 +284,8 @@ module.exports = {
},
refresh_meta: true,
async refresh({ conid, database, keepOpen }) {
async refresh({ conid, database, keepOpen }, req) {
testConnectionPermission(conid, req);
if (!keepOpen) this.close(conid, database);
await this.ensureOpened(conid, database);
@@ -205,9 +293,10 @@ module.exports = {
},
syncModel_meta: true,
async syncModel({ conid, database }) {
async syncModel({ conid, database, isFullRefresh }, req) {
testConnectionPermission(conid, req);
const conn = await this.ensureOpened(conid, database);
conn.subprocess.send({ msgtype: 'syncModel' });
conn.subprocess.send({ msgtype: 'syncModel', isFullRefresh });
return { status: 'ok' };
},
@@ -228,14 +317,22 @@ module.exports = {
}
},
closeAll(conid, kill = true) {
for (const existing of this.opened.filter(x => x.conid == conid)) {
this.close(conid, existing.database, kill);
}
},
disconnect_meta: true,
async disconnect({ conid, database }) {
async disconnect({ conid, database }, req) {
testConnectionPermission(conid, req);
await this.close(conid, database, true);
return { status: 'ok' };
},
structure_meta: true,
async structure({ conid, database }) {
async structure({ conid, database }, req) {
testConnectionPermission(conid, req);
if (conid == '__model') {
const model = await importDbModel(database);
return model;
@@ -252,14 +349,19 @@ module.exports = {
},
serverVersion_meta: true,
async serverVersion({ conid, database }) {
async serverVersion({ conid, database }, req) {
if (!conid) {
return null;
}
testConnectionPermission(conid, req);
if (!conid) return null;
const opened = await this.ensureOpened(conid, database);
return opened.serverVersion || null;
},
sqlPreview_meta: true,
async sqlPreview({ conid, database, objects, options }) {
async sqlPreview({ conid, database, objects, options }, req) {
testConnectionPermission(conid, req);
// wait for structure
await this.structure({ conid, database });
@@ -269,7 +371,8 @@ module.exports = {
},
exportModel_meta: true,
async exportModel({ conid, database }) {
async exportModel({ conid, database }, req) {
testConnectionPermission(conid, req);
const archiveFolder = await archive.getNewArchiveFolder({ database });
await fs.mkdir(path.join(archivedir(), archiveFolder));
const model = await this.structure({ conid, database });
@@ -279,7 +382,8 @@ module.exports = {
},
generateDeploySql_meta: true,
async generateDeploySql({ conid, database, archiveFolder }) {
async generateDeploySql({ conid, database, archiveFolder }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid, database);
const res = await this.sendRequest(opened, {
msgtype: 'generateDeploySql',
@@ -325,8 +429,8 @@ module.exports = {
const targetDb = generateDbPairingId(
extendDatabaseInfo(await this.structure({ conid: targetConid, database: targetDatabase }))
);
// const sourceConnection = await connections.get({conid:sourceConid})
const connection = await connections.get({ conid: targetConid });
// const sourceConnection = await connections.getCore({conid:sourceConid})
const connection = await connections.getCore({ conid: targetConid });
const driver = requireEngineDriver(connection);
const targetDbPaired = matchPairedObjects(sourceDb, targetDb, dbDiffOptions);
const diffRows = computeDbDiffRows(sourceDb, targetDbPaired, dbDiffOptions, driver);
+67 -19
View File
@@ -3,11 +3,12 @@ const fs = require('fs-extra');
const path = require('path');
const { filesdir, archivedir, resolveArchiveFolder, uploadsdir, appdir } = require('../utility/directories');
const getChartExport = require('../utility/getChartExport');
const hasPermission = require('../utility/hasPermission');
const { hasPermission } = require('../utility/hasPermission');
const socket = require('../utility/socket');
const scheduler = require('./scheduler');
const getDiagramExport = require('../utility/getDiagramExport');
const apps = require('./apps');
const getMapExport = require('../utility/getMapExport');
function serialize(format, data) {
if (format == 'text') return data;
@@ -23,8 +24,8 @@ function deserialize(format, text) {
module.exports = {
list_meta: true,
async list({ folder }) {
if (!hasPermission(`files/${folder}/read`)) return [];
async list({ folder }, req) {
if (!hasPermission(`files/${folder}/read`, req)) return [];
const dir = path.join(filesdir(), folder);
if (!(await fs.exists(dir))) return [];
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
@@ -32,11 +33,11 @@ module.exports = {
},
listAll_meta: true,
async listAll() {
async listAll(_params, req) {
const folders = await fs.readdir(filesdir());
const res = [];
for (const folder of folders) {
if (!hasPermission(`files/${folder}/read`)) continue;
if (!hasPermission(`files/${folder}/read`, req)) continue;
const dir = path.join(filesdir(), folder);
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
res.push(...files);
@@ -45,31 +46,43 @@ module.exports = {
},
delete_meta: true,
async delete({ folder, file }) {
if (!hasPermission(`files/${folder}/write`)) return;
async delete({ folder, file }, req) {
if (!hasPermission(`files/${folder}/write`, req)) return false;
await fs.unlink(path.join(filesdir(), folder, file));
socket.emitChanged(`files-changed-${folder}`);
socket.emitChanged(`all-files-changed`);
return true;
},
rename_meta: true,
async rename({ folder, file, newFile }) {
if (!hasPermission(`files/${folder}/write`)) return;
async rename({ folder, file, newFile }, req) {
if (!hasPermission(`files/${folder}/write`, req)) return false;
await fs.rename(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
socket.emitChanged(`files-changed-${folder}`);
socket.emitChanged(`all-files-changed`);
return true;
},
refresh_meta: true,
async refresh({ folders }, req) {
for (const folder of folders) {
socket.emitChanged(`files-changed-${folder}`);
socket.emitChanged(`all-files-changed`);
}
return true;
},
copy_meta: true,
async copy({ folder, file, newFile }) {
if (!hasPermission(`files/${folder}/write`)) return;
async copy({ folder, file, newFile }, req) {
if (!hasPermission(`files/${folder}/write`, req)) return false;
await fs.copyFile(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
socket.emitChanged(`files-changed-${folder}`);
socket.emitChanged(`all-files-changed`);
return true;
},
load_meta: true,
async load({ folder, file, format }) {
async load({ folder, file, format }, req) {
if (folder.startsWith('archive:')) {
const text = await fs.readFile(path.join(resolveArchiveFolder(folder.substring('archive:'.length)), file), {
encoding: 'utf-8',
@@ -81,27 +94,36 @@ module.exports = {
});
return deserialize(format, text);
} else {
if (!hasPermission(`files/${folder}/read`)) return null;
if (!hasPermission(`files/${folder}/read`, req)) return null;
const text = await fs.readFile(path.join(filesdir(), folder, file), { encoding: 'utf-8' });
return deserialize(format, text);
}
},
loadFrom_meta: true,
async loadFrom({ filePath, format }, req) {
const text = await fs.readFile(filePath, { encoding: 'utf-8' });
return deserialize(format, text);
},
save_meta: true,
async save({ folder, file, data, format }) {
async save({ folder, file, data, format }, req) {
if (folder.startsWith('archive:')) {
if (!hasPermission(`archive/write`, req)) return false;
const dir = resolveArchiveFolder(folder.substring('archive:'.length));
await fs.writeFile(path.join(dir, file), serialize(format, data));
socket.emitChanged(`archive-files-changed-${folder.substring('archive:'.length)}`);
return true;
} else if (folder.startsWith('app:')) {
if (!hasPermission(`apps/write`, req)) return false;
const app = folder.substring('app:'.length);
await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
socket.emitChanged(`app-files-changed-${app}`);
socket.emitChanged('used-apps-changed');
apps.emitChangedDbApp(folder);
return true;
} else {
if (!hasPermission(`files/${folder}/write`)) return false;
if (!hasPermission(`files/${folder}/write`, req)) return false;
const dir = path.join(filesdir(), folder);
if (!(await fs.exists(dir))) {
await fs.mkdir(dir);
@@ -122,8 +144,8 @@ module.exports = {
},
favorites_meta: true,
async favorites() {
if (!hasPermission(`files/favorites/read`)) return [];
async favorites(_params, req) {
if (!hasPermission(`files/favorites/read`, req)) return [];
const dir = path.join(filesdir(), 'favorites');
if (!(await fs.exists(dir))) return [];
const files = await fs.readdir(dir);
@@ -141,8 +163,8 @@ module.exports = {
},
generateUploadsFile_meta: true,
async generateUploadsFile() {
const fileName = `${uuidv1()}.html`;
async generateUploadsFile({ extension }) {
const fileName = `${uuidv1()}.${extension || 'html'}`;
return {
fileName,
filePath: path.join(uploadsdir(), fileName),
@@ -166,9 +188,35 @@ module.exports = {
return true;
},
exportMap_meta: true,
async exportMap({ filePath, geoJson }) {
await fs.writeFile(filePath, getMapExport(geoJson));
return true;
},
exportDiagram_meta: true,
async exportDiagram({ filePath, html, css, themeType, themeClassName }) {
await fs.writeFile(filePath, getDiagramExport(html, css, themeType, themeClassName));
return true;
},
getFileRealPath_meta: true,
async getFileRealPath({ folder, file }, req) {
if (folder.startsWith('archive:')) {
if (!hasPermission(`archive/write`, req)) return false;
const dir = resolveArchiveFolder(folder.substring('archive:'.length));
return path.join(dir, file);
} else if (folder.startsWith('app:')) {
if (!hasPermission(`apps/write`, req)) return false;
const app = folder.substring('app:'.length);
return path.join(appdir(), app, file);
} else {
if (!hasPermission(`files/${folder}/write`, req)) return false;
const dir = path.join(filesdir(), folder);
if (!(await fs.exists(dir))) {
await fs.mkdir(dir);
}
return path.join(dir, file);
}
},
};
+28 -10
View File
@@ -1,3 +1,4 @@
const { filterName } = require('dbgate-tools');
const fs = require('fs');
const lineReader = require('line-reader');
const _ = require('lodash');
@@ -111,18 +112,22 @@ module.exports = {
getInfo_meta: true,
async getInfo({ jslid }) {
const file = getJslFileName(jslid);
const firstLine = await readFirstLine(file);
if (firstLine) {
const parsed = JSON.parse(firstLine);
if (parsed.__isStreamHeader) {
return parsed;
try {
const firstLine = await readFirstLine(file);
if (firstLine) {
const parsed = JSON.parse(firstLine);
if (parsed.__isStreamHeader) {
return parsed;
}
return {
__isStreamHeader: true,
__isDynamicStructure: true,
};
}
return {
__isStreamHeader: true,
__isDynamicStructure: true,
};
return null;
} catch (err) {
return null;
}
return null;
},
getRows_meta: true,
@@ -144,6 +149,19 @@ module.exports = {
return {};
},
loadFieldValues_meta: true,
async loadFieldValues({ jslid, field, search }) {
const datastore = await this.ensureDatastore(jslid);
const res = new Set();
await datastore.enumRows(row => {
if (!filterName(search, row[field])) return true;
res.add(row[field]);
return res.size < 100;
});
// @ts-ignore
return [...res].map(value => ({ value }));
},
async notifyChangedStats(stats) {
// console.log('SENDING STATS', JSON.stringify(stats));
const datastore = this.datastores[stats.jslid];
+19 -9
View File
@@ -7,7 +7,7 @@ const socket = require('../utility/socket');
const compareVersions = require('compare-versions');
const requirePlugin = require('../shell/requirePlugin');
const downloadPackage = require('../utility/downloadPackage');
const hasPermission = require('../utility/hasPermission');
const { hasPermission } = require('../utility/hasPermission');
const _ = require('lodash');
const packagedPluginsContent = require('../packagedPluginsContent');
@@ -73,7 +73,7 @@ module.exports = {
const res = [];
for (const packageName of _.union(files1, files2)) {
if (packageName == 'dist') continue;
// if (!/^dbgate-plugin-.*$/.test(packageName)) continue;
if (!/^dbgate-plugin-.*$/.test(packageName)) continue;
try {
if (packagedContent && packagedContent[packageName]) {
const manifest = {
@@ -89,6 +89,12 @@ module.exports = {
encoding: 'utf-8',
})
.then(x => JSON.parse(x));
if (!manifest.keywords) {
continue;
}
if (!manifest.keywords.includes('dbgateplugin')) {
continue;
}
const readmeFile = path.join(isPackaged ? packagedPluginsDir() : pluginsdir(), packageName, 'README.md');
// @ts-ignore
if (await fs.exists(readmeFile)) {
@@ -109,8 +115,8 @@ module.exports = {
// },
install_meta: true,
async install({ packageName }) {
if (!hasPermission(`plugins/install`)) return;
async install({ packageName }, req) {
if (!hasPermission(`plugins/install`, req)) return;
const dir = path.join(pluginsdir(), packageName);
// @ts-ignore
if (!(await fs.exists(dir))) {
@@ -119,21 +125,23 @@ module.exports = {
socket.emitChanged(`installed-plugins-changed`);
// this.removedPlugins = this.removedPlugins.filter(x => x != packageName);
// await this.saveRemovePlugins();
return true;
},
uninstall_meta: true,
async uninstall({ packageName }) {
if (!hasPermission(`plugins/install`)) return;
async uninstall({ packageName }, req) {
if (!hasPermission(`plugins/install`, req)) return;
const dir = path.join(pluginsdir(), packageName);
await fs.rmdir(dir, { recursive: true });
socket.emitChanged(`installed-plugins-changed`);
// this.removedPlugins.push(packageName);
await this.saveRemovePlugins();
// await this.saveRemovePlugins();
return true;
},
upgrade_meta: true,
async upgrade({ packageName }) {
if (!hasPermission(`plugins/install`)) return;
async upgrade({ packageName }, req) {
if (!hasPermission(`plugins/install`, req)) return;
const dir = path.join(pluginsdir(), packageName);
// @ts-ignore
if (await fs.exists(dir)) {
@@ -142,6 +150,7 @@ module.exports = {
}
socket.emitChanged(`installed-plugins-changed`);
return true;
},
command_meta: true,
@@ -153,6 +162,7 @@ module.exports = {
authTypes_meta: true,
async authTypes({ engine }) {
const packageName = extractPackageName(engine);
if (!packageName) return null;
const content = requirePlugin(packageName);
const driver = content.drivers.find(x => x.engine == engine);
if (!driver || !driver.getAuthTypes) return null;
+14 -2
View File
@@ -6,9 +6,10 @@ const byline = require('byline');
const socket = require('../utility/socket');
const { fork } = require('child_process');
const { rundir, uploadsdir, pluginsdir, getPluginBackendPath, packagedPluginList } = require('../utility/directories');
const { extractShellApiPlugins, extractShellApiFunctionName } = require('dbgate-tools');
const { extractShellApiPlugins, extractShellApiFunctionName, jsonScriptToJavascript } = require('dbgate-tools');
const { handleProcessCommunication } = require('../utility/processComm');
const processArgs = require('../utility/processArgs');
const platformInfo = require('../utility/platformInfo');
function extractPlugins(script) {
const requireRegex = /\s*\/\/\s*@require\s+([^\s]+)\s*\n/g;
@@ -103,6 +104,7 @@ module.exports = {
scriptFile,
[
'--checkParent', // ...process.argv.slice(3)
'--is-forked-api',
...processArgs.getPassArgs(),
],
{
@@ -110,7 +112,7 @@ module.exports = {
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
env: {
...process.env,
DBGATE_API: global['API_PACKAGE'] || global['dbgateApiModulePath'] || process.argv[1],
DBGATE_API: global['API_PACKAGE'] || process.argv[1],
..._.fromPairs(pluginNames.map(name => [`PLUGIN_${_.camelCase(name)}`, getPluginBackendPath(name)])),
},
}
@@ -150,6 +152,16 @@ module.exports = {
start_meta: true,
async start({ script }) {
const runid = uuidv1();
if (script.type == 'json') {
const js = jsonScriptToJavascript(script);
return this.startCore(runid, scriptTemplate(js, false));
}
if (!platformInfo.allowShellScripting) {
return { errorMessage: 'Shell scripting is not allowed' };
}
return this.startCore(runid, scriptTemplate(script, false));
},
+3 -3
View File
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
const path = require('path');
const cron = require('node-cron');
const runners = require('./runners');
const hasPermission = require('../utility/hasPermission');
const { hasPermission } = require('../utility/hasPermission');
const scheduleRegex = /\s*\/\/\s*@schedule\s+([^\n]+)\n/;
@@ -26,8 +26,8 @@ module.exports = {
this.tasks.push(task);
},
async reload() {
if (!hasPermission('files/shell/read')) return;
async reload(_params, req) {
if (!hasPermission('files/shell/read', req)) return;
const shellDir = path.join(filesdir(), 'shell');
await this.unload();
if (!(await fs.exists(shellDir))) return;
@@ -7,6 +7,7 @@ const { handleProcessCommunication } = require('../utility/processComm');
const lock = new AsyncLock();
const config = require('./config');
const processArgs = require('../utility/processArgs');
const { testConnectionPermission } = require('../utility/hasPermission');
module.exports = {
opened: [],
@@ -37,7 +38,7 @@ module.exports = {
const res = await lock.acquire(conid, async () => {
const existing = this.opened.find(x => x.conid == conid);
if (existing) return existing;
const connection = await connections.get({ conid });
const connection = await connections.getCore({ conid });
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
'--is-forked-api',
'--start-process',
@@ -90,19 +91,22 @@ module.exports = {
},
disconnect_meta: true,
async disconnect({ conid }) {
async disconnect({ conid }, req) {
testConnectionPermission(conid, req);
await this.close(conid, true);
return { status: 'ok' };
},
listDatabases_meta: true,
async listDatabases({ conid }) {
async listDatabases({ conid }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid);
return opened.databases;
},
version_meta: true,
async version({ conid }) {
async version({ conid }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid);
return opened.version;
},
@@ -132,7 +136,8 @@ module.exports = {
},
refresh_meta: true,
async refresh({ conid, keepOpen }) {
async refresh({ conid, keepOpen }, req) {
testConnectionPermission(conid, req);
if (!keepOpen) this.close(conid);
await this.ensureOpened(conid);
@@ -140,9 +145,20 @@ module.exports = {
},
createDatabase_meta: true,
async createDatabase({ conid, name }) {
async createDatabase({ conid, name }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid);
if (opened.connection.isReadOnly) return false;
opened.subprocess.send({ msgtype: 'createDatabase', name });
return { status: 'ok' };
},
dropDatabase_meta: true,
async dropDatabase({ conid, name }, req) {
testConnectionPermission(conid, req);
const opened = await this.ensureOpened(conid);
if (opened.connection.isReadOnly) return false;
opened.subprocess.send({ msgtype: 'dropDatabase', name });
return { status: 'ok' };
},
};
+59 -3
View File
@@ -4,8 +4,10 @@ const connections = require('./connections');
const socket = require('../utility/socket');
const { fork } = require('child_process');
const jsldata = require('./jsldata');
const path = require('path');
const { handleProcessCommunication } = require('../utility/processComm');
const processArgs = require('../utility/processArgs');
const { appdir } = require('../utility/directories');
module.exports = {
/** @type {import('dbgate-types').OpenedSession[]} */
@@ -46,9 +48,18 @@ module.exports = {
this.dispatchMessage(sesid, info);
},
handle_done(sesid) {
handle_done(sesid, props) {
socket.emit(`session-done-${sesid}`);
this.dispatchMessage(sesid, 'Query execution finished');
if (!props.skipFinishedMessage) {
this.dispatchMessage(sesid, 'Query execution finished');
}
const session = this.opened.find(x => x.sesid == sesid);
if (session.loadingReader_jslid) {
socket.emit(`session-jslid-done-${session.loadingReader_jslid}`);
}
if (session.killOnDone) {
this.kill({ sesid });
}
},
handle_recordset(sesid, props) {
@@ -60,12 +71,17 @@ module.exports = {
jsldata.notifyChangedStats(stats);
},
handle_initializeFile(sesid, props) {
const { jslid } = props;
socket.emit(`session-initialize-file-${jslid}`);
},
handle_ping() {},
create_meta: true,
async create({ conid, database }) {
const sesid = uuidv1();
const connection = await connections.get({ conid });
const connection = await connections.getCore({ conid });
const subprocess = fork(global['API_PACKAGE'] || process.argv[1], [
'--is-forked-api',
'--start-process',
@@ -87,6 +103,12 @@ module.exports = {
if (handleProcessCommunication(message, subprocess)) return;
this[`handle_${msgtype}`](sesid, message);
});
subprocess.on('exit', () => {
this.opened = this.opened.filter(x => x.sesid != sesid);
this.dispatchMessage(sesid, 'Query session closed');
socket.emit(`session-closed-${sesid}`);
});
subprocess.send({ msgtype: 'connect', ...connection, database });
return _.pick(newOpened, ['conid', 'database', 'sesid']);
},
@@ -105,6 +127,29 @@ module.exports = {
return { state: 'ok' };
},
executeReader_meta: true,
async executeReader({ conid, database, sql, queryName, appFolder }) {
const { sesid } = await this.create({ conid, database });
const session = this.opened.find(x => x.sesid == sesid);
session.killOnDone = true;
const jslid = uuidv1();
session.loadingReader_jslid = jslid;
const fileName = queryName && appFolder ? path.join(appdir(), appFolder, `${queryName}.query.sql`) : null;
session.subprocess.send({ msgtype: 'executeReader', sql, fileName, jslid });
return { jslid };
},
stopLoadingReader_meta: true,
async stopLoadingReader({ jslid }) {
const session = this.opened.find(x => x.loadingReader_jslid == jslid);
if (session) {
this.kill({ sesid: session.sesid });
}
return true;
},
// cancel_meta: true,
// async cancel({ sesid }) {
// const session = this.opened.find((x) => x.sesid == sesid);
@@ -126,6 +171,17 @@ module.exports = {
return { state: 'ok' };
},
ping_meta: true,
async ping({ sesid }) {
const session = this.opened.find(x => x.sesid == sesid);
if (!session) {
throw new Error('Invalid session');
}
session.subprocess.send({ msgtype: 'ping' });
return { state: 'ok' };
},
// runCommand_meta: true,
// async runCommand({ conid, database, sql }) {
// console.log(`Running SQL command , conid=${conid}, database=${database}, sql=${sql}`);
+1 -1
View File
@@ -1,5 +1,5 @@
module.exports = {
version: '4.1.1',
version: '5.0.0-alpha.1',
buildTime: '2021-04-17T07:22:49.702Z'
};
+3 -2
View File
@@ -8,9 +8,10 @@ if (processArgs.startProcess) {
const proc = require('./proc');
const module = proc[processArgs.startProcess];
module.start();
} else if (!processArgs.checkParent && !global['API_PACKAGE'] && !global['dbgateApiModulePath']) {
const main = require('./main');
}
if (processArgs.listenApi) {
const main = require('./main');
main.start();
}
+43 -19
View File
@@ -20,15 +20,19 @@ const jsldata = require('./controllers/jsldata');
const config = require('./controllers/config');
const archive = require('./controllers/archive');
const apps = require('./controllers/apps');
const auth = require('./controllers/auth');
const uploads = require('./controllers/uploads');
const plugins = require('./controllers/plugins');
const files = require('./controllers/files');
const scheduler = require('./controllers/scheduler');
const queryHistory = require('./controllers/queryHistory');
const onFinished = require('on-finished');
const { rundir } = require('./utility/directories');
const platformInfo = require('./utility/platformInfo');
const getExpressPath = require('./utility/getExpressPath');
const { getLogins } = require('./utility/hasPermission');
const _ = require('lodash');
function start() {
// console.log('process.argv', process.argv);
@@ -37,12 +41,11 @@ function start() {
const server = http.createServer(app);
if (process.env.LOGIN && process.env.PASSWORD) {
const logins = getLogins();
if (logins && process.env.BASIC_AUTH) {
app.use(
basicAuth({
users: {
[process.env.LOGIN]: process.env.PASSWORD,
},
users: _.fromPairs(logins.map(x => [x.login, x.password])),
challenge: true,
realm: 'DbGate Web App',
})
@@ -51,6 +54,10 @@ function start() {
app.use(cors());
if (auth.shouldAuthorizeApi()) {
app.use(auth.authMiddleware);
}
app.get(getExpressPath('/stream'), async function (req, res) {
res.set({
'Cache-Control': 'no-cache',
@@ -62,7 +69,10 @@ function start() {
// Tell the client to retry every 10 seconds if connectivity is lost
res.write('retry: 10000\n\n');
socket.setSseResponse(res);
socket.addSseResponse(res);
onFinished(req, () => {
socket.removeSseResponse(res);
});
});
app.use(bodyParser.json({ limit: '50mb' }));
@@ -85,24 +95,37 @@ function start() {
if (platformInfo.isDocker) {
// server static files inside docker container
app.use(getExpressPath('/'), express.static('/home/dbgate-docker/public'));
} else {
if (!platformInfo.isNpmDist) {
app.get(getExpressPath('/'), (req, res) => {
res.send('DbGate API');
});
}
}
if (platformInfo.isNpmDist) {
const port = process.env.PORT || 3000;
console.log('DbGate API listening on port (docker build)', port);
server.listen(port);
} else if (platformInfo.isNpmDist) {
app.use(getExpressPath('/'), express.static(path.join(__dirname, '../../dbgate-web/public')));
getPort({ port: 5000 }).then(port => {
getPort({
port: parseInt(
// @ts-ignore
process.env.PORT || 3000
),
}).then(port => {
server.listen(port, () => {
console.log(`DbGate API listening on port ${port}`);
console.log(`DbGate API listening on port ${port} (NPM build)`);
});
});
} else {
} else if (process.env.DEVWEB) {
console.log('__dirname', __dirname);
console.log(path.join(__dirname, '../../web/public/build'));
app.use(getExpressPath('/'), express.static(path.join(__dirname, '../../web/public')));
const port = process.env.PORT || 3000;
console.log('DbGate API listening on port', port);
console.log('DbGate API & web listening on port (dev web build)', port);
server.listen(port);
} else {
app.get(getExpressPath('/'), (req, res) => {
res.send('DbGate API');
});
const port = process.env.PORT || 3000;
console.log('DbGate API listening on port (dev API build)', port);
server.listen(port);
}
@@ -139,10 +162,11 @@ function useAllControllers(app, electron) {
useController(app, electron, '/scheduler', scheduler);
useController(app, electron, '/query-history', queryHistory);
useController(app, electron, '/apps', apps);
useController(app, electron, '/auth', auth);
}
function initializeElectronSender(electronSender) {
function setElectronSender(electronSender) {
socket.setElectronSender(electronSender);
}
module.exports = { start, useAllControllers, initializeElectronSender, configController: config };
module.exports = { start, useAllControllers, setElectronSender, configController: config };
+1 -1
View File
@@ -20,7 +20,7 @@ function start() {
if (handleProcessCommunication(connection)) return;
try {
const driver = requireEngineDriver(connection);
const conn = await connectUtility(driver, connection);
const conn = await connectUtility(driver, connection, 'app');
const res = await driver.getVersion(conn);
process.send({ msgtype: 'connected', ...res });
} catch (e) {
@@ -7,6 +7,7 @@ const connectUtility = require('../utility/connectUtility');
const { handleProcessCommunication } = require('../utility/processComm');
const { SqlGenerator } = require('dbgate-tools');
const generateDeploySql = require('../shell/generateDeploySql');
const { dumpSqlSelect } = require('dbgate-sqltree');
let systemConnection;
let storedConnection;
@@ -14,6 +15,7 @@ let afterConnectCallbacks = [];
let afterAnalyseCallbacks = [];
let analysedStructure = null;
let lastPing = null;
let lastStatusString = null;
let lastStatus = null;
let analysedTime = 0;
let serverVersion;
@@ -77,21 +79,24 @@ async function handleIncrementalRefresh(forceSend) {
resolveAnalysedPromises();
}
function handleSyncModel() {
function handleSyncModel({ isFullRefresh }) {
if (loadingModel) return;
handleIncrementalRefresh();
if (isFullRefresh) handleFullRefresh();
else handleIncrementalRefresh();
}
function setStatus(status) {
const statusString = stableStringify(status);
if (lastStatus != statusString) {
process.send({ msgtype: 'status', status: { ...status, counter: getStatusCounter() } });
lastStatus = statusString;
const newStatus = { ...lastStatus, ...status };
const statusString = stableStringify(newStatus);
if (lastStatusString != statusString) {
process.send({ msgtype: 'status', status: { ...newStatus, counter: getStatusCounter() } });
lastStatusString = statusString;
lastStatus = newStatus;
}
}
function setStatusName(name) {
setStatus({ name });
setStatus({ name, message: null });
}
async function readVersion() {
@@ -107,7 +112,8 @@ async function handleConnect({ connection, structure, globalSettings }) {
if (!structure) setStatusName('pending');
const driver = requireEngineDriver(storedConnection);
systemConnection = await checkedAsyncCall(connectUtility(driver, storedConnection));
systemConnection = await checkedAsyncCall(connectUtility(driver, storedConnection, 'app'));
systemConnection.feedback = feedback => setStatus({ feedback });
await checkedAsyncCall(readVersion());
if (structure) {
analysedStructure = structure;
@@ -150,10 +156,11 @@ function resolveAnalysedPromises() {
afterAnalyseCallbacks = [];
}
async function handleRunScript({ msgid, sql }) {
async function handleRunScript({ msgid, sql }, skipReadonlyCheck = false) {
await waitConnected();
const driver = requireEngineDriver(storedConnection);
try {
if (!skipReadonlyCheck) ensureExecuteCustomScript(driver);
await driver.script(systemConnection, sql);
process.send({ msgtype: 'response', msgid });
} catch (err) {
@@ -161,25 +168,80 @@ async function handleRunScript({ msgid, sql }) {
}
}
async function handleQueryData({ msgid, sql }) {
async function handleQueryData({ msgid, sql }, skipReadonlyCheck = false) {
await waitConnected();
const driver = requireEngineDriver(storedConnection);
try {
if (!skipReadonlyCheck) ensureExecuteCustomScript(driver);
// console.log(sql);
const res = await driver.query(systemConnection, sql);
process.send({ msgtype: 'response', msgid, ...res });
} catch (err) {
process.send({ msgtype: 'response', msgid, errorMessage: err.message || 'Error executing SQL script' });
}
}
async function handleSqlSelect({ msgid, select }) {
const driver = requireEngineDriver(storedConnection);
const dmp = driver.createDumper();
dumpSqlSelect(dmp, select);
return handleQueryData({ msgid, sql: dmp.s }, true);
}
async function handleDriverDataCore(msgid, callMethod) {
await waitConnected();
const driver = requireEngineDriver(storedConnection);
try {
const result = await callMethod(driver);
process.send({ msgtype: 'response', msgid, result });
} catch (err) {
process.send({ msgtype: 'response', msgid, errorMessage: err.message });
}
}
async function handleCollectionData({ msgid, options }) {
await waitConnected();
const driver = requireEngineDriver(storedConnection);
try {
const result = await driver.readCollection(systemConnection, options);
process.send({ msgtype: 'response', msgid, result });
} catch (err) {
process.send({ msgtype: 'response', msgid, errorMessage: err.message });
return handleDriverDataCore(msgid, driver => driver.readCollection(systemConnection, options));
}
async function handleLoadKeys({ msgid, root, filter }) {
return handleDriverDataCore(msgid, driver => driver.loadKeys(systemConnection, root, filter));
}
async function handleExportKeys({ msgid, options }) {
return handleDriverDataCore(msgid, driver => driver.exportKeys(systemConnection, options));
}
async function handleLoadKeyInfo({ msgid, key }) {
return handleDriverDataCore(msgid, driver => driver.loadKeyInfo(systemConnection, key));
}
async function handleCallMethod({ msgid, method, args }) {
return handleDriverDataCore(msgid, driver => {
if (storedConnection.isReadOnly) {
throw new Error('Connection is read only, cannot call custom methods');
}
ensureExecuteCustomScript(driver);
return driver.callMethod(systemConnection, method, args);
});
}
async function handleLoadKeyTableRange({ msgid, key, cursor, count }) {
return handleDriverDataCore(msgid, driver => driver.loadKeyTableRange(systemConnection, key, cursor, count));
}
async function handleLoadFieldValues({ msgid, schemaName, pureName, field, search }) {
return handleDriverDataCore(msgid, driver =>
driver.loadFieldValues(systemConnection, { schemaName, pureName }, field, search)
);
}
function ensureExecuteCustomScript(driver) {
if (driver.readOnlySessions) {
return;
}
if (storedConnection.isReadOnly) {
throw new Error('Connection is read only');
}
}
@@ -187,6 +249,7 @@ async function handleUpdateCollection({ msgid, changeSet }) {
await waitConnected();
const driver = requireEngineDriver(storedConnection);
try {
ensureExecuteCustomScript(driver);
const result = await driver.updateCollection(systemConnection, changeSet);
process.send({ msgtype: 'response', msgid, result });
} catch (err) {
@@ -248,10 +311,17 @@ const messageHandlers = {
runScript: handleRunScript,
updateCollection: handleUpdateCollection,
collectionData: handleCollectionData,
loadKeys: handleLoadKeys,
loadKeyInfo: handleLoadKeyInfo,
callMethod: handleCallMethod,
loadKeyTableRange: handleLoadKeyTableRange,
sqlPreview: handleSqlPreview,
ping: handlePing,
syncModel: handleSyncModel,
generateDeploySql: handleGenerateDeploySql,
loadFieldValues: handleLoadFieldValues,
sqlSelect: handleSqlSelect,
exportKeys: handleExportKeys,
// runCommand: handleRunCommand,
};
@@ -265,11 +335,11 @@ function start() {
setInterval(() => {
const time = new Date().getTime();
if (time - lastPing > 120 * 1000) {
if (time - lastPing > 40 * 1000) {
console.log('Database connection not alive, exiting');
process.exit(0);
}
}, 60 * 1000);
}, 10 * 1000);
process.on('message', async message => {
if (handleProcessCommunication(message)) return;
+2
View File
@@ -3,6 +3,7 @@ const databaseConnectionProcess = require('./databaseConnectionProcess');
const serverConnectionProcess = require('./serverConnectionProcess');
const sessionProcess = require('./sessionProcess');
const jslDatastoreProcess = require('./jslDatastoreProcess');
const sshForwardProcess = require('./sshForwardProcess');
module.exports = {
connectProcess,
@@ -10,4 +11,5 @@ module.exports = {
serverConnectionProcess,
sessionProcess,
jslDatastoreProcess,
sshForwardProcess,
};
@@ -2,7 +2,6 @@ const stableStringify = require('json-stable-stringify');
const { extractBoolSettingsValue, extractIntSettingsValue } = require('dbgate-tools');
const childProcessChecker = require('../utility/childProcessChecker');
const requireEngineDriver = require('../utility/requireEngineDriver');
const { decryptConnection } = require('../utility/crypting');
const connectUtility = require('../utility/connectUtility');
const { handleProcessCommunication } = require('../utility/processComm');
@@ -58,11 +57,14 @@ async function handleConnect(connection) {
const driver = requireEngineDriver(storedConnection);
try {
systemConnection = await connectUtility(driver, storedConnection);
systemConnection = await connectUtility(driver, storedConnection, 'app');
readVersion();
handleRefresh();
if (extractBoolSettingsValue(globalSettings, 'connection.autoRefresh', false)) {
setInterval(handleRefresh, extractIntSettingsValue(globalSettings, 'connection.autoRefreshInterval', 30, 5, 3600) * 1000);
setInterval(
handleRefresh,
extractIntSettingsValue(globalSettings, 'connection.autoRefreshInterval', 30, 5, 3600) * 1000
);
}
} catch (err) {
setStatus({
@@ -78,14 +80,16 @@ function handlePing() {
lastPing = new Date().getTime();
}
async function handleCreateDatabase({ name }) {
async function handleDatabaseOp(op, { name }) {
const driver = requireEngineDriver(storedConnection);
systemConnection = await connectUtility(driver, storedConnection);
console.log(`RUNNING SCRIPT: CREATE DATABASE ${driver.dialect.quoteIdentifier(name)}`);
if (driver.createDatabase) {
await driver.createDatabase(systemConnection, name);
systemConnection = await connectUtility(driver, storedConnection, 'app');
if (driver[op]) {
await driver[op](systemConnection, name);
} else {
await driver.query(systemConnection, `CREATE DATABASE ${driver.dialect.quoteIdentifier(name)}`);
const dmp = driver.createDumper();
dmp[op](name);
console.log(`RUNNING SCRIPT: ${dmp.s}`);
await driver.query(systemConnection, dmp.s);
}
await handleRefresh();
}
@@ -93,7 +97,8 @@ async function handleCreateDatabase({ name }) {
const messageHandlers = {
connect: handleConnect,
ping: handlePing,
createDatabase: handleCreateDatabase,
createDatabase: props => handleDatabaseOp('createDatabase', props),
dropDatabase: props => handleDatabaseOp('dropDatabase', props),
};
async function handleMessage({ msgtype, ...other }) {
@@ -106,11 +111,11 @@ function start() {
setInterval(() => {
const time = new Date().getTime();
if (time - lastPing > 120 * 1000) {
if (time - lastPing > 40 * 1000) {
console.log('Server connection not alive, exiting');
process.exit(0);
}
}, 60 * 1000);
}, 10 * 1000);
process.on('message', async message => {
if (handleProcessCommunication(message)) return;
+125 -12
View File
@@ -15,13 +15,18 @@ let systemConnection;
let storedConnection;
let afterConnectCallbacks = [];
// let currentHandlers = [];
let lastPing = null;
class TableWriter {
constructor(structure, resultIndex) {
this.jslid = uuidv1();
this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
constructor() {
this.currentRowCount = 0;
this.currentChangeIndex = 1;
this.initializedFile = false;
}
initializeFromQuery(structure, resultIndex) {
this.jslid = uuidv1();
this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
fs.writeFileSync(
this.currentFile,
JSON.stringify({
@@ -32,13 +37,21 @@ class TableWriter {
this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' });
this.writeCurrentStats(false, false);
this.resultIndex = resultIndex;
this.initializedFile = true;
process.send({ msgtype: 'recordset', jslid: this.jslid, resultIndex });
}
initializeFromReader(jslid) {
this.jslid = jslid;
this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
this.writeCurrentStats(false, false);
}
row(row) {
// console.log('ACCEPT ROW', row);
this.currentStream.write(JSON.stringify(row) + '\n');
this.currentRowCount += 1;
if (!this.plannedStats) {
this.plannedStats = true;
process.nextTick(() => {
@@ -49,6 +62,21 @@ class TableWriter {
}
}
rowFromReader(row) {
if (!this.initializedFile) {
process.send({ msgtype: 'initializeFile', jslid: this.jslid });
this.initializedFile = true;
fs.writeFileSync(this.currentFile, JSON.stringify(row) + '\n');
this.currentStream = fs.createWriteStream(this.currentFile, { flags: 'a' });
this.writeCurrentStats(false, false);
this.initializedFile = true;
return;
}
this.row(row);
}
writeCurrentStats(isFinished = false, emitEvent = false) {
const stats = {
rowCount: this.currentRowCount,
@@ -63,18 +91,20 @@ class TableWriter {
}
}
close() {
close(afterClose) {
if (this.currentStream) {
this.currentStream.end(() => {
this.writeCurrentStats(true, true);
if (afterClose) afterClose();
});
}
}
}
class StreamHandler {
constructor(resultIndexHolder, resolve) {
constructor(resultIndexHolder, resolve, startLine) {
this.recordset = this.recordset.bind(this);
this.startLine = startLine;
this.row = this.row.bind(this);
// this.error = this.error.bind(this);
this.done = this.done.bind(this);
@@ -98,7 +128,11 @@ class StreamHandler {
recordset(columns) {
this.closeCurrentWriter();
this.currentWriter = new TableWriter(Array.isArray(columns) ? { columns } : columns, this.resultIndexHolder.value);
this.currentWriter = new TableWriter();
this.currentWriter.initializeFromQuery(
Array.isArray(columns) ? { columns } : columns,
this.resultIndexHolder.value
);
this.resultIndexHolder.value += 1;
// this.writeCurrentStats();
@@ -110,7 +144,6 @@ class StreamHandler {
// }, 500);
}
row(row) {
// console.log('ACCEPT ROW', row);
if (this.currentWriter) this.currentWriter.row(row);
else if (row.message) process.send({ msgtype: 'info', info: { message: row.message } });
// this.onRow(this.jslid);
@@ -124,22 +157,40 @@ class StreamHandler {
this.resolve();
}
info(info) {
if (info && info.line != null) {
info = {
...info,
line: this.startLine + info.line,
};
}
process.send({ msgtype: 'info', info });
}
}
function handleStream(driver, resultIndexHolder, sql) {
function handleStream(driver, resultIndexHolder, sqlItem) {
return new Promise((resolve, reject) => {
const handler = new StreamHandler(resultIndexHolder, resolve);
driver.stream(systemConnection, sql, handler);
const start = sqlItem.trimStart || sqlItem.start;
const handler = new StreamHandler(resultIndexHolder, resolve, start && start.line);
driver.stream(systemConnection, sqlItem.text, handler);
});
}
function allowExecuteCustomScript(driver) {
if (driver.readOnlySessions) {
return true;
}
if (storedConnection.isReadOnly) {
return false;
// throw new Error('Connection is read only');
}
return true;
}
async function handleConnect(connection) {
storedConnection = connection;
const driver = requireEngineDriver(storedConnection);
systemConnection = await connectUtility(driver, storedConnection);
systemConnection = await connectUtility(driver, storedConnection, 'app');
for (const [resolve] of afterConnectCallbacks) {
resolve();
}
@@ -163,10 +214,26 @@ async function handleExecuteQuery({ sql }) {
await waitConnected();
const driver = requireEngineDriver(storedConnection);
if (!allowExecuteCustomScript(driver)) {
process.send({
msgtype: 'info',
info: {
message: 'Connection without read-only sessions is read only',
severity: 'error',
},
});
process.send({ msgtype: 'done', skipFinishedMessage: true });
return;
//process.send({ msgtype: 'error', error: e.message });
}
const resultIndexHolder = {
value: 0,
};
for (const sqlItem of splitQuery(sql, driver.getQuerySplitterOptions('stream'))) {
for (const sqlItem of splitQuery(sql, {
...driver.getQuerySplitterOptions('stream'),
returnRichInfo: true,
})) {
await handleStream(driver, resultIndexHolder, sqlItem);
// const handler = new StreamHandler(resultIndex);
// const stream = await driver.stream(systemConnection, sqlItem, handler);
@@ -176,9 +243,44 @@ async function handleExecuteQuery({ sql }) {
process.send({ msgtype: 'done' });
}
async function handleExecuteReader({ jslid, sql, fileName }) {
await waitConnected();
const driver = requireEngineDriver(storedConnection);
if (fileName) {
sql = fs.readFileSync(fileName, 'utf-8');
} else {
if (!allowExecuteCustomScript(driver)) {
process.send({ msgtype: 'done' });
return;
}
}
const writer = new TableWriter();
writer.initializeFromReader(jslid);
const reader = await driver.readQuery(systemConnection, sql);
reader.on('data', data => {
writer.rowFromReader(data);
});
reader.on('end', () => {
writer.close(() => {
process.send({ msgtype: 'done' });
});
});
}
function handlePing() {
lastPing = new Date().getTime();
}
const messageHandlers = {
connect: handleConnect,
executeQuery: handleExecuteQuery,
executeReader: handleExecuteReader,
ping: handlePing,
// cancel: handleCancel,
};
@@ -189,6 +291,17 @@ async function handleMessage({ msgtype, ...other }) {
function start() {
childProcessChecker();
lastPing = new Date().getTime();
setInterval(() => {
const time = new Date().getTime();
if (time - lastPing > 25 * 1000) {
console.log('Session not alive, exiting');
process.exit(0);
}
}, 10 * 1000);
process.on('message', async message => {
if (handleProcessCommunication(message)) return;
try {
@@ -0,0 +1,70 @@
const fs = require('fs-extra');
const platformInfo = require('../utility/platformInfo');
const childProcessChecker = require('../utility/childProcessChecker');
const { handleProcessCommunication } = require('../utility/processComm');
const { SSHConnection } = require('../utility/SSHConnection');
async function getSshConnection(connection) {
const sshConfig = {
endHost: connection.sshHost || '',
endPort: connection.sshPort || 22,
bastionHost: connection.sshBastionHost || '',
agentForward: connection.sshMode == 'agent',
passphrase: connection.sshMode == 'keyFile' ? connection.sshKeyfilePassword : undefined,
username: connection.sshLogin,
password: connection.sshMode == 'userPassword' ? connection.sshPassword : undefined,
agentSocket: connection.sshMode == 'agent' ? platformInfo.sshAuthSock : undefined,
privateKey:
connection.sshMode == 'keyFile' && connection.sshKeyfile ? await fs.readFile(connection.sshKeyfile) : undefined,
skipAutoPrivateKey: true,
noReadline: true,
};
const sshConn = new SSHConnection(sshConfig);
return sshConn;
}
async function handleStart({ connection, tunnelConfig }) {
try {
const sshConn = await getSshConnection(connection);
await sshConn.forward(tunnelConfig);
process.send({
msgtype: 'connected',
connection,
tunnelConfig,
});
} catch (err) {
console.log('Error creating SSH tunnel connection:', err.message);
process.send({
msgtype: 'error',
connection,
tunnelConfig,
errorMessage: err.message,
});
}
}
const messageHandlers = {
connect: handleStart,
};
async function handleMessage({ msgtype, ...other }) {
const handler = messageHandlers[msgtype];
await handler(other);
}
function start() {
childProcessChecker();
process.on('message', async message => {
if (handleProcessCommunication(message)) return;
try {
await handleMessage(message);
} catch (e) {
console.error('sshForwardProcess - unhandled error', e);
}
});
}
module.exports = { start };
+36 -7
View File
@@ -1,18 +1,47 @@
const EnsureStreamHeaderStream = require('../utility/EnsureStreamHeaderStream');
const Stream = require('stream');
const ColumnMapTransformStream = require('../utility/ColumnMapTransformStream');
function copyStream(input, output, options) {
const { columns } = options || {};
const transforms = [];
if (columns) {
transforms.push(new ColumnMapTransformStream(columns));
}
if (output.requireFixedStructure) {
transforms.push(new EnsureStreamHeaderStream());
}
// return new Promise((resolve, reject) => {
// Stream.pipeline(input, ...transforms, output, err => {
// if (err) {
// reject(err);
// } else {
// resolve();
// }
// });
// });
function copyStream(input, output) {
return new Promise((resolve, reject) => {
const finisher = output['finisher'] || output;
finisher.on('finish', resolve);
finisher.on('error', reject);
if (output.requireFixedStructure) {
const ensureHeader = new EnsureStreamHeaderStream();
input.pipe(ensureHeader);
ensureHeader.pipe(output);
} else {
input.pipe(output);
let lastStream = input;
for (const tran of transforms) {
lastStream.pipe(tran);
lastStream = tran;
}
lastStream.pipe(output);
// if (output.requireFixedStructure) {
// const ensureHeader = new EnsureStreamHeaderStream();
// input.pipe(ensureHeader);
// ensureHeader.pipe(output);
// } else {
// input.pipe(output);
// }
});
}
+38
View File
@@ -0,0 +1,38 @@
const requireEngineDriver = require('../utility/requireEngineDriver');
const connectUtility = require('../utility/connectUtility');
function doDump(dumper) {
return new Promise((resolve, reject) => {
dumper.once('end', () => {
resolve(true);
});
dumper.once('error', err => {
reject(err);
});
dumper.run();
});
}
async function dumpDatabase({
connection = undefined,
systemConnection = undefined,
driver = undefined,
outputFile,
databaseName,
schemaName,
}) {
console.log(`Dumping database`);
if (!driver) driver = requireEngineDriver(connection);
const pool = systemConnection || (await connectUtility(driver, connection, 'read', { forceRowsAsObjects: true }));
console.log(`Connected.`);
const dumper = await driver.createBackupDumper(pool, {
outputFile,
databaseName,
schemaName,
});
await doDump(dumper);
}
module.exports = dumpDatabase;
+1 -1
View File
@@ -5,7 +5,7 @@ async function executeQuery({ connection = undefined, systemConnection = undefin
console.log(`Execute query ${sql}`);
if (!driver) driver = requireEngineDriver(connection);
const pool = systemConnection || (await connectUtility(driver, connection));
const pool = systemConnection || (await connectUtility(driver, connection, 'script'));
console.log(`Connected.`);
await driver.script(pool, sql);
+1 -1
View File
@@ -21,7 +21,7 @@ async function generateDeploySql({
}) {
if (!driver) driver = requireEngineDriver(connection);
const pool = systemConnection || (await connectUtility(driver, connection));
const pool = systemConnection || (await connectUtility(driver, connection, 'read'));
if (!analysedStructure) {
analysedStructure = await driver.analyseFull(pool);
}
+57
View File
@@ -0,0 +1,57 @@
const fs = require('fs');
const requireEngineDriver = require('../utility/requireEngineDriver');
const connectUtility = require('../utility/connectUtility');
const { splitQueryStream } = require('dbgate-query-splitter/lib/splitQueryStream');
const download = require('./download');
const stream = require('stream');
class ImportStream extends stream.Transform {
constructor(pool, driver) {
super({ objectMode: true });
this.pool = pool;
this.driver = driver;
}
async _transform(chunk, encoding, cb) {
try {
await this.driver.script(this.pool, chunk);
} catch (err) {
this.emit('error', err.message);
}
cb();
}
_flush(cb) {
this.push('finish');
cb();
this.emit('end');
}
}
function awaitStreamEnd(stream) {
return new Promise((resolve, reject) => {
stream.once('end', () => {
resolve(true);
});
stream.once('error', err => {
reject(err);
});
});
}
async function importDatabase({ connection = undefined, systemConnection = undefined, driver = undefined, inputFile }) {
console.log(`Importing database`);
if (!driver) driver = requireEngineDriver(connection);
const pool = systemConnection || (await connectUtility(driver, connection, 'write'));
console.log(`Connected.`);
const downloadedFile = await download(inputFile);
const fileStream = fs.createReadStream(downloadedFile, 'utf-8');
const splittedStream = splitQueryStream(fileStream, driver.getQuerySplitterOptions('script'));
const importStream = new ImportStream(pool, driver);
// @ts-ignore
splittedStream.pipe(importStream);
await awaitStreamEnd(importStream);
}
module.exports = importDatabase;
+4
View File
@@ -21,6 +21,8 @@ const executeQuery = require('./executeQuery');
const loadFile = require('./loadFile');
const deployDb = require('./deployDb');
const initializeApiEnvironment = require('./initializeApiEnvironment');
const dumpDatabase = require('./dumpDatabase');
const importDatabase = require('./importDatabase');
const dbgateApi = {
queryReader,
@@ -45,6 +47,8 @@ const dbgateApi = {
loadFile,
deployDb,
initializeApiEnvironment,
dumpDatabase,
importDatabase,
};
requirePlugin.initializeDbgateApi(dbgateApi);
+19 -5
View File
@@ -1,14 +1,28 @@
const requireEngineDriver = require('../utility/requireEngineDriver');
const { decryptConnection } = require('../utility/crypting');
const connectUtility = require('../utility/connectUtility');
async function queryReader({ connection, sql }) {
console.log(`Reading query ${sql}`);
async function queryReader({
connection,
query,
queryType,
// obsolete; use query instead
sql,
}) {
// if (sql && json) {
// throw new Error('Only one of sql or json could be set');
// }
// if (!sql && !json) {
// throw new Error('One of sql or json must be set');
// }
console.log(`Reading query ${query || sql}`);
// else console.log(`Reading query ${JSON.stringify(json)}`);
const driver = requireEngineDriver(connection);
const pool = await connectUtility(driver, connection);
const pool = await connectUtility(driver, connection, queryType == 'json' ? 'read' : 'script');
console.log(`Connected.`);
return await driver.readQuery(pool, sql);
const reader =
queryType == 'json' ? await driver.readJsonQuery(pool, query) : await driver.readQuery(pool, query || sql);
return reader;
}
module.exports = queryReader;
+5 -4
View File
@@ -5,10 +5,11 @@ const { driverBase } = require('dbgate-tools');
const requireEngineDriver = require('../utility/requireEngineDriver');
class SqlizeStream extends stream.Transform {
constructor({ fileName }) {
constructor({ fileName, dataName }) {
super({ objectMode: true });
this.wasHeader = false;
this.tableName = path.parse(fileName).name;
this.dataName = dataName;
this.driver = driverBase;
}
_transform(chunk, encoding, done) {
@@ -28,7 +29,7 @@ class SqlizeStream extends stream.Transform {
const dmp = this.driver.createDumper();
dmp.put(
'^insert ^into %f (%,i) ^values (%,v);\n',
{ pureName: this.tableName },
{ pureName: this.dataName || this.tableName },
Object.keys(chunk),
Object.values(chunk)
);
@@ -38,9 +39,9 @@ class SqlizeStream extends stream.Transform {
}
}
async function sqlDataWriter({ fileName, driver, encoding = 'utf-8' }) {
async function sqlDataWriter({ fileName, dataName, driver, encoding = 'utf-8' }) {
console.log(`Writing file ${fileName}`);
const stringify = new SqlizeStream({ fileName });
const stringify = new SqlizeStream({ fileName, dataName });
const fileStream = fs.createWriteStream(fileName, encoding);
stringify.pipe(fileStream);
stringify['finisher'] = fileStream;
+2 -2
View File
@@ -4,12 +4,12 @@ const connectUtility = require('../utility/connectUtility');
async function tableReader({ connection, pureName, schemaName }) {
const driver = requireEngineDriver(connection);
const pool = await connectUtility(driver, connection);
const pool = await connectUtility(driver, connection, 'read');
console.log(`Connected.`);
const fullName = { pureName, schemaName };
if (driver.dialect.nosql) {
if (driver.databaseEngineTypes.includes('document')) {
// @ts-ignore
console.log(`Reading collection ${fullNameToString(fullName)}`);
// @ts-ignore
+1 -1
View File
@@ -8,7 +8,7 @@ async function tableWriter({ connection, schemaName, pureName, driver, systemCon
if (!driver) {
driver = requireEngineDriver(connection);
}
const pool = systemConnection || (await connectUtility(driver, connection));
const pool = systemConnection || (await connectUtility(driver, connection, 'write'));
console.log(`Connected.`);
return await driver.writeTable(pool, { schemaName, pureName }, options);
@@ -0,0 +1,21 @@
const stream = require('stream');
const { transformRowUsingColumnMap } = require('dbgate-tools');
class ColumnMapTransformStream extends stream.Transform {
constructor(columns) {
super({ objectMode: true });
this.columns = columns;
}
_transform(chunk, encoding, done) {
if (chunk.__isStreamHeader) {
// skip stream header
done();
return;
}
this.push(transformRowUsingColumnMap(chunk, this.columns));
done();
}
}
module.exports = ColumnMapTransformStream;
@@ -159,10 +159,23 @@ class JsonLinesDatastore {
}
}
async enumRows(eachRow) {
await lock.acquire('reader', async () => {
await this._ensureReader(0, null);
for (;;) {
const line = await this._readLine(true);
if (line == null) break;
const shouldContinue = eachRow(line);
if (!shouldContinue) break;
}
});
}
async getRows(offset, limit, filter) {
const res = [];
await lock.acquire('reader', async () => {
await this._ensureReader(offset, filter);
// console.log(JSON.stringify(this.currentFilter, undefined, 2));
for (let i = 0; i < limit; i += 1) {
const line = await this._readLine(true);
if (line == null) break;
+251
View File
@@ -0,0 +1,251 @@
/*
* Copyright 2018 Stocard GmbH.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { Client } = require('ssh2');
const net = require('net');
const fs = require('fs');
const os = require('os');
const path = require('path');
const debug = require('debug');
// interface Options {
// username?: string;
// password?: string;
// privateKey?: string | Buffer;
// agentForward?: boolean;
// bastionHost?: string;
// passphrase?: string;
// endPort?: number;
// endHost: string;
// agentSocket?: string;
// skipAutoPrivateKey?: boolean;
// noReadline?: boolean;
// }
// interface ForwardingOptions {
// fromPort: number;
// toPort: number;
// toHost?: string;
// }
class SSHConnection {
constructor(options) {
this.options = options;
this.debug = debug('ssh');
this.connections = [];
this.isWindows = process.platform === 'win32';
if (!options.username) {
this.options.username = process.env['SSH_USERNAME'] || process.env['USER'];
}
if (!options.endPort) {
this.options.endPort = 22;
}
if (!options.privateKey && !options.agentForward && !options.skipAutoPrivateKey) {
const defaultFilePath = path.join(os.homedir(), '.ssh', 'id_rsa');
if (fs.existsSync(defaultFilePath)) {
this.options.privateKey = fs.readFileSync(defaultFilePath);
}
}
}
async shutdown() {
this.debug('Shutdown connections');
for (const connection of this.connections) {
connection.removeAllListeners();
connection.end();
}
return new Promise(resolve => {
if (this.server) {
this.server.close(resolve);
}
return resolve();
});
}
async tty() {
const connection = await this.establish();
this.debug('Opening tty');
await this.shell(connection);
}
async executeCommand(command) {
const connection = await this.establish();
this.debug('Executing command "%s"', command);
await this.shell(connection, command);
}
async shell(connection, command) {
return new Promise((resolve, reject) => {
connection.shell((err, stream) => {
if (err) {
return reject(err);
}
stream
.on('close', async () => {
stream.end();
process.stdin.unpipe(stream);
process.stdin.destroy();
connection.end();
await this.shutdown();
return resolve();
})
.stderr.on('data', data => {
return reject(data);
});
stream.pipe(process.stdout);
if (command) {
stream.end(`${command}\nexit\n`);
} else {
process.stdin.pipe(stream);
}
});
});
}
async establish() {
let connection;
if (this.options.bastionHost) {
connection = await this.connectViaBastion(this.options.bastionHost);
} else {
connection = await this.connect(this.options.endHost);
}
return connection;
}
async connectViaBastion(bastionHost) {
this.debug('Connecting to bastion host "%s"', bastionHost);
const connectionToBastion = await this.connect(bastionHost);
return new Promise((resolve, reject) => {
connectionToBastion.forwardOut(
'127.0.0.1',
22,
this.options.endHost,
this.options.endPort || 22,
async (err, stream) => {
if (err) {
return reject(err);
}
const connection = await this.connect(this.options.endHost, stream);
return resolve(connection);
}
);
});
}
async connect(host, stream) {
this.debug('Connecting to "%s"', host);
const connection = new Client();
return new Promise(async (resolve, reject) => {
const options = {
host,
port: this.options.endPort,
username: this.options.username,
password: this.options.password,
privateKey: this.options.privateKey,
};
if (this.options.agentForward) {
options['agentForward'] = true;
// see https://github.com/mscdex/ssh2#client for agents on Windows
// guaranteed to give the ssh agent sock if the agent is running (posix)
let agentDefault = process.env['SSH_AUTH_SOCK'];
if (this.isWindows) {
// null or undefined
if (agentDefault == null) {
agentDefault = 'pageant';
}
}
const agentSock = this.options.agentSocket ? this.options.agentSocket : agentDefault;
if (agentSock == null) {
throw new Error('SSH Agent Socket is not provided, or is not set in the SSH_AUTH_SOCK env variable');
}
options['agent'] = agentSock;
}
if (stream) {
options['sock'] = stream;
}
// PPK private keys can be encrypted, but won't contain the word 'encrypted'
// in fact they always contain a `encryption` header, so we can't do a simple check
options['passphrase'] = this.options.passphrase;
const looksEncrypted = this.options.privateKey
? this.options.privateKey.toString().toLowerCase().includes('encrypted')
: false;
if (looksEncrypted && !options['passphrase'] && !this.options.noReadline) {
// options['passphrase'] = await this.getPassphrase();
}
connection.on('ready', () => {
this.connections.push(connection);
return resolve(connection);
});
connection.on('error', error => {
reject(error);
});
try {
connection.connect(options);
} catch (error) {
reject(error);
}
});
}
// private async getPassphrase() {
// return new Promise(resolve => {
// const rl = readline.createInterface({
// input: process.stdin,
// output: process.stdout,
// });
// rl.question('Please type in the passphrase for your private key: ', answer => {
// return resolve(answer);
// });
// });
// }
async forward(options) {
const connection = await this.establish();
return new Promise((resolve, reject) => {
this.server = net
.createServer(socket => {
this.debug(
'Forwarding connection from "localhost:%d" to "%s:%d"',
options.fromPort,
options.toHost,
options.toPort
);
connection.forwardOut(
'localhost',
options.fromPort,
options.toHost || 'localhost',
options.toPort,
(error, stream) => {
if (error) {
return reject(error);
}
socket.pipe(stream);
stream.pipe(socket);
}
);
})
.listen(options.fromPort, 'localhost', () => {
return resolve();
});
});
}
}
module.exports = { SSHConnection };
+40 -7
View File
@@ -1,14 +1,47 @@
const { SSHConnection } = require('node-ssh-forward');
const portfinder = require('portfinder');
const fs = require('fs-extra');
const { decryptConnection } = require('./crypting');
const { getSshTunnel } = require('./sshTunnel');
const { getSshTunnelProxy } = require('./sshTunnelProxy');
const platformInfo = require('../utility/platformInfo');
const connections = require('../controllers/connections');
async function loadConnection(driver, storedConnection, connectionMode) {
const { allowShellConnection } = platformInfo;
if (connectionMode == 'app') {
return storedConnection;
}
if (storedConnection._id || !allowShellConnection) {
if (!storedConnection._id) {
throw new Error('Missing connection _id');
}
await connections._init();
const loaded = await connections.getCore({ conid: storedConnection._id });
const loadedWithDb = {
...loaded,
database: storedConnection.database,
};
if (loaded.isReadOnly) {
if (connectionMode == 'read') return loadedWithDb;
if (connectionMode == 'write') throw new Error('Cannot write readonly connection');
if (connectionMode == 'script') {
if (driver.readOnlySessions) return loadedWithDb;
throw new Error('Cannot write readonly connection');
}
}
return loadedWithDb;
}
return storedConnection;
}
async function connectUtility(driver, storedConnection, connectionMode, additionalOptions = null) {
const connectionLoaded = await loadConnection(driver, storedConnection, connectionMode);
async function connectUtility(driver, storedConnection) {
const connection = {
database: storedConnection.defaultDatabase,
...decryptConnection(storedConnection),
database: connectionLoaded.defaultDatabase,
...decryptConnection(connectionLoaded),
};
if (!connection.port && driver.defaultPort) connection.port = driver.defaultPort.toString();
@@ -57,7 +90,7 @@ async function connectUtility(driver, storedConnection) {
}
}
const conn = await driver.connect(connection);
const conn = await driver.connect({ ...connection, ...additionalOptions });
return conn;
}
+7 -1
View File
@@ -55,7 +55,7 @@ function encryptPasswordField(connection, field) {
[field]: 'crypt:' + getEncryptor().encrypt(connection[field]),
};
}
return connection;
return connection;
}
function decryptPasswordField(connection, field) {
@@ -75,6 +75,11 @@ function encryptConnection(connection) {
return connection;
}
function maskConnection(connection) {
if (!connection) return connection;
return _.omit(connection, ['password', 'sshPassword', 'sshKeyfilePassword']);
}
function decryptConnection(connection) {
connection = decryptPasswordField(connection, 'password');
connection = decryptPasswordField(connection, 'sshPassword');
@@ -95,5 +100,6 @@ module.exports = {
loadEncryptionKey,
encryptConnection,
decryptConnection,
maskConnection,
pickSafeConnectionInfo,
};
+39 -3
View File
@@ -3,11 +3,13 @@ const path = require('path');
const fs = require('fs');
const cleanDirectory = require('./cleanDirectory');
const platformInfo = require('./platformInfo');
const processArgs = require('./processArgs');
const consoleObjectWriter = require('../shell/consoleObjectWriter');
const createDirectories = {};
const ensureDirectory = (dir, clean) => {
if (!createDirectories[dir]) {
if (clean && fs.existsSync(dir)) {
if (clean && fs.existsSync(dir) && !platformInfo.isForkedApi) {
console.log(`Cleaning directory ${dir}`);
cleanDirectory(dir);
}
@@ -19,8 +21,18 @@ const ensureDirectory = (dir, clean) => {
}
};
function datadirCore() {
if (process.env.WORKSPACE_DIR) {
return process.env.WORKSPACE_DIR;
}
if (processArgs.workspaceDir) {
return processArgs.workspaceDir;
}
return path.join(os.homedir(), '.dbgate');
}
function datadir() {
const dir = path.join(os.homedir(), 'dbgate-data');
const dir = datadirCore();
ensureDirectory(dir);
return dir;
@@ -54,7 +66,10 @@ function packagedPluginsDir() {
}
if (platformInfo.isNpmDist) {
// node_modules
return global['dbgateApiPackagedPluginsPath'];
return global['PLUGINS_DIR'];
}
if (processArgs.pluginsDir) {
return processArgs.pluginsDir;
}
if (platformInfo.isElectronBundle) {
return path.resolve(__dirname, '../../plugins');
@@ -98,6 +113,27 @@ function clearArchiveLinksCache() {
archiveLinksCache = {};
}
function migrateDataDir() {
if (process.env.WORKSPACE_DIR) {
return;
}
if (processArgs.workspaceDir) {
return;
}
try {
const oldDir = path.join(os.homedir(), 'dbgate-data');
const newDir = path.join(os.homedir(), '.dbgate');
if (fs.existsSync(oldDir) && !fs.existsSync(newDir)) {
fs.renameSync(oldDir, newDir);
}
} catch (e) {
console.log('Error migrating data dir:', e.message);
}
}
migrateDataDir();
module.exports = {
datadir,
jsldir,
+1 -1
View File
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
async function saveFreeTableData(file, data) {
const { structure, rows } = data;
const fileStream = fs.createWriteStream(file);
await fileStream.write(JSON.stringify(structure) + '\n');
await fileStream.write(JSON.stringify({ __isStreamHeader: true, ...structure }) + '\n');
for (const row of rows) {
await fileStream.write(JSON.stringify(row) + '\n');
}
@@ -6,6 +6,10 @@ function getJslFileName(jslid) {
if (archiveMatch) {
return path.join(resolveArchiveFolder(archiveMatch[1]), `${archiveMatch[2]}.jsonl`);
}
const fileMatch = jslid.match(/^file:\/\/(.*)$/);
if (fileMatch) {
return fileMatch[1];
}
return path.join(jsldir(), `${jslid}.jsonl`);
}
+77
View File
@@ -0,0 +1,77 @@
const getMapExport = (geoJson) => {
return `<html>
<meta charset='utf-8'>
<head>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"
integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
crossorigin=""></script>
<script>
function createMap() {
map = leaflet.map('map').setView([50, 15], 13);
leaflet
.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '<a href="https://dbgate.org" title="Exported from DbGate">DbGate</a> | © OpenStreetMap',
})
.addTo(map);
const geoJsonObj = leaflet
.geoJSON(${JSON.stringify(geoJson)}, {
style: function () {
return {
weight: 2,
fillColor: '#ff7800',
color: '#ff7800',
opacity: 0.8,
fillOpacity: 0.4,
};
},
pointToLayer: (feature, latlng) => {
return leaflet.circleMarker(latlng, {
radius: 7,
weight: 2,
fillColor: '#ff0000',
color: '#ff0000',
opacity: 0.9,
fillOpacity: 0.9,
});
},
onEachFeature: (feature, layer) => {
// does this feature have a property named popupContent?
if (feature.properties && feature.properties.popupContent) {
layer.bindPopup(feature.properties.popupContent);
layer.bindTooltip(feature.properties.popupContent);
}
},
})
.addTo(map);
map.fitBounds(geoJsonObj.getBounds());
}
</script>
<style>
#map {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
</style>
</head>
<body onload='createMap()'>
<div id='map'></div>
</body>
</html>`;
};
module.exports = getMapExport;
+78 -6
View File
@@ -1,12 +1,84 @@
const { compilePermissions, testPermission } = require('dbgate-tools');
const _ = require('lodash');
let compiled = undefined;
const userPermissions = {};
function hasPermission(tested) {
if (compiled === undefined) {
compiled = compilePermissions(process.env.PERMISSIONS);
function hasPermission(tested, req) {
if (!req) {
// request object not available, allow all
return true;
}
return testPermission(tested, compiled);
const { user } = (req && req.auth) || {};
const key = user || '';
const logins = getLogins();
if (!userPermissions[key]) {
if (logins) {
const login = logins.find(x => x.login == user);
userPermissions[key] = compilePermissions(login ? login.permissions : null);
} else {
userPermissions[key] = compilePermissions(process.env.PERMISSIONS);
}
}
return testPermission(tested, userPermissions[key]);
}
module.exports = hasPermission;
let loginsCache = null;
let loginsLoaded = false;
function getLogins() {
if (loginsLoaded) {
return loginsCache;
}
const res = [];
if (process.env.LOGIN && process.env.PASSWORD) {
res.push({
login: process.env.LOGIN,
password: process.env.PASSWORD,
permissions: process.env.PERMISSIONS,
});
}
if (process.env.LOGINS) {
const logins = _.compact(process.env.LOGINS.split(',').map(x => x.trim()));
for (const login of logins) {
const password = process.env[`LOGIN_PASSWORD_${login}`];
const permissions = process.env[`LOGIN_PERMISSIONS_${login}`];
if (password) {
res.push({
login,
password,
permissions,
});
}
}
}
loginsCache = res.length > 0 ? res : null;
loginsLoaded = true;
return loginsCache;
}
function connectionHasPermission(connection, req) {
if (!connection) {
return true;
}
if (_.isString(connection)) {
return hasPermission(`connections/${connection}`, req);
} else {
return hasPermission(`connections/${connection._id}`, req);
}
}
function testConnectionPermission(connection, req) {
if (!connectionHasPermission(connection, req)) {
throw new Error('Connection permission not granted');
}
}
module.exports = {
hasPermission,
getLogins,
connectionHasPermission,
testConnectionPermission,
};

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