Compare commits

...

140 Commits

Author SHA1 Message Date
Jan Prochazka d68d9206b4 v5.3.1 2024-06-21 09:35:09 +02:00
Jan Prochazka 9d99c01018 v5.3.1-beta.3 2024-06-21 08:03:30 +02:00
Jan Prochazka 16ed91b147 fixed regression #819 2024-06-21 07:58:12 +02:00
Jan Prochazka 4d32e57947 v5.3.1-beta.2 2024-06-17 17:06:55 +02:00
Jan Prochazka 4d25fef37d fixed singledb docker connections 2024-06-17 17:06:00 +02:00
Jan Prochazka 25835ee19f v5.3.1-beta.1 2024-06-17 11:38:45 +02:00
Jan Prochazka 2cd3aac158 #816 fixed redshift DB 2024-06-17 11:38:18 +02:00
Jan Prochazka ee671297bf added version to error gist 2024-06-07 15:25:26 +02:00
Jan Prochazka ce895f92cd Merge branch 'master' of github.com:dbgate/dbgate 2024-06-07 10:56:30 +02:00
Jan Prochazka 4e746a3055 Merge pull request #787 from michael-pattern/feat/763/per-user_permissions_when_using_oauth-follow-up
feat: per-user permissions when using oauth, follow-up
2024-06-07 10:54:45 +02:00
Jan Prochazka 5bc0af1fba changelog 2024-06-07 10:27:36 +02:00
Jan Prochazka 66a9e0d14a v5.3.0 2024-06-07 10:18:15 +02:00
Jan Prochazka b536b56348 v5.2.10-beta.4 2024-06-03 13:09:58 +02:00
Jan Prochazka ad6a22d2a6 #811 fixed columns in mongodb query 2024-06-03 12:43:59 +02:00
Jan Prochazka 64d9b26d79 allow specify username to redis connection 2024-06-03 11:00:13 +02:00
Jan Prochazka 284606e3d5 collection allows switch tab 2024-06-03 10:29:33 +02:00
Jan Prochazka e8129fd499 handle error with no structure 2024-06-03 10:27:25 +02:00
Jan Prochazka d454da325f fix: DB list for different connection 2024-06-03 10:14:17 +02:00
Jan Prochazka 5c703c786d Merge branch 'master' of github.com:dbgate/dbgate 2024-06-03 09:50:14 +02:00
Jan Prochazka 864c5bb208 switch database command 2024-06-03 09:50:08 +02:00
Jan Prochazka 504d16f189 v5.2.10-beta.3 2024-06-03 08:06:47 +02:00
Jan Prochazka d87af2a820 oracle version getter 2024-06-03 08:06:05 +02:00
Jan Prochazka 4e6e0a79c4 oracle version fallback 2024-06-03 07:53:12 +02:00
Jan Prochazka f4fbb28124 oracle: bulk inserter 2024-06-01 16:28:46 +02:00
Jan Prochazka 1c03a8ce9e v5.2.10-beta.2 2024-06-01 14:38:22 +02:00
Jan Prochazka 5bf2cf2784 Merge branch 'new-oracle-driver' 2024-06-01 14:38:01 +02:00
Jan Prochazka e572cd392c removed experimental oracle status 2024-06-01 14:36:57 +02:00
Jan Prochazka a812ff510d oracle: import data works 2024-06-01 14:35:40 +02:00
Jan Prochazka cafe0e68c3 fixes 2024-06-01 13:08:51 +02:00
Jan Prochazka 728f3621eb fix 2024-06-01 12:37:57 +02:00
Jan Prochazka ca0ae2084c oracle: handle statements in stream 2024-06-01 10:49:38 +02:00
Jan Prochazka 0cc7a98391 oracle: fixed commit 2024-06-01 08:36:13 +02:00
Jan Prochazka 68a40e5da6 oracle: upgraded query spliiter 2024-06-01 08:16:37 +02:00
Jan Prochazka bbf2e2f7ed fixes 2024-06-01 08:12:18 +02:00
Jan Prochazka 1f75a818c8 oracle: code cleanup, not null detection 2024-05-31 17:03:35 +02:00
Jan Prochazka ebdcd9ad94 oracle: detect autoincrement column 2024-05-31 16:49:43 +02:00
Jan Prochazka 2d1ac97191 oracle: fixed analysing constraints 2024-05-31 16:45:33 +02:00
Jan Prochazka 8f5b395935 oracle analyser code cleanup 2024-05-31 16:06:39 +02:00
Jan Prochazka df60d40134 oracle - using default schema 2024-05-31 15:21:49 +02:00
Jan Prochazka 2723c41832 oracle analyser per schema 2024-05-31 14:35:35 +02:00
Jan Prochazka a2102a51a1 use oracledb purejs client 2024-05-31 10:17:48 +02:00
Jan Prochazka 958d786dfb use .env instead of .env.local 2024-05-31 10:03:06 +02:00
Jan Prochazka e2526082b8 v5.2.10-beta.1 2024-05-31 08:54:35 +02:00
Jan Prochazka 0d22c675b6 #803 2024-05-31 08:28:32 +02:00
Jan Prochazka ab481121f9 changelog 2024-05-29 20:50:48 +02:00
Jan Prochazka e9ee52ac9d v5.2.9 2024-05-29 20:45:58 +02:00
Jan Prochazka 5eecb45961 printSecrets job 2024-05-29 07:17:25 +02:00
Jan Prochazka 94e991b059 v5.2.9-beta.6 2024-05-29 07:10:33 +02:00
Jan Prochazka 373a35fe65 Revert "Merge pull request #744 from Bare7a/postgresql-user-type-enhancements"
This reverts commit fdabe1eeaa, reversing
changes made to 4429b1d618.
2024-05-29 07:09:43 +02:00
Jan Prochazka eba5bd9c2b v5.2.9-beta.5 2024-05-27 18:06:27 +02:00
Jan Prochazka ca3507f5d4 fixed electron logs 2024-05-27 18:04:54 +02:00
Jan Prochazka 4f5db15c20 logging 2024-05-27 14:05:44 +02:00
Jan Prochazka 22bed04d13 gist - configurable token 2024-05-27 14:01:58 +02:00
Jan Prochazka d3737b4e08 v5.2.9-beta.4 2024-05-27 12:13:34 +02:00
Jan Prochazka 20c1315380 pg more analyser logs 2024-05-27 12:02:40 +02:00
Jan Prochazka e9442bd633 postgreSQL - extended nalyser logs 2024-05-27 11:43:38 +02:00
Jan Prochazka 59bd699fc6 v5.2.9-beta.3 2024-05-24 14:19:41 +02:00
Jan Prochazka cc3fd605de add gist upload secret 2024-05-24 14:18:57 +02:00
Jan Prochazka 0adf730f0b use gist secret 2024-05-24 14:13:12 +02:00
Jan Prochazka 5ab0907bd8 upload error to gist 2024-05-24 13:12:07 +02:00
Jan Prochazka e04da15f72 fix mongo reload - using setLoadedRows instead of bind:loadedRows 2024-05-24 10:47:38 +02:00
Jan Prochazka 5fe55af3b7 feat(mongo): fixed data writes after mongo driver upgrade #798 2024-05-24 09:37:44 +02:00
Jan Prochazka 79793d1b58 socket fix 2024-05-24 09:36:04 +02:00
Jan Prochazka d00ee890e5 fixed stream 2024-05-20 20:15:53 +02:00
Jan Prochazka 7d984d8faf feat(mjs): added crypto imports 2024-05-20 19:48:21 +02:00
Jan Prochazka 153f40f13e removed uuid dependency from api package 2024-05-20 19:15:03 +02:00
Jan Prochazka 134d8d1b1a feat(mjs): refactor 2024-05-20 19:00:11 +02:00
Jan Prochazka 2678daab4d Merge pull request #779 from Shah-Panam/Oauth-Allowed-Groups
Added OAuth Allowed Groups Option
2024-05-20 15:08:58 +02:00
Jan Prochazka 781ee15304 Merge commit '51d4bc9a75cdf28831b941f8ed73bd4644a2ca4e' 2024-05-20 14:03:18 +02:00
Jan Prochazka 51d4bc9a75 stream filtering by connection id 2024-05-20 14:02:47 +02:00
Jan Prochazka df3313e647 don't wrap statusbar 2024-05-20 12:48:50 +02:00
michael-pattern 4214b4f613 Use LOGIN_PERMISSIONS_* to compile permissions directly instead of creating logins. Accept req.user.login in hasPermission 2024-05-17 10:59:20 -04:00
ProjectInfinity 685c0f7dbc v5.2.9-beta.2 2024-05-17 13:53:28 +02:00
ProjectInfinity 4417edf73b Change from 127.0.0.1 to localhost for SSH tunnel 2024-05-17 13:06:48 +02:00
ProjectInfinity faf94c1a24 v5.2.9-beta.1 2024-05-17 13:02:46 +02:00
Jan Prochazka c82a877271 #782 disable auto upgrade workaround 2024-05-17 12:15:09 +02:00
Jan Prochazka 8ba85acd3c changelog 2024-05-17 06:45:06 +02:00
Jan Prochazka ba65704d55 v5.2.8 2024-05-17 06:40:13 +02:00
Jan Prochazka 68f77d4ed7 v5.2.8-beta.24 2024-05-15 18:57:10 +02:00
Jan Prochazka 008f6be6ac Merge branch 'master' of github.com:dbgate/dbgate 2024-05-15 18:56:57 +02:00
Jan Prochazka 7324cef87a write uncaught exception to console 2024-05-15 18:56:52 +02:00
michael-pattern cb9921918f Make use of LOGINS and OAUTH_PERMISSIONS exclusive 2024-05-15 12:40:09 -04:00
Panam Shah 9839dc795b Added OAuth Allowed Groups Option 2024-05-14 11:40:53 +00:00
Jan Prochazka 471fcdc131 added flatpak metainfo 2024-05-13 16:28:21 +02:00
Jan Prochazka c2abc83f99 reverted ubuntu upgrade 2024-05-13 14:47:32 +02:00
Jan Prochazka a23bda7294 v5.2.8-beta.23 2024-05-13 14:26:55 +02:00
Jan Prochazka a2d643305b Merge commit '9b4683ef53e815a4190ae90b8a83365235208d0e' 2024-05-13 14:26:38 +02:00
Jan Prochazka dd36427a80 upgraded docker ubuntu base 2024-05-13 14:25:26 +02:00
Jan Prochazka 9b4683ef53 v5.2.8-beta.22 2024-05-13 09:27:57 +02:00
Jan Prochazka a24271f045 build tar.gz for linux 2024-05-13 09:27:19 +02:00
Jan Prochazka f74e57bec2 handle not found connection in ConnectionTab 2024-05-13 09:26:54 +02:00
Jan Prochazka 4fb6b49b86 small fix 2024-05-13 08:40:43 +02:00
Jan Prochazka 72c380cef5 v5.2.8-beta.17 2024-05-09 14:23:42 +02:00
Jan Prochazka 39cdaf88f4 Merge pull request #770 from michael-pattern/feat/763/per-user_permissions_when_using_oauth
feat: per-user permissions when using oauth
2024-05-09 14:20:12 +02:00
Jan Prochazka 52c77031c5 Merge pull request #742 from frenchtoasters/trustCertEnv
Adding env for parsing for trustServerCertificate connection value
2024-05-09 14:02:45 +02:00
Jan Prochazka fdabe1eeaa Merge pull request #744 from Bare7a/postgresql-user-type-enhancements
Postgresql - Show proper types for Composite Types, Enums and Arrays
2024-05-09 13:21:04 +02:00
Jan Prochazka 4429b1d618 revert changes button #759 2024-05-09 13:07:31 +02:00
Jan Prochazka 5c24774170 fixed copy & paste commands 2024-05-09 13:03:05 +02:00
Jan Prochazka 792be82acd changelog 2024-05-09 12:20:34 +02:00
Jan Prochazka 6e3cd08d8a redis driver upgraded 2024-05-09 12:16:14 +02:00
michael-pattern 696d870c2f Allow password-based user login only when password is truthy 2024-05-08 17:52:50 -04:00
michael-pattern 26471517a9 Only add users to basicAuth when password is truthy 2024-05-08 17:52:05 -04:00
michael-pattern 58233a2fd5 Create login entries when the OAUTH_PERMISSIONS flag is truthy 2024-05-08 17:51:27 -04:00
Jan Prochazka 230948c4b4 changelog 2024-05-08 19:27:31 +02:00
Jan Prochazka df593074c2 test container node version => 18 2024-05-08 19:00:28 +02:00
Jan Prochazka 474ecb1b71 Merge branch 'update-packages-2' 2024-05-08 18:55:52 +02:00
Jan Prochazka e8e5781b59 removed better-sqlite prebuilds 2024-05-08 17:26:34 +02:00
Jan Prochazka a042ff363e v5.2.8-beta.16 2024-05-08 10:35:59 +02:00
Jan Prochazka 63bdf817c6 upgraded webpack 2024-05-08 10:35:14 +02:00
Jan Prochazka 82eed3b86e v5.2.8-beta.15 2024-05-08 10:27:52 +02:00
Jan Prochazka 21a24f9ba2 node version => 18 2024-05-08 10:27:35 +02:00
Jan Prochazka 550354fe09 v5.2.8-beta.14 2024-05-08 10:22:45 +02:00
Jan Prochazka e14e7efa1a fixed build error - upgraded chart.js 2024-05-08 10:22:25 +02:00
Jan Prochazka b1cf418058 upgrade electron && db drivers 2024-05-08 10:17:45 +02:00
Jan Prochazka bde4127b33 v5.2.8-beta.13 2024-05-08 08:33:34 +02:00
Jan Prochazka e981cb2734 upgrade webpack 2024-05-08 08:31:10 +02:00
Jan Prochazka 6f4c0edb46 upgraded mongodb driver 2024-05-08 08:21:51 +02:00
Jan Prochazka 6591e45a6e v5.2.8-beta.12 2024-05-08 07:47:02 +02:00
Jan Prochazka 397a6b54ff Merge branch 'master' of github.com:dbgate/dbgate 2024-05-08 07:46:31 +02:00
Jan Prochazka 51555da376 fixed missing env 2024-05-08 07:46:28 +02:00
ProjectInfinity 8e6b1973c7 Merge branch 'copy-paste-improvements' 2024-04-17 17:56:51 +02:00
ProjectInfinity 5a8627c39f Add copy to column list 2024-04-17 17:44:10 +02:00
Bare7a 26a46d9037 updated tableModifications.js 2024-04-06 17:39:58 +03:00
Bare7a b9a974ca27 updated tableModifications.js 2024-04-06 17:37:14 +03:00
Bare7a e4ed163723 updated tableModifications.js 2024-04-06 17:33:47 +03:00
Bare7a 4d8c62f3f5 updated tableModifications.js 2024-04-06 17:31:25 +03:00
Bare7a 4b2e28483b Updated columns.js 2024-04-06 17:30:09 +03:00
Bare7a 3cd070e211 Update columns.js 2024-04-06 17:21:06 +03:00
Bare7a 1e818e7756 Postgresql - Show proper types for Composite Types, Enums and Arrays 2024-04-06 17:13:36 +03:00
Jan Prochazka 91efb7abda v5.2.8-beta.11 2024-04-05 10:23:57 +02:00
Jan Prochazka 5659311ba2 v5.2.8-beta.10 2024-04-05 10:22:54 +02:00
Jan Prochazka 232031ff5b Merge branch 'master' of github.com:dbgate/dbgate 2024-04-05 10:20:35 +02:00
Jan Prochazka 0e242321ed upgraded electron-builder-notarize 2024-04-05 10:20:31 +02:00
Tyler French 83f3391b24 Adding env for parsing for trustServerCertificate connection value 2024-04-03 15:29:19 -04:00
ProjectInfinity 715c6f7f29 Make TabControl scrollable
Fixes #730
2024-03-28 03:40:01 +01:00
ProjectInfinity 0fc20f7238 Fix filter being unclickable
A commit caused the filter input to be unclickable, this fixes that.
2024-03-26 00:09:12 +01:00
ProjectInfinity c824e32f0a Add copy name to table list 2024-03-14 00:24:53 +01:00
ProjectInfinity 10a916bce6 Add copy/paste to query tab and database list 2024-03-13 23:59:02 +01:00
Jan Prochazka 1080147085 v5.2.8-beta.9 2024-02-16 08:43:22 +01:00
Jan Prochazka f0ebe260e2 v5.2.6-beta.8 2024-02-16 08:42:53 +01:00
139 changed files with 3561 additions and 3769 deletions
+9 -2
View File
@@ -23,10 +23,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 16.x
- name: Use Node.js 18.x
uses: actions/setup-node@v1
with:
node-version: 16.x
node-version: 18.x
- name: yarn adjustPackageJson
run: |
yarn adjustPackageJson
@@ -39,6 +39,11 @@ jobs:
- name: setCurrentVersion
run: |
yarn setCurrentVersion
- name: printSecrets
run: |
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
- name: fillNativeModulesElectron
run: |
yarn fillNativeModulesElectron
@@ -63,6 +68,7 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
- name: publishSnap
@@ -88,6 +94,7 @@ jobs:
mv app/dist/*.exe artifacts/ || true
mv app/dist/*.zip artifacts/ || true
mv app/dist/*.tar.gz artifacts/ || true
mv app/dist/*.AppImage artifacts/ || true
mv app/dist/*.deb artifacts/ || true
mv app/dist/*.snap artifacts/ || true
+9 -2
View File
@@ -27,10 +27,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 16.x
- name: Use Node.js 18.x
uses: actions/setup-node@v1
with:
node-version: 16.x
node-version: 18.x
- name: yarn adjustPackageJson
run: |
yarn adjustPackageJson
@@ -45,6 +45,11 @@ jobs:
- name: setCurrentVersion
run: |
yarn setCurrentVersion
- name: printSecrets
run: |
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
- name: fillNativeModulesElectron
run: |
yarn fillNativeModulesElectron
@@ -69,6 +74,7 @@ jobs:
CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
- name: generatePadFile
@@ -98,6 +104,7 @@ jobs:
mv app/dist/*.exe artifacts/ || true
mv app/dist/*.zip artifacts/ || true
mv app/dist/*.tar.gz artifacts/ || true
mv app/dist/*.AppImage artifacts/ || true
mv app/dist/*.deb artifacts/ || true
mv app/dist/*.dmg artifacts/ || true
+9 -2
View File
@@ -53,18 +53,25 @@ jobs:
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 16.x
- name: Use Node.js 18.x
uses: actions/setup-node@v1
with:
node-version: 16.x
node-version: 18.x
- name: yarn install
run: |
# yarn --version
# yarn config set network-timeout 300000
yarn install
- name: setCurrentVersion
run: |
yarn setCurrentVersion
- name: printSecrets
run: |
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
- name: Prepare docker image
run: |
yarn run prepare:docker
+8 -2
View File
@@ -30,10 +30,10 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 16.x
- name: Use Node.js 18.x
uses: actions/setup-node@v1
with:
node-version: 16.x
node-version: 18.x
- name: Configure NPM token
env:
@@ -49,6 +49,12 @@ jobs:
run: |
yarn setCurrentVersion
- name: printSecrets
run: |
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
- name: Publish types
working-directory: packages/types
run: |
+1 -1
View File
@@ -8,7 +8,7 @@ on:
jobs:
test-runner:
runs-on: ubuntu-latest
container: node:16.20
container: node:18
steps:
- name: Context
+38
View File
@@ -8,6 +8,44 @@ Builds:
- linux - application for linux
- win - application for Windows
### 5.3.0
- CHANGED: New Oracle driver, much better Oracle support. Works now also in docker distribution
- FIXED: Connection to oracle with service name #809
- ADDED: Connect to redis using a custom username #807
- FIXED: Unable to open SQL files #797
- FIXED: MongoDB query without columns #811
- ADDED: Switch connection for opened file #814
### 5.2.9
- FIXED: PostgresSQL doesn't show tables when connected #793 #805
- FIXED: MongoDB write operations fail #798 #802
- FIXED: Elecrron app logging losed most of log messages
- FIXED: Connection error with SSH tunnel
- ADDED: option to disable autoupgrades (with --disable-auto-upgrade)
- ADDED: Send error context to github gist
### 5.2.8
- FIXED: file menu save and save as not working
- FIXED: query editor on import/export screen overlaps with selector
- FIXED: Fixed inconsistencies in max/unmaximize window buttons
- FIXED: shortcut for select all
- FIXED: download with auth header
- CHANGED: Upgraded database drivers for mysql, postgres, sqlite, mssql, mongo, redis
- CHANGED: Upgraded electron version (now using v30)
- ADDED: Vim keyboard bindings for editor
- FIXED: Correctly select the save folder for dump
- ADDED: enum + set for mysql (#693)
- FIXED: localStorageGabageCollector not working
- FIXED: Encoding error when opening Unicode query files
- ADDED: Add copy/paste to query tab and database list
- ADDED: Add copy name to table list
- FIXED: Make TabControl scrollable (#730)
- ADDED: Add copy to column list
- FIXED: Problems with SQLite + glibc in docker containers
- ADDED: Button for discard/reset changes (#759)
- FIXED: Don't show error dialog when subprocess fails, as DbGate handles this correctly (#751, #746, #542, #272)
### 5.2.7
- FIXED: fix body overflow when context menu height great than viewport #592
- FIXED: Pass signals in entrypoint.sh #596
+1 -1
View File
@@ -22,7 +22,7 @@ DbGate is licensed under MIT license and is completely free.
* MySQL
* PostgreSQL
* SQL Server
* Oracle (experimental)
* Oracle
* MongoDB
* Redis
* SQLite
-3
View File
@@ -5,9 +5,6 @@ function adjustFile(file) {
if (process.platform != 'win32') {
delete json.optionalDependencies.msnodesqlv8;
}
if (process.arch == 'arm64') {
delete json.optionalDependencies.oracledb;
}
fs.writeFileSync(file, JSON.stringify(json, null, 2), 'utf-8');
}
+39
View File
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>org.dbgate.DbGate</id>
<name>DbGate</name>
<summary>(no)SQL database client</summary>
<metadata_license>CC0-1.0</metadata_license>
<project_license>MIT</project_license>
<developer_name>Jan Prochazka</developer_name>
<description>
<p>DbGate is cross-platform database manager. It's designed to be simple to use and effective, when working with more databases simultaneously. But there are also many advanced features like schema compare, visual query designer, chart visualisation or batch export and import.</p>
</description>
<url type="homepage">https://dbgate.org/</url>
<url type="vcs-browser">https://github.com/dbgate/dbgate</url>
<url type="contact">https://dbgate.org/about/</url>
<url type="donation">https://github.com/sponsors/dbgate</url>
<url type="bugtracker">https://github.com/dbgate/dbgate/issues</url>
<launchable type="desktop-id">org.dbgate.DbGate.desktop</launchable>
<screenshots>
<screenshot type="default">
<image>
https://github.com/dbgate/dbgate/raw/c2abc83f994a56945c27fccea3df84b48005961f/img/screenshot1.png</image>
</screenshot>
<screenshot>
<image>
https://github.com/dbgate/dbgate/raw/c2abc83f994a56945c27fccea3df84b48005961f/img/screenshot2.png</image>
</screenshot>
</screenshots>
<content_rating type="oars-1.1"/>
<releases>
<release version="5.2.7" date="2024-05-13"/>
</releases>
</component>
+6 -6
View File
@@ -48,7 +48,8 @@
"armv7l",
"arm64"
]
}
},
"tar.gz"
],
"icon": "icons/",
"category": "Development",
@@ -114,13 +115,12 @@
"devDependencies": {
"copyfiles": "^2.2.0",
"cross-env": "^6.0.3",
"electron": "17.4.10",
"electron": "30.0.2",
"electron-builder": "23.1.0",
"electron-builder-notarize": "^1.5.1"
"electron-builder-notarize": "^1.5.2"
},
"optionalDependencies": {
"better-sqlite3": "7.6.2",
"msnodesqlv8": "^2.6.0",
"oracledb": "^5.5.0"
"better-sqlite3": "9.6.0",
"msnodesqlv8": "^4.2.1"
}
}
+20 -1
View File
@@ -17,6 +17,7 @@ const path = require('path');
const url = require('url');
const mainMenuDefinition = require('./mainMenuDefinition');
const { settings } = require('cluster');
let disableAutoUpgrade = false;
// require('@electron/remote/main').initialize();
@@ -27,6 +28,10 @@ let mainModule;
// let getLogger;
// let loadLogsContent;
process.on('uncaughtException', function (error) {
console.error('uncaughtException', error);
});
const isMac = () => os.platform() == 'darwin';
// unhandled({
@@ -45,11 +50,21 @@ const isMac = () => os.platform() == 'darwin';
try {
initialConfig = JSON.parse(fs.readFileSync(configRootPath, { encoding: 'utf-8' }));
disableAutoUpgrade = initialConfig['disableAutoUpgrade'] || false;
} catch (err) {
console.log('Error loading config-root:', err.message);
initialConfig = {};
}
if (process.argv.includes('--disable-auto-upgrade')) {
console.log('Disabling auto-upgrade');
disableAutoUpgrade = true;
}
if (process.argv.includes('--enable-auto-upgrade')) {
console.log('Enabling auto-upgrade');
disableAutoUpgrade = false;
}
// 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;
@@ -317,6 +332,7 @@ function createWindow() {
JSON.stringify({
winBounds: mainWindow.getBounds(),
winIsMaximized: mainWindow.isMaximized(),
disableAutoUpgrade,
}),
'utf-8'
);
@@ -379,7 +395,10 @@ function createWindow() {
}
function onAppReady() {
if (!process.env.DEVMODE) {
if (disableAutoUpgrade) {
console.log('Auto-upgrade is disabled, run dbgate --enable-auto-upgrade to enable');
}
if (!process.env.DEVMODE && !disableAutoUpgrade) {
autoUpdater.checkForUpdatesAndNotify();
}
createWindow();
+1
View File
@@ -90,6 +90,7 @@ module.exports = ({ editMenu }) => [
{ divider: true },
{ command: 'folder.showLogs', hideDisabled: true },
{ command: 'folder.showData', hideDisabled: true },
{ command: 'new.gist', hideDisabled: true },
],
},
{
+459 -345
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -11,8 +11,8 @@ RUN apt-get update && apt-get install -y \
make
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | gpg --dearmor -o /usr/share/keyrings/nodesource-archive-keyring.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/nodesource-archive-keyring.gpg] https://deb.nodesource.com/node_16.x jammy main" | tee /etc/apt/sources.list.d/nodesource.list \
&& echo "deb-src [signed-by=/usr/share/keyrings/nodesource-archive-keyring.gpg] https://deb.nodesource.com/node_16.x jammy main" | tee -a /etc/apt/sources.list.d/nodesource.list \
&& echo "deb [signed-by=/usr/share/keyrings/nodesource-archive-keyring.gpg] https://deb.nodesource.com/node_18.x jammy main" | tee /etc/apt/sources.list.d/nodesource.list \
&& echo "deb-src [signed-by=/usr/share/keyrings/nodesource-archive-keyring.gpg] https://deb.nodesource.com/node_18.x jammy main" | tee -a /etc/apt/sources.list.d/nodesource.list \
&& apt-get update && apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& npm install -g yarn
+1 -1
View File
@@ -1,4 +1,4 @@
FROM node:14-alpine
FROM node:18-alpine
WORKDIR /home/dbgate-docker
-3
View File
@@ -5,9 +5,6 @@ let fillContent = '';
if (process.platform == 'win32') {
fillContent += `content.msnodesqlv8 = () => require('msnodesqlv8');`;
}
if (process.arch != 'arm64') {
fillContent += `content.oracledb = () => require('oracledb');`;
}
fillContent += `content['better-sqlite3'] = () => require('better-sqlite3');`;
const getContent = empty => `
@@ -1,7 +1,6 @@
const stableStringify = require('json-stable-stringify');
const _ = require('lodash');
const fp = require('lodash/fp');
const uuidv1 = require('uuid/v1');
const { testWrapper } = require('../tools');
const engines = require('../engines');
const { getAlterDatabaseScript, extendDatabaseInfo, generateDbPairingId } = require('dbgate-tools');
@@ -1,9 +1,9 @@
const stableStringify = require('json-stable-stringify');
const _ = require('lodash');
const fp = require('lodash/fp');
const uuidv1 = require('uuid/v1');
const { testWrapper } = require('../tools');
const engines = require('../engines');
const crypto = require('crypto');
const { getAlterTableScript, extendDatabaseInfo, generateDbPairingId } = require('dbgate-tools');
function pickImportantTableInfo(table) {
@@ -76,7 +76,7 @@ describe('Alter table', () => {
tbl.columns.push({
columnName: 'added',
dataType: 'int',
pairingId: uuidv1(),
pairingId: crypto.randomUUID(),
notNull: false,
autoIncrement: false,
});
+2 -1
View File
@@ -1,6 +1,6 @@
{
"private": true,
"version": "5.2.8-beta.7",
"version": "5.3.1",
"name": "dbgate-all",
"workspaces": [
"packages/*",
@@ -39,6 +39,7 @@
"build:app:local": "yarn plugins:copydist && cd app && yarn build:local",
"start:app:local": "cd app && yarn start:local",
"setCurrentVersion": "node setCurrentVersion",
"printSecrets": "node printSecrets",
"generatePadFile": "node generatePadFile",
"adjustPackageJson": "node adjustPackageJson",
"fillNativeModules": "node fillNativeModules",
+11 -3
View File
@@ -1,6 +1,6 @@
DEVMODE=1
CONNECTIONS=mysql,postgres,mongo,mongo2,mysqlssh,sqlite,relational
CONNECTIONS=mysql,postgres,postgres1,mongo,mongo2,mysqlssh,sqlite,relational
LABEL_mysql=MySql localhost
SERVER_mysql=localhost
@@ -12,10 +12,18 @@ ENGINE_mysql=mysql@dbgate-plugin-mysql
LABEL_postgres=Postgres localhost
SERVER_postgres=localhost
USER_postgres=postgres
PASSWORD_postgres=test
PORT_postgres=5433
PASSWORD_postgres=Pwd2020Db
PORT_postgres=5432
ENGINE_postgres=postgres@dbgate-plugin-postgres
LABEL_postgres1=Postgres localhost test DB
SERVER_postgres1=localhost
USER_postgres1=postgres
PASSWORD_postgres1=Pwd2020Db
PORT_postgres1=5432
ENGINE_postgres1=postgres@dbgate-plugin-postgres
DATABASE_postgres1=test
LABEL_mongo=Mongo URL
URL_mongo=mongodb://localhost:27017
ENGINE_mongo=mongo@dbgate-plugin-mongo
+9 -11
View File
@@ -26,10 +26,10 @@
"compare-versions": "^3.6.0",
"cors": "^2.8.5",
"cross-env": "^6.0.3",
"dbgate-query-splitter": "^4.9.3",
"dbgate-datalib": "^5.0.0-alpha.1",
"dbgate-query-splitter": "^4.10.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-datalib": "^5.0.0-alpha.1",
"debug": "^4.3.4",
"diff": "^5.0.0",
"diff2html": "^3.4.13",
@@ -52,16 +52,15 @@
"ncp": "^2.0.0",
"node-cron": "^2.0.3",
"on-finished": "^2.4.1",
"pinomin": "^1.0.1",
"pinomin": "^1.0.4",
"portfinder": "^1.0.28",
"rimraf": "^3.0.0",
"simple-encryptor": "^4.0.0",
"ssh2": "^1.11.0",
"tar": "^6.0.5",
"uuid": "^3.4.0"
"tar": "^6.0.5"
},
"scripts": {
"start": "env-cmd node src/index.js --listen-api",
"start": "env-cmd -f .env 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",
@@ -79,12 +78,11 @@
"node-loader": "^1.0.2",
"nodemon": "^2.0.2",
"typescript": "^4.4.3",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
},
"optionalDependencies": {
"better-sqlite3": "7.6.2",
"msnodesqlv8": "^2.6.0",
"oracledb": "^5.5.0"
"better-sqlite3": "9.6.0",
"msnodesqlv8": "^4.2.1"
}
}
+2 -2
View File
@@ -1,12 +1,12 @@
const fs = require('fs-extra');
const readline = require('readline');
const crypto = require('crypto');
const path = require('path');
const { archivedir, clearArchiveLinksCache, resolveArchiveFolder } = require('../utility/directories');
const socket = require('../utility/socket');
const loadFilesRecursive = require('../utility/loadFilesRecursive');
const getJslFileName = require('../utility/getJslFileName');
const { getLogger } = require('dbgate-tools');
const uuidv1 = require('uuid/v1');
const dbgateApi = require('../shell');
const jsldata = require('./jsldata');
const platformInfo = require('../utility/platformInfo');
@@ -127,7 +127,7 @@ module.exports = {
return true;
}
const tmpchangedFilePath = path.join(resolveArchiveFolder(folder), `${file}-${uuidv1()}.jsonl`);
const tmpchangedFilePath = path.join(resolveArchiveFolder(folder), `${file}-${crypto.randomUUID()}.jsonl`);
const reader = await dbgateApi.modifyJsonLinesReader({
fileName: changedFilePath,
changeSet,
+21 -3
View File
@@ -1,14 +1,14 @@
const axios = require('axios');
const jwt = require('jsonwebtoken');
const getExpressPath = require('../utility/getExpressPath');
const uuidv1 = require('uuid/v1');
const { getLogins } = require('../utility/hasPermission');
const { getLogger } = require('dbgate-tools');
const AD = require('activedirectory2').promiseWrapper;
const crypto = require('crypto');
const logger = getLogger('auth');
const tokenSecret = uuidv1();
const tokenSecret = crypto.randomUUID();
function shouldAuthorizeApi() {
const logins = getLogins();
@@ -90,6 +90,24 @@ module.exports = {
) {
return { error: `Username ${login} not allowed to log in` };
}
const groups =
process.env.OAUTH_GROUP_FIELD && payload && payload[process.env.OAUTH_GROUP_FIELD]
? payload[process.env.OAUTH_GROUP_FIELD]
: [];
const allowedGroups =
process.env.OAUTH_ALLOWED_GROUPS
? process.env.OAUTH_ALLOWED_GROUPS.split(',').map(group => group.toLowerCase().trim())
: [];
if (
process.env.OAUTH_ALLOWED_GROUPS &&
!groups.some(group => allowedGroups.includes(group.toLowerCase().trim()))
) {
return { error: `Username ${login} does not belong to an allowed group` };
}
if (access_token) {
return {
accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: getTokenLifetime() }),
@@ -137,7 +155,7 @@ module.exports = {
return { error: 'Logins not configured' };
}
const foundLogin = logins.find(x => x.login == login);
if (foundLogin && foundLogin.password == password) {
if (foundLogin && foundLogin.password && foundLogin.password == password) {
return {
accessToken: jwt.sign({ login }, tokenSecret, { expiresIn: getTokenLifetime() }),
};
@@ -61,6 +61,7 @@ function getPortalCollections() {
useDatabaseUrl: !!process.env[`URL_${id}`],
databaseFile: process.env[`FILE_${id}`],
socketPath: process.env[`SOCKET_PATH_${id}`],
serviceName: process.env[`SERVICE_NAME_${id}`],
authType: process.env[`AUTH_TYPE_${id}`] || (process.env[`SOCKET_PATH_${id}`] ? 'socket' : undefined),
defaultDatabase:
process.env[`DATABASE_${id}`] ||
@@ -88,6 +89,7 @@ function getPortalCollections() {
sslCertFilePassword: process.env[`SSL_CERT_FILE_PASSWORD_${id}`],
sslKeyFile: process.env[`SSL_KEY_FILE_${id}`],
sslRejectUnauthorized: process.env[`SSL_REJECT_UNAUTHORIZED_${id}`],
trustServerCertificate: process.env[`SSL_TRUST_CERTIFICATE_${id}`],
}));
logger.info({ connections: connections.map(pickSafeConnectionInfo) }, 'Using connections from ENV variables');
@@ -1,4 +1,3 @@
const uuidv1 = require('uuid/v1');
const connections = require('./connections');
const archive = require('./archive');
const socket = require('../utility/socket');
@@ -30,6 +29,7 @@ const processArgs = require('../utility/processArgs');
const { testConnectionPermission } = require('../utility/hasPermission');
const { MissingCredentialsError } = require('../utility/exceptions');
const pipeForkLogs = require('../utility/pipeForkLogs');
const crypto = require('crypto');
const logger = getLogger('databaseConnections');
@@ -137,7 +137,7 @@ module.exports = {
/** @param {import('dbgate-types').OpenedDatabaseConnection} conn */
sendRequest(conn, message) {
const msgid = uuidv1();
const msgid = crypto.randomUUID();
const promise = new Promise((resolve, reject) => {
this.requests[msgid] = [resolve, reject];
try {
+2 -2
View File
@@ -1,6 +1,6 @@
const uuidv1 = require('uuid/v1');
const fs = require('fs-extra');
const path = require('path');
const crypto = require('crypto');
const { filesdir, archivedir, resolveArchiveFolder, uploadsdir, appdir } = require('../utility/directories');
const getChartExport = require('../utility/getChartExport');
const { hasPermission } = require('../utility/hasPermission');
@@ -164,7 +164,7 @@ module.exports = {
generateUploadsFile_meta: true,
async generateUploadsFile({ extension }) {
const fileName = `${uuidv1()}.${extension || 'html'}`;
const fileName = `${crypto.randomUUID()}.${extension || 'html'}`;
return {
fileName,
filePath: path.join(uploadsdir(), fileName),
+3 -3
View File
@@ -1,7 +1,7 @@
const crypto = require('crypto');
const _ = require('lodash');
const path = require('path');
const fs = require('fs-extra');
const uuidv1 = require('uuid/v1');
const byline = require('byline');
const socket = require('../utility/socket');
const { fork } = require('child_process');
@@ -165,7 +165,7 @@ module.exports = {
start_meta: true,
async start({ script }) {
const runid = uuidv1();
const runid = crypto.randomUUID()
if (script.type == 'json') {
const js = jsonScriptToJavascript(script);
@@ -213,7 +213,7 @@ module.exports = {
loadReader_meta: true,
async loadReader({ functionName, props }) {
const promise = new Promise((resolve, reject) => {
const runid = uuidv1();
const runid = crypto.randomUUID();
this.requests[runid] = [resolve, reject];
this.startCore(runid, loaderScriptTemplate(functionName, props, runid));
});
@@ -1,7 +1,6 @@
const connections = require('./connections');
const socket = require('../utility/socket');
const { fork } = require('child_process');
const uuidv1 = require('uuid/v1');
const _ = require('lodash');
const AsyncLock = require('async-lock');
const { handleProcessCommunication } = require('../utility/processComm');
@@ -152,7 +151,7 @@ module.exports = {
},
ping_meta: true,
async ping({ conidArray }) {
async ping({ conidArray, strmid }) {
await Promise.all(
_.uniq(conidArray).map(async conid => {
const last = this.lastPinged[conid];
@@ -169,6 +168,7 @@ module.exports = {
}
})
);
socket.setStreamIdFilter(strmid, { conid: conidArray });
return { status: 'ok' };
},
@@ -200,7 +200,7 @@ module.exports = {
},
sendRequest(conn, message) {
const msgid = uuidv1();
const msgid = crypto.randomUUID();
const promise = new Promise((resolve, reject) => {
this.requests[msgid] = [resolve, reject];
try {
@@ -240,4 +240,20 @@ module.exports = {
if (opened.connection.isReadOnly) return false;
return this.loadDataCore('summaryCommand', { conid, command, row });
},
getOpenedConnectionReport() {
return this.opened.map(con => ({
status: con.status,
versionText: con.version?.versionText,
databaseCount: con.databases.length,
connection: _.pick(con.connection, [
'engine',
'useSshTunnel',
'authType',
'trustServerCertificate',
'useSsl',
'sshMode',
]),
}));
},
};
+4 -4
View File
@@ -1,5 +1,5 @@
const crypto = require('crypto');
const _ = require('lodash');
const uuidv1 = require('uuid/v1');
const connections = require('./connections');
const socket = require('../utility/socket');
const { fork } = require('child_process');
@@ -85,7 +85,7 @@ module.exports = {
create_meta: true,
async create({ conid, database }) {
const sesid = uuidv1();
const sesid = crypto.randomUUID();
const connection = await connections.getCore({ conid });
const subprocess = fork(
global['API_PACKAGE'] || process.argv[1],
@@ -149,7 +149,7 @@ module.exports = {
const { sesid } = await this.create({ conid, database });
const session = this.opened.find(x => x.sesid == sesid);
session.killOnDone = true;
const jslid = uuidv1();
const jslid = crypto.randomUUID();
session.loadingReader_jslid = jslid;
const fileName = queryName && appFolder ? path.join(appdir(), appFolder, `${queryName}.query.sql`) : null;
@@ -169,7 +169,7 @@ module.exports = {
startProfiler_meta: true,
async startProfiler({ sesid }) {
const jslid = uuidv1();
const jslid = crypto.randomUUID();
const session = this.opened.find(x => x.sesid == sesid);
if (!session) {
throw new Error('Invalid session');
+98 -3
View File
@@ -1,8 +1,18 @@
const crypto = require('crypto');
const path = require('path');
const { uploadsdir } = require('../utility/directories');
const uuidv1 = require('uuid/v1');
const { uploadsdir, getLogsFilePath } = require('../utility/directories');
const { getLogger } = require('dbgate-tools');
const logger = getLogger('uploads');
const axios = require('axios');
const os = require('os');
const fs = require('fs/promises');
const { read } = require('./queryHistory');
const platformInfo = require('../utility/platformInfo');
const _ = require('lodash');
const serverConnections = require('./serverConnections');
const config = require('./config');
const gistSecret = require('../gistSecret');
const currentVersion = require('../currentVersion');
module.exports = {
upload_meta: {
@@ -15,7 +25,7 @@ module.exports = {
res.json(null);
return;
}
const uploadName = uuidv1();
const uploadName = crypto.randomUUID();
const filePath = path.join(uploadsdir(), uploadName);
logger.info(`Uploading file ${data.name}, size=${data.size}`);
@@ -35,4 +45,89 @@ module.exports = {
get(req, res) {
res.sendFile(path.join(uploadsdir(), req.query.file));
},
async getGistToken() {
const settings = await config.getSettings();
return settings['other.gistCreateToken'] || gistSecret;
},
uploadErrorToGist_meta: true,
async uploadErrorToGist() {
const logs = await fs.readFile(getLogsFilePath(), { encoding: 'utf-8' });
const connections = await serverConnections.getOpenedConnectionReport();
try {
const response = await axios.default.post(
'https://api.github.com/gists',
{
description: `DbGate ${currentVersion.version} error report`,
public: false,
files: {
'logs.jsonl': {
content: logs,
},
'os.json': {
content: JSON.stringify(
{
release: os.release(),
arch: os.arch(),
machine: os.machine(),
platform: os.platform(),
type: os.type(),
},
null,
2
),
},
'platform.json': {
content: JSON.stringify(
_.omit(
{
...platformInfo,
},
['defaultKeyfile', 'sshAuthSock']
),
null,
2
),
},
'connections.json': {
content: JSON.stringify(connections, null, 2),
},
'version.json': {
content: JSON.stringify(currentVersion, null, 2),
},
},
},
{
headers: {
Authorization: `token ${await this.getGistToken()}`,
'Content-Type': 'application/json',
Accept: 'application/vnd.github.v3+json',
},
}
);
return response.data;
} catch (err) {
logger.error({ err }, 'Error uploading gist');
return {
apiErrorMessage: err.message,
};
// console.error('Error creating gist:', error.response ? error.response.data : error.message);
}
},
deleteGist_meta: true,
async deleteGist({ url }) {
const response = await axios.default.delete(url, {
headers: {
Authorization: `token ${await this.getGistToken()}`,
'Content-Type': 'application/json',
Accept: 'application/vnd.github.v3+json',
},
});
return true;
},
};
+1
View File
@@ -0,0 +1 @@
module.exports = process.env.GIST_UPLOAD_SECRET;
+13 -7
View File
@@ -1,4 +1,4 @@
const { setLogger, getLogger, setLoggerName } = require('dbgate-tools');
const { setLogConfig, getLogger, setLoggerName } = require('dbgate-tools');
const processArgs = require('./utility/processArgs');
const fs = require('fs');
const moment = require('moment');
@@ -30,22 +30,27 @@ function configureLogger() {
setLogsFilePath(logsFilePath);
setLoggerName('main');
const logger = createLogger({
const consoleLogLevel = process.env.CONSOLE_LOG_LEVEL || process.env.LOG_LEVEL || 'info';
const fileLogLevel = process.env.FILE_LOG_LEVEL || process.env.LOG_LEVEL || 'debug';
const logConfig = {
base: { pid: process.pid },
targets: [
{
type: 'console',
// @ts-ignore
level: process.env.CONSOLE_LOG_LEVEL || process.env.LOG_LEVEL || 'info',
level: consoleLogLevel,
},
{
type: 'stream',
// @ts-ignore
level: process.env.FILE_LOG_LEVEL || process.env.LOG_LEVEL || 'info',
level: fileLogLevel,
stream: fs.createWriteStream(logsFilePath, { flags: 'a' }),
},
],
});
};
// logger.info(`Initialized logging, console log level: ${consoleLogLevel}, file log level: ${fileLogLevel}`);
// const streams = [];
// if (!platformInfo.isElectron) {
@@ -83,14 +88,15 @@ function configureLogger() {
// },
// });
setLogger(logger);
// @ts-ignore
setLogConfig(logConfig);
}
if (processArgs.listenApi) {
configureLogger();
}
const shell = require('./shell');
const shell = require('./shell/index');
const dbgateTools = require('dbgate-tools');
global['DBGATE_TOOLS'] = dbgateTools;
+4 -3
View File
@@ -48,7 +48,7 @@ function start() {
if (logins && process.env.BASIC_AUTH) {
app.use(
basicAuth({
users: _.fromPairs(logins.map(x => [x.login, x.password])),
users: _.fromPairs(logins.filter(x => x.password).map(x => [x.login, x.password])),
challenge: true,
realm: 'DbGate Web App',
})
@@ -77,6 +77,7 @@ function start() {
}
app.get(getExpressPath('/stream'), async function (req, res) {
const strmid = req.query.strmid;
res.set({
'Cache-Control': 'no-cache',
'Content-Type': 'text/event-stream',
@@ -87,9 +88,9 @@ function start() {
// Tell the client to retry every 10 seconds if connectivity is lost
res.write('retry: 10000\n\n');
socket.addSseResponse(res);
socket.addSseResponse(res, strmid);
onFinished(req, () => {
socket.removeSseResponse(res);
socket.removeSseResponse(strmid);
});
});
+2 -2
View File
@@ -1,4 +1,4 @@
const uuidv1 = require('uuid/v1');
const crypto = require('crypto');
const path = require('path');
const fs = require('fs');
const _ = require('lodash');
@@ -31,7 +31,7 @@ class TableWriter {
}
initializeFromQuery(structure, resultIndex) {
this.jslid = uuidv1();
this.jslid = crypto.randomUUID();
this.currentFile = path.join(jsldir(), `${this.jslid}.jsonl`);
fs.writeFileSync(
this.currentFile,
+2 -2
View File
@@ -1,11 +1,11 @@
const crypto = require('crypto');
const path = require('path');
const uuidv1 = require('uuid/v1');
const { uploadsdir } = require('../utility/directories');
const { downloadFile } = require('../utility/downloader');
async function download(url) {
if (url && url.match(/(^http:\/\/)|(^https:\/\/)/)) {
const tmpFile = path.join(uploadsdir(), uuidv1());
const tmpFile = path.join(uploadsdir(), crypto.randomUUID());
await downloadFile(url, tmpFile);
return tmpFile;
}
+3 -3
View File
@@ -1,5 +1,5 @@
const crypto = require('crypto');
const { fork } = require('child_process');
const uuidv1 = require('uuid/v1');
const { handleProcessCommunication } = require('./processComm');
const processArgs = require('../utility/processArgs');
const pipeForkLogs = require('./pipeForkLogs');
@@ -67,7 +67,7 @@ class DatastoreProxy {
async getRows(offset, limit) {
await this.ensureSubprocess();
const msgid = uuidv1();
const msgid = crypto.randomUUID();
const promise = new Promise((resolve, reject) => {
this.requests[msgid] = [resolve, reject];
try {
@@ -81,7 +81,7 @@ class DatastoreProxy {
}
async notifyChangedCore() {
const msgid = uuidv1();
const msgid = crypto.randomUUID();
const promise = new Promise((resolve, reject) => {
this.requests[msgid] = [resolve, reject];
try {
@@ -1,6 +1,6 @@
const crypto = require('crypto');
const AsyncLock = require('async-lock');
const fs = require('fs-extra');
const uuidv1 = require('uuid/v1');
const lock = new AsyncLock();
@@ -57,7 +57,7 @@ class JsonLinesDatabase {
? obj
: {
...obj,
_id: uuidv1(),
_id: crypto.randomUUID(),
};
this.data.push(elem);
await this._save();
@@ -1,3 +1,4 @@
const crypto = require('crypto');
const fs = require('fs');
const os = require('os');
const rimraf = require('rimraf');
@@ -8,7 +9,6 @@ const stableStringify = require('json-stable-stringify');
const { evaluateCondition } = require('dbgate-sqltree');
const requirePluginFunction = require('./requirePluginFunction');
const esort = require('external-sorting');
const uuidv1 = require('uuid/v1');
const { jsldir } = require('./directories');
const LineReader = require('./LineReader');
@@ -28,7 +28,7 @@ class JsonLinesDatastore {
}
static async sortFile(infile, outfile, sort) {
const tempDir = path.join(os.tmpdir(), uuidv1());
const tempDir = path.join(os.tmpdir(), crypto.randomUUID());
fs.mkdirSync(tempDir);
await esort
@@ -210,7 +210,7 @@ class JsonLinesDatastore {
async getRows(offset, limit, filter, sort) {
const res = [];
if (sort && !this.sortedFiles[stableStringify(sort)]) {
const jslid = uuidv1();
const jslid = crypto.randomUUID();
const sortedFile = path.join(jsldir(), `${jslid}.jsonl`);
await JsonLinesDatastore.sortFile(this.file, sortedFile, sort);
this.sortedFiles[stableStringify(sort)] = sortedFile;
+1 -1
View File
@@ -52,7 +52,7 @@ async function connectUtility(driver, storedConnection, connectionMode, addition
throw new Error(tunnel.message);
}
connection.server = '127.0.0.1';
connection.server = 'localhost';
connection.port = tunnel.localPort;
}
+3 -3
View File
@@ -1,7 +1,7 @@
const crypto = require('crypto');
// const pacote = require('pacote');
const axios = require('axios');
// const tarballExtract = require('tarball-extract');
const uuidv1 = require('uuid/v1');
const path = require('path');
const fs = require('fs');
const zlib = require('zlib');
@@ -38,9 +38,9 @@ async function downloadPackage(packageName, directory) {
const tarball = infoResp.data.versions[latest].dist.tarball;
const tmpFile = path.join(uploadsdir(), uuidv1() + '.tgz');
const tmpFile = path.join(uploadsdir(), crypto.randomUUID() + '.tgz');
await downloadFile(tarball, tmpFile);
const tmpDir = path.join(uploadsdir(), uuidv1());
const tmpDir = path.join(uploadsdir(), crypto.randomUUID());
fs.mkdirSync(tmpDir);
await extractTarball(tmpFile, tmpDir);
await copyDirectory(path.join(tmpDir, 'package'), directory);
+10 -1
View File
@@ -9,7 +9,8 @@ function hasPermission(tested, req) {
return true;
}
const { user } = (req && req.auth) || {};
const key = user || '';
const { login } = (process.env.OAUTH_PERMISSIONS && req && req.user) || {};
const key = user || login || '';
const logins = getLogins();
if (!userPermissions[key]) {
@@ -53,6 +54,14 @@ function getLogins() {
}
}
}
else if (process.env.OAUTH_PERMISSIONS) {
const login_permission_keys = Object.keys(process.env).filter((key) => _.startsWith(key, 'LOGIN_PERMISSIONS_'))
for (const permissions_key of login_permission_keys) {
const login = permissions_key.replace('LOGIN_PERMISSIONS_', '');
const permissions = process.env[permissions_key];
userPermissions[login] = compilePermissions(permissions);
}
}
loginsCache = res.length > 0 ? res : null;
loginsLoaded = true;
+33 -7
View File
@@ -1,7 +1,7 @@
const _ = require('lodash');
const stableStringify = require('json-stable-stringify');
const sseResponses = [];
const sseResponses = {};
let electronSender = null;
let pingConfigured = false;
@@ -12,12 +12,15 @@ module.exports = {
pingConfigured = true;
}
},
addSseResponse(value) {
sseResponses.push(value);
addSseResponse(value, strmid) {
sseResponses[strmid] = {
...sseResponses[strmid],
response: value,
};
this.ensurePing();
},
removeSseResponse(value) {
_.remove(sseResponses, x => x == value);
removeSseResponse(strmid) {
delete sseResponses[strmid];
},
setElectronSender(value) {
electronSender = value;
@@ -27,8 +30,25 @@ module.exports = {
if (electronSender) {
electronSender.send(message, data == null ? null : data);
}
for (const res of sseResponses) {
res.write(`event: ${message}\ndata: ${stableStringify(data == null ? null : data)}\n\n`);
for (const strmid in sseResponses) {
let skipThisStream = false;
if (sseResponses[strmid].filter) {
for (const key in sseResponses[strmid].filter) {
if (data && data[key]) {
if (!sseResponses[strmid].filter[key].includes(data[key])) {
skipThisStream = true;
break;
}
}
}
}
if (skipThisStream) {
continue;
}
sseResponses[strmid].response?.write(
`event: ${message}\ndata: ${stableStringify(data == null ? null : data)}\n\n`
);
}
},
emitChanged(key, params = undefined) {
@@ -36,4 +56,10 @@ module.exports = {
this.emit('changed-cache', { key, ...params });
// this.emit(key);
},
setStreamIdFilter(strmid, filter) {
sseResponses[strmid] = {
...sseResponses[strmid],
filter,
};
},
};
+2 -2
View File
@@ -1,5 +1,5 @@
const crypto = require('crypto');
const { getLogger } = require('dbgate-tools');
const uuidv1 = require('uuid/v1');
const { getSshTunnel } = require('./sshTunnel');
const logger = getLogger('sshTunnelProxy');
@@ -22,7 +22,7 @@ function handleGetSshTunnelResponse({ msgid, response }, subprocess) {
async function getSshTunnelProxy(connection) {
if (!process.send) return getSshTunnel(connection);
const msgid = uuidv1();
const msgid = crypto.randomUUID();
process.send({ msgtype: 'getsshtunnel-request', msgid, connection });
return new Promise((resolve, reject) => {
dispatchedMessages[msgid] = { resolve, reject };
+1 -1
View File
@@ -41,6 +41,6 @@
"dbgate-plugin-oracle": "^5.0.0-alpha.1",
"dbgate-web": "^5.0.0-alpha.1",
"dotenv": "^16.0.0",
"pinomin": "^1.0.1"
"pinomin": "^1.0.4"
}
}
+2 -2
View File
@@ -31,12 +31,12 @@
"typescript": "^4.4.3"
},
"dependencies": {
"dbgate-query-splitter": "^4.9.3",
"dbgate-query-splitter": "^4.10.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"debug": "^4.3.4",
"json-stable-stringify": "^1.0.1",
"lodash": "^4.17.21",
"pinomin": "^1.0.1",
"pinomin": "^1.0.4",
"uuid": "^3.4.0"
}
}
+19 -7
View File
@@ -4,6 +4,7 @@ import _groupBy from 'lodash/groupBy';
import _pick from 'lodash/pick';
import _compact from 'lodash/compact';
import { getLogger } from './getLogger';
import { type Logger } from 'pinomin';
const logger = getLogger('dbAnalyser');
@@ -37,9 +38,11 @@ export class DatabaseAnalyser {
singleObjectFilter: any;
singleObjectId: string = null;
dialect: SqlDialect;
logger: Logger;
constructor(public pool, public driver: EngineDriver, version) {
this.dialect = (driver?.dialectByVersion && driver?.dialectByVersion(version)) || driver?.dialect;
this.logger = logger;
}
async _runAnalysis() {
@@ -177,8 +180,15 @@ export class DatabaseAnalyser {
// return this.createQueryCore('=OBJECT_ID_CONDITION', typeFields) != ' is not null';
// }
createQuery(template, typeFields) {
return this.createQueryCore(template, typeFields);
createQuery(template, typeFields, replacements = {}) {
return this.createQueryCore(this.processQueryReplacements(template, replacements), typeFields);
}
processQueryReplacements(query, replacements) {
for (const repl in replacements) {
query = query.replaceAll(repl, replacements[repl]);
}
return query;
}
createQueryCore(template, typeFields) {
@@ -236,9 +246,9 @@ export class DatabaseAnalyser {
this.pool.feedback(obj);
}
if (obj && obj.analysingMessage) {
logger.debug(obj.analysingMessage);
logger.debug(obj.analysingMessage);
}
}
}
async getModifications() {
const snapshot = await this._getFastSnapshot();
@@ -299,8 +309,8 @@ export class DatabaseAnalyser {
return [..._compact(res), ...this.getDeletedObjects(snapshot)];
}
async analyserQuery(template, typeFields) {
const sql = this.createQuery(template, typeFields);
async analyserQuery(template, typeFields, replacements = {}) {
const sql = this.createQuery(template, typeFields, replacements);
if (!sql) {
return {
@@ -308,7 +318,9 @@ export class DatabaseAnalyser {
};
}
try {
return await this.driver.query(this.pool, sql);
const res = await this.driver.query(this.pool, sql);
this.logger.debug({ rows: res.rows.length, template }, `Loaded analyser query`);
return res;
} catch (err) {
logger.error({ err }, 'Error running analyser query');
return {
+13 -8
View File
@@ -199,14 +199,8 @@ export class SqlDumper implements AlterProcessor {
selectScopeIdentity(table: TableInfo) {}
columnDefinition(column: ColumnInfo, { includeDefault = true, includeNullable = true, includeCollate = true } = {}) {
if (column.computedExpression) {
this.put('^as %s', column.computedExpression);
if (column.isPersisted) this.put(' ^persisted');
return;
}
const type = column.dataType || this.dialect.fallbackDataType;
columnType(dataType: string) {
const type = dataType || this.dialect.fallbackDataType;
const typeWithValues = type.match(/([^(]+)(\(.+[^)]\))/);
if (typeWithValues?.length) {
@@ -217,6 +211,17 @@ export class SqlDumper implements AlterProcessor {
this.putRaw(SqlDumper.convertKeywordCase(type));
}
}
columnDefinition(column: ColumnInfo, { includeDefault = true, includeNullable = true, includeCollate = true } = {}) {
if (column.computedExpression) {
this.put('^as %s', column.computedExpression);
if (column.isPersisted) this.put(' ^persisted');
return;
}
this.columnType(column.dataType);
if (column.autoIncrement) {
this.autoIncrement();
}
@@ -56,24 +56,42 @@ export function createBulkInsertStreamBase(driver: EngineDriver, stream, pool, n
const rows = writable.buffer;
writable.buffer = [];
const dmp = driver.createDumper();
if (driver.dialect.allowMultipleValuesInsert) {
const dmp = driver.createDumper();
dmp.putRaw(`INSERT INTO ${fullNameQuoted} (`);
dmp.putCollection(',', writable.columnNames, col => dmp.putRaw(driver.dialect.quoteIdentifier(col as string)));
dmp.putRaw(')\n VALUES\n');
dmp.putRaw(`INSERT INTO ${fullNameQuoted} (`);
dmp.putCollection(',', writable.columnNames, col => dmp.putRaw(driver.dialect.quoteIdentifier(col as string)));
dmp.putRaw(')\n VALUES\n');
let wasRow = false;
for (const row of rows) {
if (wasRow) dmp.putRaw(',\n');
dmp.putRaw('(');
dmp.putCollection(',', writable.columnNames, col => dmp.putValue(row[col as string]));
dmp.putRaw(')');
wasRow = true;
}
dmp.putRaw(';');
// require('fs').writeFileSync('/home/jena/test.sql', dmp.s);
// console.log(dmp.s);
await driver.query(pool, dmp.s, { discardResult: true });
} else {
for (const row of rows) {
const dmp = driver.createDumper();
dmp.putRaw(`INSERT INTO ${fullNameQuoted} (`);
dmp.putCollection(',', writable.columnNames, col => dmp.putRaw(driver.dialect.quoteIdentifier(col as string)));
dmp.putRaw(')\n VALUES\n');
let wasRow = false;
for (const row of rows) {
if (wasRow) dmp.putRaw(',\n');
dmp.putRaw('(');
dmp.putCollection(',', writable.columnNames, col => dmp.putValue(row[col as string]));
dmp.putRaw(')');
wasRow = true;
dmp.putRaw('(');
dmp.putCollection(',', writable.columnNames, col => dmp.putValue(row[col as string]));
dmp.putRaw(')');
await driver.query(pool, dmp.s, { discardResult: true });
}
}
if (options.commitAfterInsert) {
const dmp = driver.createDumper();
dmp.commitTransaction();
await driver.query(pool, dmp.s, { discardResult: true });
}
dmp.putRaw(';');
// require('fs').writeFileSync('/home/jena/test.sql', dmp.s);
// console.log(dmp.s);
await driver.query(pool, dmp.s, { discardResult: true });
};
writable.sendIfFull = async () => {
+28 -15
View File
@@ -1,27 +1,40 @@
import pinomin, { Logger } from 'pinomin';
import pinomin, { Logger, type LogConfig } from 'pinomin';
let _logger: Logger;
let _logConfig: LogConfig;
let _name: string = null;
const defaultLogger: Logger = pinomin({
const defaultLogConfig: LogConfig = {
base: { pid: global?.process?.pid },
targets: [{ type: 'console', level: 'info' }],
});
};
export function setLogger(value: Logger) {
_logger = value;
export function setLogConfig(value: LogConfig) {
_logConfig = value;
}
export function setLoggerName(value) {
_name = value;
}
export function getLogger(caller?: string): Logger {
let res = _logger || defaultLogger;
if (caller) {
const props = { caller };
if (_name) {
props['name'] = _name;
}
res = res.child(props);
}
return res;
return pinomin({
getConfig: () => {
const config = _logConfig || defaultLogConfig;
if (caller) {
const props = { caller };
if (_name) {
props['name'] = _name;
}
return {
...config,
base: {
...config.base,
...props,
},
};
}
return config;
},
});
}
+4
View File
@@ -2,6 +2,10 @@ import type { DatabaseInfo, TableInfo, ApplicationDefinition, ViewInfo, Collecti
import _flatten from 'lodash/flatten';
export function addTableDependencies(db: DatabaseInfo): DatabaseInfo {
if (!db.tables) {
return db;
}
const allForeignKeys = _flatten(db.tables.map(x => x.foreignKeys || []));
return {
...db,
+1
View File
@@ -12,6 +12,7 @@ export interface SqlDialect {
defaultSchemaName?: string;
enableConstraintsPerTable?: boolean;
requireStandaloneSelectForScopeIdentity?: boolean;
allowMultipleValuesInsert?: boolean;
dropColumnDependencies?: string[];
changeColumnDependencies?: string[];
+1
View File
@@ -24,6 +24,7 @@ export interface WriteTableOptions {
dropIfExists?: boolean;
truncate?: boolean;
createIfNotExists?: boolean;
commitAfterInsert?: boolean;
}
export interface EngineAuthType {
+2 -2
View File
@@ -20,11 +20,11 @@
"@rollup/plugin-typescript": "^8.2.5",
"@tsconfig/svelte": "^1.0.0",
"ace-builds": "^1.4.8",
"chart.js": "^3.6.0",
"chart.js": "^4.4.2",
"chartjs-adapter-moment": "^1.0.0",
"cross-env": "^7.0.3",
"dbgate-datalib": "^5.0.0-alpha.1",
"dbgate-query-splitter": "^4.9.3",
"dbgate-query-splitter": "^4.10.1",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-types": "^5.0.0-alpha.1",
@@ -31,6 +31,7 @@
return [
{ text: 'Rename column', onClick: handleRenameColumn },
{ text: 'Drop column', onClick: handleDropColumn },
{ text: 'Copy name', onClick: () => navigator.clipboard.writeText(data.columnName)},
];
}
@@ -1,4 +1,6 @@
<script lang="ts" context="module">
import {copyTextToClipboard} from "../utility/clipboard";
export const extractKey = props => props.name;
export function disconnectDatabaseConnection(conid, database, showConfirmation = true) {
@@ -169,6 +171,10 @@
);
};
const handleCopyName = async () => {
copyTextToClipboard(name);
}
const handleDisconnect = () => {
disconnectDatabaseConnection(connection._id, name);
};
@@ -295,6 +301,7 @@
!connection.isReadOnly &&
!connection.singleDatabase && { onClick: handleDropDatabase, text: 'Drop database' },
{ divider: true },
driver?.databaseEngineTypes?.includes('sql') && { onClick: handleCopyName, text: 'Copy database name' },
driver?.databaseEngineTypes?.includes('sql') && { onClick: handleShowDiagram, text: 'Show diagram' },
driver?.databaseEngineTypes?.includes('sql') && { onClick: handleSqlGenerator, text: 'SQL Generator' },
driver?.supportsDatabaseProfiler && { onClick: handleDatabaseProfiler, text: 'Database profiler' },
@@ -1,4 +1,6 @@
<script lang="ts" context="module">
import {copyTextToClipboard} from "../utility/clipboard";
export const extractKey = ({ schemaName, pureName }) => (schemaName ? `${schemaName}.${pureName}` : pureName);
export const createMatcher =
({ schemaName, pureName, columns }) =>
@@ -80,6 +82,11 @@
isTruncate: true,
requiresWriteAccess: true,
},
{
label: 'Copy table name',
isCopyTableName: true,
requiresWriteAccess: false
},
{
label: 'Create table backup',
isDuplicateTable: true,
@@ -511,6 +518,8 @@
saveScriptToDatabase(dbid, `db.dropCollection('${data.pureName}')`);
},
});
} else if (menu.isCopyTableName) {
copyTextToClipboard(data.pureName);
} else if (menu.isRenameCollection) {
showModal(InputTextModal, {
label: 'New collection name',
+29
View File
@@ -38,6 +38,7 @@ import { getSettings } from '../utility/metadataLoaders';
import { isMac } from '../utility/common';
import { doLogout, internalRedirectTo } from '../clientAuth';
import { disconnectServerConnection } from '../appobj/ConnectionAppObject.svelte';
import UploadErrorModal from '../modals/UploadErrorModal.svelte';
// function themeCommand(theme: ThemeDefinition) {
// return {
@@ -575,6 +576,7 @@ export function registerFileCommands({
findReplace = false,
undoRedo = false,
executeAdditionalCondition = null,
copyPaste = false,
}) {
if (save) {
registerCommand({
@@ -645,6 +647,25 @@ export function registerFileCommands({
});
}
if (copyPaste) {
registerCommand({
id: idPrefix + '.copy',
category,
name: 'Copy',
disableHandleKeyText: 'CtrlOrCommand+C',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().copy(),
});
registerCommand({
id: idPrefix + '.paste',
category,
name: 'Paste',
disableHandleKeyText: 'CtrlOrCommand+V',
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().paste(),
});
}
if (findReplace) {
registerCommand({
id: idPrefix + '.find',
@@ -845,6 +866,14 @@ registerCommand({
onClick: () => getElectron().send('window-action', 'selectAll'),
});
registerCommand({
id: 'new.gist',
category: 'New',
name: 'Upload error to gist',
onClick: () => showModal(UploadErrorModal),
});
const electron = getElectron();
if (electron) {
electron.addEventListener('run-command', (e, commandId) => runCommand(commandId));
@@ -136,10 +136,11 @@
export let macroPreview;
export let macroValues;
export let selectedCellsPublished;
export let setLoadedRows = null;
// export let onChangeGrider = undefined;
export let loadedRows = [];
let loadedRows = [];
export const activator = createActivator('CollectionDataGridCore', false);
@@ -225,6 +226,11 @@
...createQuickExportMenu(quickExportHandler, { command: 'collectionDataGrid.export' }),
tag: 'export',
}));
function handleSetLoadedRows(rows) {
loadedRows = rows;
if (setLoadedRows) setLoadedRows(rows);
}
</script>
<LoadingDataGridCore
@@ -232,7 +238,7 @@
loadDataPage={loadCollectionDataPage}
{dataPageAvailable}
{loadRowCount}
bind:loadedRows
setLoadedRows={handleSetLoadedRows}
bind:selectedCellsPublished
frameSelection={!!macroPreview}
onOpenQuery={openQuery}
+4 -3
View File
@@ -88,8 +88,9 @@
export let macroCondition;
export let onRunMacro;
export let hasMultiColumnFilter = false;
export let setLoadedRows = null;
export let loadedRows;
let loadedRows;
export const activator = createActivator('DataGrid', false);
@@ -208,7 +209,7 @@
{#if isFormView}
<svelte:component this={formViewComponent} {...$$props} />
{:else if isJsonView}
<svelte:component this={jsonViewComponent} {...$$props} bind:loadedRows />
<svelte:component this={jsonViewComponent} {...$$props} {setLoadedRows} />
{:else}
<svelte:component
this={gridCoreComponent}
@@ -217,7 +218,7 @@
formViewAvailable={!!formViewComponent}
macroValues={extractMacroValuesForMacro($macroValues, $selectedMacro)}
macroPreview={$selectedMacro}
bind:loadedRows
{setLoadedRows}
bind:selectedCellsPublished
onChangeSelectedColumns={cols => {
if (domColumnManager) domColumnManager.setSelectedColumns(cols);
+10 -2
View File
@@ -38,6 +38,8 @@
id: 'dataGrid.revertAllChanges',
category: 'Data grid',
name: 'Revert all changes',
toolbarName: 'Revert all',
icon: 'icon undo',
testEnabled: () => getCurrentDataGrid()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataGrid().revertAllChanges(),
});
@@ -689,7 +691,6 @@
return;
}
openNewTab(
{
title: 'Map',
@@ -1008,6 +1009,8 @@
$: selectedCellsInfo = getSelectedCellsInfo(selectedCells, grider, realColumnUniqueNames, getSelectedRowData());
$: databaseStatus = useDatabaseStatus({ conid, database });
// $: console.log('visibleRealColumns', visibleRealColumns);
// $: console.log('visibleRowCountUpperBound', visibleRowCountUpperBound);
// $: console.log('rowHeight', rowHeight);
@@ -1163,6 +1166,7 @@
if (event.target.closest('.collapseButtonMarker')) return;
if (event.target.closest('.showFormButtonMarker')) return;
if (event.target.closest('.inplaceeditor-container')) return;
if (event.target.closest('input')) return;
shiftDragStartCell = null;
// event.target.closest('table').focus();
@@ -1737,7 +1741,11 @@
</script>
{#if !display || (!isDynamicStructure && (!columns || columns.length == 0))}
<LoadingInfo wrapper message="Waiting for structure" />
{#if $databaseStatus?.name == 'pending' || $databaseStatus?.name == 'checkStructure' || $databaseStatus?.name == 'loadStructure'}
<LoadingInfo wrapper message="Waiting for structure" />
{:else}
<ErrorInfo alignTop message="No structure was loaded, probably table doesn't exist in current database" />
{/if}
{:else if errorMessage}
<div>
<ErrorInfo message={errorMessage} alignTop />
+5 -1
View File
@@ -70,6 +70,10 @@
supportsReload,
!!changeSetState
);
function handleSetLoadedRows(rows) {
loadedRows = rows;
}
</script>
{#key jslid}
@@ -81,7 +85,7 @@
setConfig={config.update}
gridCoreComponent={JslDataGridCore}
formViewComponent={JslFormView}
bind:loadedRows
setLoadedRows={handleSetLoadedRows}
isDynamicStructure={!!infoUsed?.__isDynamicStructure}
useEvalFilters
showMacros={!!dispatchChangeSet}
@@ -72,7 +72,9 @@
export let selectedCellsPublished = () => [];
export const activator = createActivator('JslDataGridCore', false);
export let loadedRows = [];
export let setLoadedRows;
let loadedRows = [];
let domGrid;
let changeIndex = 0;
@@ -186,12 +188,17 @@
...createQuickExportMenu(quickExportHandler, { command: 'jslTableGrid.export' }),
tag: 'export',
}));
function handleSetLoadedRows(rows) {
loadedRows = rows;
setLoadedRows?.(rows);
}
</script>
<LoadingDataGridCore
bind:this={domGrid}
{...$$props}
bind:loadedRows
setLoadedRows={handleSetLoadedRows}
bind:selectedCellsPublished
{loadDataPage}
{dataPageAvailable}
@@ -16,10 +16,11 @@
export let rowCountLoaded = null;
export let preprocessLoadedRow = null;
export let setLoadedRows = null;
// export let griderFactory;
export let loadedRows = [];
let loadedRows = [];
let isLoading = false;
let isLoadedAll = false;
let loadedTime = new Date().getTime();
@@ -49,7 +50,6 @@
// await new Promise(resolve => setTimeout(resolve, 5000));
loadedTimeRef.set(loadStart);
// console.log('LOAD NEXT ROWS', loadedRows);
const nextRows = await loadDataPage(
$$props,
@@ -121,6 +121,8 @@
display.reload();
}
}
$: if (setLoadedRows) setLoadedRows(loadedRows);
</script>
<DataGridCore
@@ -212,6 +212,10 @@
tag: 'export',
})
);
function handleSetLoadedRows(rows) {
loadedRows = rows;
}
</script>
<LoadingDataGridCore
@@ -219,7 +223,7 @@
{loadDataPage}
{dataPageAvailable}
{loadRowCount}
bind:loadedRows
setLoadedRows={handleSetLoadedRows}
bind:selectedCellsPublished
frameSelection={!!macroPreview}
{grider}
@@ -49,7 +49,9 @@
if (index >= 0 && index + d >= 0 && index + d < current.columns?.length) {
let columns = [...current.columns];
[columns[index], columns[index + d]] = [columns[index + d], columns[index]];
const tmp = columns[index + d];
columns[index + d] = columns[index];
columns[index] = tmp;
return {
...current,
@@ -62,6 +62,7 @@
.main {
display: flex;
flex-direction: column;
overflow: auto;
}
.main.flex1 {
@@ -25,13 +25,14 @@
export let changeSetState;
export let dispatchChangeSet;
export let setLoadedRows;
export const activator = createActivator('CollectionJsonView', true);
let isLoading = false;
let loadedTime = null;
export let loadedRows = [];
let loadedRows = [];
let skip = 0;
let limit = 50;
@@ -39,6 +40,7 @@
isLoading = true;
// @ts-ignore
loadedRows = await loadCollectionDataPage($$props, parseInt(skip) || 0, parseInt(limit) || 50);
if (setLoadedRows) setLoadedRows(loadedRows);
isLoading = false;
loadedTime = new Date().getTime();
}
@@ -4,6 +4,9 @@
import { getFormContext } from '../forms/FormProviderCore.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import { useDatabaseList } from '../utility/metadataLoaders';
import uuidv1 from 'uuid/v1';
import { temporaryOpenedConnections } from '../stores';
import useEffect from '../utility/useEffect';
export let conidName;
@@ -17,6 +20,16 @@
})),
'label'
);
const tmpid = uuidv1();
$: effect = useEffect(() => {
temporaryOpenedConnections.update(x => [...x, { tmpid, conid: $values && $values[conidName] }]);
return () => {
temporaryOpenedConnections.update(x => x.filter(y => y.tmpid != tmpid));
};
});
$: $effect;
</script>
<FormSelectField {...$$restProps} options={databaseOptions} />
+3 -3
View File
@@ -15,7 +15,7 @@
import FormSelectField from '../forms/FormSelectField.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormButton from '../forms/FormButton.svelte';
import { apiCall } from '../utility/api';
import { apiCall } from '../utility/api';
export let editingData;
export let savingTab;
@@ -29,8 +29,8 @@ import { apiCall } from '../utility/api';
urlPath: _.kebabCase(_.deburr(savingTab.title)),
}
: editingData
? _.pick(editingData, savedProperties)
: {};
? _.pick(editingData, savedProperties)
: {};
$: savedFile = savingTab && savingTab.props && savingTab.props.savedFile;
@@ -0,0 +1,61 @@
<script lang="ts">
import _ from 'lodash';
import getElectron from '../utility/getElectron';
import hasPermission from '../utility/hasPermission';
import localforage from 'localforage';
import ModalBase from './ModalBase.svelte';
import uuidv1 from 'uuid/v1';
import { closeCurrentModal } from './modalTools';
import { copyTextToClipboard } from '../utility/clipboard';
import FormProvider from '../forms/FormProvider.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
import FormValues from '../forms/FormValues.svelte';
import FormSelectField from '../forms/FormSelectField.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormButton from '../forms/FormButton.svelte';
import { apiCall } from '../utility/api';
import FormConnectionSelect from '../impexp/FormConnectionSelect.svelte';
import FormDatabaseSelect from '../impexp/FormDatabaseSelect.svelte';
import { changeTab } from '../utility/common';
export let editingData;
export let callingTab;
const handleSubmit = async ev => {
const { conid, database } = ev.detail;
changeTab(callingTab.tabid, tab => ({
...tab,
props: {
...tab.props,
conid,
database,
},
}));
closeCurrentModal();
// console.log('SwitchDatabaseModal.handleSubmit', ev);
// changeTab(tabid, tab => ({ ...tab, busy }));
};
$: initialValues = {
conid: callingTab?.props?.conid,
database: callingTab?.props?.database,
};
</script>
<FormProvider {initialValues}>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">Switch database</svelte:fragment>
<FormConnectionSelect name="conid" label="Server" direction="source" isNative />
<FormDatabaseSelect conidName="conid" name="database" label="Database" isNative />
<svelte:fragment slot="footer">
<FormValues let:values>
<FormSubmit value="OK" on:click={handleSubmit} />
<FormButton value="Cancel" on:click={closeCurrentModal} />
</FormValues>
</svelte:fragment>
</ModalBase>
</FormProvider>
@@ -0,0 +1,66 @@
<script lang="ts">
import { onMount } from 'svelte';
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import FormTextField from '../forms/FormTextField.svelte';
import { apiCall } from '../utility/api';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
import { copyTextToClipboard } from '../utility/clipboard';
import Link from '../elements/Link.svelte';
import LoadingInfo from '../elements/LoadingInfo.svelte';
import { showSnackbarSuccess } from '../utility/snackbar';
import ErrorInfo from '../elements/ErrorInfo.svelte';
export let error = null;
let htmlUrl;
let url;
let errorMessage;
async function upload() {
const resp = await apiCall('uploads/upload-error-to-gist');
url = resp.url;
htmlUrl = resp.html_url;
errorMessage = resp.errorMessage;
}
onMount(() => {
upload();
});
async function handleDelete() {
const resp = await apiCall('uploads/delete-gist', { url });
closeCurrentModal();
showSnackbarSuccess('Gist was deleted');
}
function handleCopy() {
copyTextToClipboard(htmlUrl);
}
</script>
<ModalBase {...$$restProps}>
<svelte:fragment slot="header">Upload error</svelte:fragment>
{#if htmlUrl}
<div>
<p>
Upload error to gist was successful. Please copy gist URL abnd paste it to related github issue. You could check
uploaded data, if don't want to make them public, use Delete button to remove them from gist.
</p>
<p><Link href={htmlUrl}>Open uploaded data</Link></p>
</div>
{:else if errorMessage}
<ErrorInfo message={errorMessage} />
{:else}
<LoadingInfo message="Uploading error to gist..." />
{/if}
<svelte:fragment slot="footer">
<FormStyledButton value="Copy URL" disabled={!htmlUrl} on:click={handleCopy} />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton value="Delete" disabled={!url} on:click={handleDelete} />
</svelte:fragment>
</ModalBase>
@@ -123,6 +123,10 @@
{/if}
{/if}
{#if driver?.showConnectionField('serviceName', $values)}
<FormTextField label="Service name" name="serviceName" disabled={isConnected} />
{/if}
{#if driver?.showConnectionField('socketPath', $values)}
<FormTextField
label="Socket path"
@@ -74,6 +74,7 @@ ORDER BY
{ label: 'Themes', slot: 3 },
{ label: 'Default Actions', slot: 4 },
{ label: 'Confirmations', slot: 5 },
{ label: 'Other', slot: 6 },
]}
>
<svelte:fragment slot="1">
@@ -313,6 +314,15 @@ ORDER BY
label="Skip confirmation when saving collection data (NoSQL)"
/>
</svelte:fragment>
<svelte:fragment slot="6">
<div class="heading">Other</div>
<FormTextField
name="other.gistCreateToken"
label="API token for creating error gists"
defaultValue=""
/>
</svelte:fragment>
</TabControl>
</FormValues>
+10
View File
@@ -82,6 +82,7 @@ export const visibleSelectedWidget = derived(
export const emptyConnectionGroupNames = writableWithStorage([], 'emptyConnectionGroupNames');
export const collapsedConnectionGroupNames = writableWithStorage([], 'collapsedConnectionGroupNames');
export const openedConnections = writable([]);
export const temporaryOpenedConnections = writable([]);
export const openedSingleDatabaseConnections = writable([]);
export const expandedConnections = writable([]);
export const currentDatabase = writable(null);
@@ -144,6 +145,15 @@ export const activeDbKeysStore = writableWithStorage({}, 'activeDbKeysStore');
export const currentThemeDefinition = derived([currentTheme, extensions], ([$currentTheme, $extensions]) =>
$extensions.themes.find(x => x.themeClassName == $currentTheme)
);
export const openedConnectionsWithTemporary = derived(
[openedConnections, temporaryOpenedConnections, openedSingleDatabaseConnections],
([$openedConnections, $temporaryOpenedConnections, $openedSingleDatabaseConnections]) =>
_.uniq([
...$openedConnections,
...$temporaryOpenedConnections.map(x => x.conid),
...$openedSingleDatabaseConnections,
])
);
let nativeMenuOnStartup = null;
export const visibleTitleBar = derived(useSettings(), $settings => {
+13 -2
View File
@@ -292,6 +292,7 @@
import { useConnectionColorFactory } from '../utility/useConnectionColor';
import TabCloseButton from '../elements/TabCloseButton.svelte';
import CloseTabModal from '../modals/CloseTabModal.svelte';
import SwitchDatabaseModal from '../modals/SwitchDatabaseModal.svelte';
export let multiTabIndex;
export let shownTab;
@@ -304,8 +305,8 @@
$currentDatabase && $currentDatabase.name && $currentDatabase.connection
? `database://${$currentDatabase.name}-${$currentDatabase.connection._id}`
: $currentDatabase && $currentDatabase.connection
? `server://${$currentDatabase.connection._id}`
: '_no';
? `server://${$currentDatabase.connection._id}`
: '_no';
$: tabsWithDb = $openedTabs.filter(showTabFilterFunc).map(tab => ({
...tab,
@@ -372,6 +373,16 @@
onClick: () => showModal(FavoriteModal, { savingTab: tab }),
},
],
tabComponent &&
tabs[tabComponent] &&
tabs[tabComponent].allowSwitchDatabase &&
tabs[tabComponent].allowSwitchDatabase(props) && [
{ divider: true },
{
text: 'Switch database',
onClick: () => showModal(SwitchDatabaseModal, { callingTab: tab }),
},
],
{ divider: true },
appobj &&
appobj.createAppObjectMenu &&
@@ -3,6 +3,7 @@
export const matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
export const allowAddToFavorites = props => true;
export const allowSwitchDatabase = props => true;
registerCommand({
id: 'collectionTable.save',
@@ -167,11 +168,15 @@
$: setLocalStorage('collection_collapsedLeftColumn', $collapsedLeftColumnStore);
const quickExportHandlerRef = createQuickExportHandlerRef();
function handleSetLoadedRows(rows) {
loadedRows = rows;
}
</script>
<ToolStripContainer>
<DataGrid
bind:loadedRows
setLoadedRows={handleSetLoadedRows}
{...$$props}
config={$config}
setConfig={config.update}
@@ -193,6 +198,7 @@
<ToolStripCommandButton command="dataGrid.refresh" hideDisabled />
<ToolStripCommandButton command="dataForm.refresh" hideDisabled />
<ToolStripCommandButton command="collectionTable.save" />
<ToolStripCommandButton command="dataGrid.revertAllChanges" hideDisabled />
<ToolStripCommandButton command="dataGrid.insertNewRow" hideDisabled />
<ToolStripCommandButton command="dataGrid.deleteSelectedRows" hideDisabled />
<ToolStripCommandButton command="dataGrid.switchToJson" hideDisabled />
+11 -2
View File
@@ -26,7 +26,7 @@
} from '../stores';
import _, { Dictionary } from 'lodash';
import { apiCall } from '../utility/api';
import { showSnackbarSuccess } from '../utility/snackbar';
import { showSnackbarError, showSnackbarSuccess } from '../utility/snackbar';
import { changeTab } from '../utility/common';
import getConnectionLabel from '../utility/getConnectionLabel';
import { onMount } from 'svelte';
@@ -47,6 +47,9 @@
}
);
// $: console.log('ConnectionTab.$values', $values);
// $: console.log('ConnectionTab.driver', driver);
$: engine = $values.engine;
$: driver = $extensions.drivers.find(x => x.engine == engine);
@@ -81,6 +84,7 @@
'defaultDatabase',
'singleDatabase',
'socketPath',
'serviceName',
];
const visibleProps = allProps.filter(x => driver?.showConnectionField(x, $values));
const omitProps = _.difference(allProps, visibleProps);
@@ -161,7 +165,12 @@
onMount(async () => {
if (conid) {
$values = await apiCall('connections/get', { conid });
const con = await apiCall('connections/get', { conid });
if (con) {
$values = con;
} else {
showSnackbarError(`Connection not found: ${conid}`);
}
}
});
+29 -2
View File
@@ -1,4 +1,7 @@
<script lang="ts" context="module">
import registerCommand from '../commands/registerCommand';
import { copyTextToClipboard } from '../utility/clipboard';
const getCurrentEditor = () => getActiveComponent('QueryTab');
registerCommand({
@@ -37,6 +40,7 @@
toggleComment: true,
findReplace: true,
executeAdditionalCondition: () => getCurrentEditor()?.hasConnection(),
copyPaste: true,
});
registerCommand({
id: 'query.executeCurrent',
@@ -47,14 +51,14 @@
getCurrentEditor() != null && !getCurrentEditor()?.isBusy() && getCurrentEditor()?.hasConnection(),
onClick: () => getCurrentEditor().executeCurrent(),
});
export const allowSwitchDatabase = props => true;
</script>
<script lang="ts">
import { getContext, onDestroy, onMount } from 'svelte';
import sqlFormatter from 'sql-formatter';
import registerCommand from '../commands/registerCommand';
import VerticalSplitter from '../elements/VerticalSplitter.svelte';
import SqlEditor from '../query/SqlEditor.svelte';
import useEditorData from '../query/useEditorData';
@@ -81,6 +85,7 @@
import ToolStripExportButton, { createQuickExportHandlerRef } from '../buttons/ToolStripExportButton.svelte';
import ToolStripSaveButton from '../buttons/ToolStripSaveButton.svelte';
import ToolStripCommandSplitButton from '../buttons/ToolStripCommandSplitButton.svelte';
import { getClipboardText } from '../utility/clipboard';
export let tabid;
export let conid;
@@ -241,6 +246,17 @@
domEditor.getEditor().execCommand('togglecomment');
}
export function copy() {
const selectedText = domEditor.getEditor().getSelectedText();
copyTextToClipboard(selectedText);
}
export function paste() {
getClipboardText().then(text => {
domEditor.getEditor().execCommand('paste', text);
});
}
export function find() {
domEditor.getEditor().execCommand('find');
}
@@ -311,6 +327,8 @@
{ command: 'query.save' },
{ command: 'query.saveAs' },
{ divider: true },
{ command: 'query.copy' },
{ command: 'query.paste' },
{ command: 'query.find' },
{ command: 'query.replace' },
{ divider: true },
@@ -320,6 +338,15 @@
const quickExportHandlerRef = createQuickExportHandlerRef();
$: {
conid;
database;
if (canKill()) {
kill();
}
errorMessages = [];
}
let isInitialized = false;
</script>
@@ -57,6 +57,7 @@
export const matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
export const allowAddToFavorites = props => true;
export const allowSwitchDatabase = props => true;
</script>
<script lang="ts">
@@ -277,6 +278,7 @@
<ToolStripCommandButton command="dataForm.goToLast" hideDisabled />
<ToolStripCommandButton command="tableData.save" />
<ToolStripCommandButton command="dataGrid.revertAllChanges" hideDisabled />
<ToolStripCommandButton command="dataGrid.insertNewRow" hideDisabled />
<ToolStripCommandButton command="dataGrid.deleteSelectedRows" hideDisabled />
<ToolStripCommandButton command="dataGrid.switchToForm" hideDisabled />
+4 -3
View File
@@ -1,6 +1,7 @@
<script lang="ts" context="module">
export const matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
export const allowAddToFavorites = props => true;
export const allowSwitchDatabase = props => true;
</script>
<script lang="ts">
@@ -8,9 +9,9 @@
import { findEngineDriver } from 'dbgate-tools';
import { setContext } from 'svelte';
import { writable } from 'svelte/store';
import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte';
import ToolStripContainer from '../buttons/ToolStripContainer.svelte';
import ToolStripExportButton, { createQuickExportHandlerRef } from '../buttons/ToolStripExportButton.svelte';
import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte';
import ToolStripContainer from '../buttons/ToolStripContainer.svelte';
import ToolStripExportButton, { createQuickExportHandlerRef } from '../buttons/ToolStripExportButton.svelte';
import DataGrid from '../datagrid/DataGrid.svelte';
import SqlDataGridCore from '../datagrid/SqlDataGridCore.svelte';
+4 -1
View File
@@ -8,6 +8,9 @@ import { isOauthCallback, redirectToLogin } from '../clientAuth';
import { showModal } from '../modals/modalTools';
import DatabaseLoginModal, { isDatabaseLoginVisible } from '../modals/DatabaseLoginModal.svelte';
import _ from 'lodash';
import uuidv1 from 'uuid/v1';
export const strmid = uuidv1();
let eventSource;
let apiLogging = false;
@@ -49,7 +52,7 @@ export function removeVolatileMapping(conid) {
function wantEventSource() {
if (!eventSource) {
eventSource = new EventSource(`${resolveApi()}/stream`);
eventSource = new EventSource(`${resolveApi()}/stream?strmid=${strmid}`);
// eventSource.addEventListener('clean-cache', e => cacheClean(JSON.parse(e.data)));
}
}
+5
View File
@@ -66,6 +66,11 @@ export function copyTextToClipboard(text) {
}
}
/* Currently this doesn't work in firefox stable, but works in nightly */
export async function getClipboardText() {
return await navigator.clipboard.readText();
}
export function extractRowCopiedValue(row, col) {
let value = row[col];
if (value === undefined) value = _.get(row, col);
@@ -1,6 +1,6 @@
import _ from 'lodash';
import { openedConnections, currentDatabase } from '../stores';
import { apiCall } from './api';
import { openedConnections, currentDatabase, openedConnectionsWithTemporary } from '../stores';
import { apiCall, strmid } from './api';
import { getConnectionList } from './metadataLoaders';
// const doServerPing = async value => {
@@ -10,7 +10,7 @@ import { getConnectionList } from './metadataLoaders';
// };
const doServerPing = value => {
apiCall('server-connections/ping', { conidArray: value });
apiCall('server-connections/ping', { conidArray: value, strmid });
};
const doDatabasePing = value => {
@@ -26,7 +26,7 @@ let openedConnectionsHandle = null;
let currentDatabaseHandle = null;
export function subscribeConnectionPingers() {
openedConnections.subscribe(value => {
openedConnectionsWithTemporary.subscribe(value => {
doServerPing(value);
if (openedConnectionsHandle) window.clearInterval(openedConnectionsHandle);
openedConnectionsHandle = window.setInterval(() => doServerPing(value), 20 * 1000);
+1 -1
View File
@@ -97,7 +97,7 @@ function mapItem(item, commands) {
if (command) {
return {
text: item.text || command.menuName || command.toolbarName || command.name,
keyText: command.keyText || command.keyTextFromGroup,
keyText: command.keyText || command.keyTextFromGroup || command.disableHandleKeyText,
onClick: () => {
if (command.isGroupCommand) {
runGroupCommand(command.group);
@@ -24,6 +24,9 @@ function getConnectionLabelCore(connection, { allowExplicitDatabase = true } = {
if (connection.singleDatabase && connection.defaultDatabase) {
return `${connection.defaultDatabase}`;
}
if (connection.useDatabaseUrl) {
return `${connection.databaseUrl}`;
}
return '';
}
+4 -2
View File
@@ -61,6 +61,7 @@ function getFileEncoding(filePath, fs) {
}
function decodeFile(buf: Uint8Array, enc: string) {
// TODO: use import instead of window.require. Requires doesn't work in built electron app
const iconv = window.require('iconv-lite');
return iconv.decode(buf, enc);
}
@@ -120,8 +121,9 @@ export function openElectronFileCore(filePath, extensions) {
if (nameLower.endsWith('.sql')) {
const encoding = getFileEncoding(filePath, fs);
const buf = fs.readFileSync(filePath);
const data = decodeFile(buf, encoding);
const data = fs.readFileSync(filePath, { encoding });
// const buf = fs.readFileSync(filePath);
// const data = decodeFile(buf, encoding);
newQuery({
title: parsed.name,
@@ -189,6 +189,7 @@
padding: 0px 10px;
display: flex;
align-items: center;
white-space: nowrap;
}
.version {
-26
View File
@@ -1,26 +0,0 @@
diff --git a/node_modules/svelte/internal/index.js b/node_modules/svelte/internal/index.js
index 1cce90d..6220522 100644
--- a/node_modules/svelte/internal/index.js
+++ b/node_modules/svelte/internal/index.js
@@ -374,7 +374,7 @@ function insert_hydration(target, node, anchor) {
}
}
function detach(node) {
- node.parentNode.removeChild(node);
+ if (node.parentNode) node.parentNode.removeChild(node);
}
function destroy_each(iterations, detaching) {
for (let i = 0; i < iterations.length; i += 1) {
diff --git a/node_modules/svelte/internal/index.mjs b/node_modules/svelte/internal/index.mjs
index 6650e85..b746187 100644
--- a/node_modules/svelte/internal/index.mjs
+++ b/node_modules/svelte/internal/index.mjs
@@ -370,7 +370,7 @@ function insert_hydration(target, node, anchor) {
}
}
function detach(node) {
- node.parentNode.removeChild(node);
+ if (node.parentNode) node.parentNode.removeChild(node);
}
function destroy_each(iterations, detaching) {
for (let i = 0; i < iterations.length; i += 1) {
+2 -2
View File
@@ -35,7 +35,7 @@
"csv": "^5.3.2",
"dbgate-plugin-tools": "^1.0.7",
"lodash": "^4.17.21",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
}
+2 -2
View File
@@ -35,7 +35,7 @@
"lodash": "^4.17.21",
"xlsx": "0.16.9",
"dbgate-plugin-tools": "^1.0.7",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
}
+5 -5
View File
@@ -32,12 +32,12 @@
},
"devDependencies": {
"dbgate-plugin-tools": "^1.0.7",
"dbgate-query-splitter": "^4.9.3",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"dbgate-query-splitter": "^4.10.1",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4",
"dbgate-tools": "^5.0.0-alpha.1",
"is-promise": "^4.0.0",
"mongodb": "^4.7.0",
"mongodb-client-encryption": "^2.1.0"
"mongodb": "^6.3.0",
"mongodb-client-encryption": "^6.0.0"
}
}
@@ -10,9 +10,24 @@ class Analyser extends DatabaseAnalyser {
const collections = collectionsAndViews.filter((x) => x.type == 'collection');
const views = collectionsAndViews.filter((x) => x.type == 'view');
const stats = await Promise.all(
collections.filter((x) => x.type == 'collection').map((x) => this.pool.__getDatabase().collection(x.name).stats())
);
let stats;
try {
stats = await Promise.all(
collections
.filter((x) => x.type == 'collection')
.map((x) =>
this.pool
.__getDatabase()
.collection(x.name)
.aggregate([{ $collStats: { count: {} } }])
.toArray()
.then((resp) => ({ name: x.name, count: resp[0].count }))
)
);
} catch (e) {
// $collStats not supported
stats = {};
}
const res = this.mergeAnalyseResult({
collections: [
@@ -23,7 +23,9 @@ async function readCursor(cursor, options) {
function convertObjectId(condition) {
return _.cloneDeepWith(condition, (x) => {
if (x && x.$oid) return ObjectId(x.$oid);
if (x && x.$oid) {
return ObjectId.createFromHexString(x.$oid);
}
});
}
@@ -60,7 +62,9 @@ const driver = {
mongoUrl = databaseUrl;
}
} else {
mongoUrl = user ? `mongodb://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${server}:${port}` : `mongodb://${server}:${port}`;
mongoUrl = user
? `mongodb://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${server}:${port}`
: `mongodb://${server}:${port}`;
}
const options = {
@@ -93,7 +97,7 @@ const driver = {
let func;
func = eval(`(db,ObjectId) => ${sql}`);
const db = await getScriptableDb(pool);
const res = func(db, ObjectId);
const res = func(db, ObjectId.createFromHexString);
if (isPromise(res)) await res;
},
async stream(pool, sql, options) {
@@ -113,7 +117,7 @@ const driver = {
let exprValue;
try {
exprValue = func(db, ObjectId);
exprValue = func(db, ObjectId.createFromHexString);
} catch (err) {
options.info({
message: 'Error evaluating expression: ' + err.message,
@@ -227,7 +231,7 @@ const driver = {
func = eval(`(db,ObjectId) => ${sql}`);
const db = await getScriptableDb(pool);
exprValue = func(db, ObjectId);
exprValue = func(db, ObjectId.createFromHexString);
// return directly stream without header row
return exprValue.stream();
@@ -290,7 +294,7 @@ const driver = {
...insert.document,
...insert.fields,
};
const resdoc = await collection.insert(convertObjectId(document));
const resdoc = await collection.insertOne(convertObjectId(document));
res.inserted.push(resdoc._id);
}
for (const update of changeSet.updates) {
@@ -67,7 +67,7 @@ const driver = {
getCollectionUpdateScript(changeSet) {
let res = '';
for (const insert of changeSet.inserts) {
res += `db.${insert.pureName}.insert(${jsonStringifyWithObjectId({
res += `db.${insert.pureName}.insertOne(${jsonStringifyWithObjectId({
...insert.document,
...insert.fields,
})});\n`;
+4 -4
View File
@@ -32,11 +32,11 @@
},
"devDependencies": {
"dbgate-plugin-tools": "^1.0.7",
"dbgate-query-splitter": "^4.9.3",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"dbgate-query-splitter": "^4.10.1",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4",
"dbgate-tools": "^5.0.0-alpha.1",
"tedious": "^14.5.0",
"tedious": "^18.2.0",
"async-lock": "^1.2.6"
}
}
+3 -3
View File
@@ -33,10 +33,10 @@
"devDependencies": {
"antares-mysql-dumper": "^0.0.1",
"dbgate-plugin-tools": "^1.0.7",
"dbgate-query-splitter": "^4.9.3",
"dbgate-query-splitter": "^4.10.1",
"dbgate-tools": "^5.0.0-alpha.1",
"mysql2": "^3.6.5",
"webpack": "^5.89.0",
"mysql2": "^3.9.7",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
}
@@ -22,6 +22,7 @@ const dialect = {
enableConstraintsPerTable: false,
anonymousPrimaryKey: true,
explicitDropConstraint: true,
allowMultipleValuesInsert: true,
quoteIdentifier(s) {
return '`' + s + '`';
},
+6 -3
View File
@@ -31,10 +31,13 @@
},
"devDependencies": {
"dbgate-plugin-tools": "^1.0.8",
"dbgate-query-splitter": "^4.9.0",
"dbgate-query-splitter": "^4.10.1",
"dbgate-tools": "^5.0.0-alpha.1",
"lodash": "^4.17.21",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
},
"dependencies": {
"oracledb": "^6.5.1"
}
}

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