diff --git a/.github/workflows/build-app-beta.yaml b/.github/workflows/build-app-beta.yaml index ca9df362f..e5948beb2 100644 --- a/.github/workflows/build-app-beta.yaml +++ b/.github/workflows/build-app-beta.yaml @@ -6,9 +6,13 @@ name: Electron app BETA push: tags: - v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+ +permissions: + id-token: write + contents: write jobs: build: runs-on: ${{ matrix.os }} + environment: dbgate-app strategy: fail-fast: false matrix: @@ -60,21 +64,53 @@ jobs: - name: Install Snapcraft if: matrix.os == 'ubuntu-22.04' uses: samuelmeuli/action-snapcraft@v1 - - name: Publish + - name: Publish Windows + if: matrix.os == 'windows-2022' + run: | + + yarn run build:app + - name: Publish MacOS + if: matrix.os == 'macos-14' run: | yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} 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 }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + - name: Publish Linux + if: matrix.os == 'ubuntu-22.04' + run: | + + yarn run build:app + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} + - name: Azure login (OIDC) + uses: azure/login@v2 + if: matrix.os == 'windows-2022' + with: + client-id: ${{ secrets.AZURE_TC_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TC_TENANT_ID }} + allow-no-subscriptions: true + - name: Sign Windows artifacts with Azure Trusted Signing + uses: azure/trusted-signing-action@v0 + if: matrix.os == 'windows-2022' + with: + endpoint: https://wus3.codesigning.azure.net/ + trusted-signing-account-name: DbGate + certificate-profile-name: DbGate-Release + files-folder: app/dist + files-folder-filter: exe + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + - name: Fix YML hashes + if: matrix.os == 'windows-2022' + run: | + + yarn run fixYmlHashes - name: Copy artifacts run: | mkdir artifacts diff --git a/.github/workflows/build-app-check.yaml b/.github/workflows/build-app-check.yaml index c5686419e..173a21fad 100644 --- a/.github/workflows/build-app-check.yaml +++ b/.github/workflows/build-app-check.yaml @@ -6,9 +6,13 @@ name: Electron app check build push: tags: - check-[0-9]+-[0-9]+-[0-9]+.[0-9]+ +permissions: + id-token: write + contents: write jobs: build: runs-on: ${{ matrix.os }} + environment: dbgate-app strategy: fail-fast: false matrix: @@ -56,21 +60,53 @@ jobs: - name: Install Snapcraft if: matrix.os == 'ubuntu-22.04' uses: samuelmeuli/action-snapcraft@v1 - - name: Publish + - name: Publish Windows + if: matrix.os == 'windows-2022' + run: | + + yarn run build:app + - name: Publish MacOS + if: matrix.os == 'macos-14' run: | yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} 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 }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + - name: Publish Linux + if: matrix.os == 'ubuntu-22.04' + run: | + + yarn run build:app + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} + - name: Azure login (OIDC) + uses: azure/login@v2 + if: matrix.os == 'windows-2022' + with: + client-id: ${{ secrets.AZURE_TC_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TC_TENANT_ID }} + allow-no-subscriptions: true + - name: Sign Windows artifacts with Azure Trusted Signing + uses: azure/trusted-signing-action@v0 + if: matrix.os == 'windows-2022' + with: + endpoint: https://wus3.codesigning.azure.net/ + trusted-signing-account-name: DbGate + certificate-profile-name: DbGate-Release + files-folder: app/dist + files-folder-filter: exe + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + - name: Fix YML hashes + if: matrix.os == 'windows-2022' + run: | + + yarn run fixYmlHashes - name: Copy artifacts run: | mkdir artifacts diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index 4f1cd8591..9cdbdf1f6 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -6,9 +6,13 @@ name: Electron app PREMIUM BETA push: tags: - v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+ +permissions: + id-token: write + contents: write jobs: build: runs-on: ${{ matrix.os }} + environment: dbgate-app strategy: fail-fast: false matrix: @@ -39,7 +43,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 11203754aad94189b565c2816d37760b15c8e07f + ref: f27a03d4aff5b00a009643df146a9c17bdbf7801 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro @@ -87,23 +91,61 @@ jobs: cd dbgate-merged yarn fillPackagedPlugins - - name: Publish + - name: Publish Windows + if: matrix.os == 'windows-2022' + run: | + cd .. + cd dbgate-merged + + yarn run build:app + - name: Publish MacOS + if: matrix.os == 'macos-14' run: | cd .. cd dbgate-merged yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} 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 }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + - name: Publish Linux + if: matrix.os == 'ubuntu-22.04' + run: | + cd .. + cd dbgate-merged + + yarn run build:app + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} + - name: Azure login (OIDC) + uses: azure/login@v2 + if: matrix.os == 'windows-2022' + with: + client-id: ${{ secrets.AZURE_TC_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TC_TENANT_ID }} + allow-no-subscriptions: true + - name: Sign Windows artifacts with Azure Trusted Signing + uses: azure/trusted-signing-action@v0 + if: matrix.os == 'windows-2022' + with: + endpoint: https://wus3.codesigning.azure.net/ + trusted-signing-account-name: DbGate + certificate-profile-name: DbGate-Release + files-folder: ../dbgate-merged/app/dist + files-folder-filter: exe + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + - name: Fix YML hashes + if: matrix.os == 'windows-2022' + run: | + cd .. + cd dbgate-merged + + yarn run fixYmlHashes - name: Copy artifacts run: | mkdir artifacts diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index 6ad30d299..72fa001f0 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -6,9 +6,13 @@ name: Electron app PREMIUM push: tags: - v[0-9]+.[0-9]+.[0-9]+ +permissions: + id-token: write + contents: write jobs: build: runs-on: ${{ matrix.os }} + environment: dbgate-app strategy: fail-fast: false matrix: @@ -39,7 +43,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 11203754aad94189b565c2816d37760b15c8e07f + ref: f27a03d4aff5b00a009643df146a9c17bdbf7801 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro @@ -87,23 +91,61 @@ jobs: cd dbgate-merged yarn fillPackagedPlugins - - name: Publish + - name: Publish Windows + if: matrix.os == 'windows-2022' + run: | + cd .. + cd dbgate-merged + + yarn run build:app + - name: Publish MacOS + if: matrix.os == 'macos-14' run: | cd .. cd dbgate-merged yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} 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 }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + - name: Publish Linux + if: matrix.os == 'ubuntu-22.04' + run: | + cd .. + cd dbgate-merged + + yarn run build:app + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} + - name: Azure login (OIDC) + uses: azure/login@v2 + if: matrix.os == 'windows-2022' + with: + client-id: ${{ secrets.AZURE_TC_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TC_TENANT_ID }} + allow-no-subscriptions: true + - name: Sign Windows artifacts with Azure Trusted Signing + uses: azure/trusted-signing-action@v0 + if: matrix.os == 'windows-2022' + with: + endpoint: https://wus3.codesigning.azure.net/ + trusted-signing-account-name: DbGate + certificate-profile-name: DbGate-Release + files-folder: ../dbgate-merged/app/dist + files-folder-filter: exe + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + - name: Fix YML hashes + if: matrix.os == 'windows-2022' + run: | + cd .. + cd dbgate-merged + + yarn run fixYmlHashes - name: Copy artifacts run: | mkdir artifacts diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index 22545dd62..212f72a2b 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -6,9 +6,13 @@ name: Electron app push: tags: - v[0-9]+.[0-9]+.[0-9]+ +permissions: + id-token: write + contents: write jobs: build: runs-on: ${{ matrix.os }} + environment: dbgate-app strategy: fail-fast: false matrix: @@ -56,24 +60,56 @@ jobs: - name: Install Snapcraft if: matrix.os == 'ubuntu-22.04' uses: samuelmeuli/action-snapcraft@v1 - - name: Publish + - name: Publish Windows + if: matrix.os == 'windows-2022' + run: | + + yarn run build:app + - name: Publish MacOS + if: matrix.os == 'macos-14' run: | yarn run build:app env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} - WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }} CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }} 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 }} - SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} APPLE_APP_SPECIFIC_PASSWORD: ${{secrets.APPLE_APP_SPECIFIC_PASSWORD}} + - name: Publish Linux + if: matrix.os == 'ubuntu-22.04' + run: | + + yarn run build:app + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}} - name: generatePadFile run: | yarn generatePadFile + - name: Azure login (OIDC) + uses: azure/login@v2 + if: matrix.os == 'windows-2022' + with: + client-id: ${{ secrets.AZURE_TC_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TC_TENANT_ID }} + allow-no-subscriptions: true + - name: Sign Windows artifacts with Azure Trusted Signing + uses: azure/trusted-signing-action@v0 + if: matrix.os == 'windows-2022' + with: + endpoint: https://wus3.codesigning.azure.net/ + trusted-signing-account-name: DbGate + certificate-profile-name: DbGate-Release + files-folder: app/dist + files-folder-filter: exe + timestamp-rfc3161: http://timestamp.acs.microsoft.com + timestamp-digest: SHA256 + - name: Fix YML hashes + if: matrix.os == 'windows-2022' + run: | + + yarn run fixYmlHashes - name: Copy artifacts run: | mkdir artifacts diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index dc5cb248e..e69e17de9 100644 --- a/.github/workflows/build-cloud-pro.yaml +++ b/.github/workflows/build-cloud-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 11203754aad94189b565c2816d37760b15c8e07f + ref: f27a03d4aff5b00a009643df146a9c17bdbf7801 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-docker-pro.yaml b/.github/workflows/build-docker-pro.yaml index 519e08fe7..1dd394cf6 100644 --- a/.github/workflows/build-docker-pro.yaml +++ b/.github/workflows/build-docker-pro.yaml @@ -44,7 +44,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 11203754aad94189b565c2816d37760b15c8e07f + ref: f27a03d4aff5b00a009643df146a9c17bdbf7801 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-npm-pro.yaml b/.github/workflows/build-npm-pro.yaml index 054be0c9c..dfa2cdb31 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -7,6 +7,9 @@ name: NPM packages PREMIUM tags: - v[0-9]+.[0-9]+.[0-9]+ - v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+ +permissions: + id-token: write + contents: write jobs: build: runs-on: ${{ matrix.os }} @@ -32,7 +35,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 11203754aad94189b565c2816d37760b15c8e07f + ref: f27a03d4aff5b00a009643df146a9c17bdbf7801 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro @@ -49,13 +52,8 @@ jobs: cd .. cd dbgate-merged node adjustNpmPackageJsonPremium - - name: Configure NPM token - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - cd .. - cd dbgate-merged - npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}" + - name: Update npm + run: npm install -g npm@latest - name: Remove dbmodel - should be not published run: | cd .. @@ -71,28 +69,35 @@ jobs: cd .. cd dbgate-merged yarn setCurrentVersion + - name: Compute npm dist-tag + run: | + if [[ "${GITHUB_REF_NAME}" =~ -alpha\. ]]; then + echo "NPM_TAG=alpha" >> $GITHUB_ENV + else + echo "NPM_TAG=latest" >> $GITHUB_ENV + fi - name: Publish dbgate-api-premium run: | cd .. cd dbgate-merged/packages/api - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-web-premium run: | cd .. cd dbgate-merged/packages/web - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-serve-premium run: | cd .. cd dbgate-merged/packages/serve - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-cosmosdb run: | cd .. cd dbgate-merged/plugins/dbgate-plugin-cosmosdb - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-firestore run: | cd .. cd dbgate-merged/plugins/dbgate-plugin-firestore - npm publish + npm publish --tag "$NPM_TAG" diff --git a/.github/workflows/build-npm.yaml b/.github/workflows/build-npm.yaml index 9b815cea7..079c25f8a 100644 --- a/.github/workflows/build-npm.yaml +++ b/.github/workflows/build-npm.yaml @@ -7,6 +7,9 @@ name: NPM packages tags: - v[0-9]+.[0-9]+.[0-9]+ - v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+ +permissions: + id-token: write + contents: write jobs: build: runs-on: ${{ matrix.os }} @@ -26,103 +29,107 @@ jobs: uses: actions/setup-node@v1 with: node-version: 22.x - - name: Configure NPM token - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}" + - name: Update npm + run: npm install -g npm@latest - name: yarn install run: | yarn install - name: setCurrentVersion run: | yarn setCurrentVersion + - name: Compute npm dist-tag + run: | + if [[ "${GITHUB_REF_NAME}" =~ -alpha\. ]]; then + echo "NPM_TAG=alpha" >> $GITHUB_ENV + else + echo "NPM_TAG=latest" >> $GITHUB_ENV + fi - name: Publish types working-directory: packages/types run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish tools working-directory: packages/tools run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish sqltree working-directory: packages/sqltree run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish api working-directory: packages/api run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish datalib working-directory: packages/datalib run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish filterparser working-directory: packages/filterparser run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish web working-directory: packages/web run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-serve working-directory: packages/serve run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbmodel working-directory: packages/dbmodel run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-csv working-directory: plugins/dbgate-plugin-csv run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-xml working-directory: plugins/dbgate-plugin-xml run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-excel working-directory: plugins/dbgate-plugin-excel run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-mssql working-directory: plugins/dbgate-plugin-mssql run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-mysql working-directory: plugins/dbgate-plugin-mysql run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-mongo working-directory: plugins/dbgate-plugin-mongo run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-postgres working-directory: plugins/dbgate-plugin-postgres run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-sqlite working-directory: plugins/dbgate-plugin-sqlite run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-redis working-directory: plugins/dbgate-plugin-redis run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-oracle working-directory: plugins/dbgate-plugin-oracle run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-clickhouse working-directory: plugins/dbgate-plugin-clickhouse run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-dbf working-directory: plugins/dbgate-plugin-dbf run: | - npm publish + npm publish --tag "$NPM_TAG" - name: Publish dbgate-plugin-cassandra working-directory: plugins/dbgate-plugin-cassandra run: | - npm publish + npm publish --tag "$NPM_TAG" diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index 7df23b243..f2566871d 100644 --- a/.github/workflows/e2e-pro.yaml +++ b/.github/workflows/e2e-pro.yaml @@ -26,7 +26,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 11203754aad94189b565c2816d37760b15c8e07f + ref: f27a03d4aff5b00a009643df146a9c17bdbf7801 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/CHANGELOG.md b/CHANGELOG.md index 82ddc86c2..c9a0b847b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,37 @@ Builds: - linux - application for linux - win - application for Windows +## 6.6.11 +- FIXED: Fixed theming on application startup +- CHANGED: Improved licensing page + +## 6.6.10 +- FIXED: License from environment variable is not refreshed #1245 +- FIXED: connection closing / reconnecting #1237 +- ADDED: retain history across multiple queries #1236 +- ADDED: load CSVs to temp tables #1235 +- FIXED: Not possible to scroll the data view horizontally by pressing shift and scroll mouse middle button on Mac #453 +- FIXED: Expired trial workflow (Premium) +- ADDED: Column name collision resolving #1234 (MySQL) + +## 6.6.8 +- CHANGED: Windows executable now uses Azure trusted signing certificate +- CHANGED: NPM packages now use GitHub OIDC provenance signing for better security +- CHANGED: Some features moved to Premium edition (master/detail views, FK lookups, column expansion, split view, advanced export/import, data archives, grouping, macros) + +## 6.6.6 +- ADDED: Allow disable/re-enable filter #1174 +- ADDED: Close right side tabs #1219 +- ADDED: Ability disable execute current line in query editor #1209 +- ADDED: Support for Redis Cluster #1204 (Premium) + ## 6.6.5 - ADDED: SQL AI assistant - powered by database chat, could help you to write SQL queries (Premium) - ADDED: Explain SQL error (powered by AI) (Premium) - ADDED: Database chat (and SQL AI Assistant) now supports showing charts (Premium) - FIXED: Fxied editing new files and roles (Team Premium) - FIXED: Connection to standalone database could be now pinned +- FIXED: Cannot open up large JSON file #1215 ## 6.6.4 - ADDED: AI Database chat now supports much more LLM models. (Premium) diff --git a/README.md b/README.md index 40b0051af..639af9c4c 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,9 @@ DbGate is licensed under GPL-3.0 license and is free to use for any purpose. * Try it online - [demo.dbgate.org](https://demo.dbgate.org) - online demo application * **Download** application for Windows, Linux or Mac from [dbgate.io](https://www.dbgate.io/download/) -* Looking for DbGate Community? **Download** from [dbgate.org](https://dbgate.org/download/) +* Looking for DbGate Community? **Download** from [dbgate.io](https://www.dbgate.io/download-community/) * Run web version as [NPM package](https://www.npmjs.com/package/dbgate-serve) or as [docker image](https://hub.docker.com/r/dbgate/dbgate) * Use nodeJs [scripting interface](https://docs.dbgate.io/scripting) ([API documentation](https://docs.dbgate.io/apidoc)) -* [Recommend DbGate](https://testimonial.to/dbgate) | [Rate on G2](https://www.g2.com/products/dbgate/reviews) -* [Give us feedback](https://dbgate.org/feedback) - it will help us to decide, how to improve DbGate in future -* We [offer 2-year PREMIUM license](https://dbgate.org/review/) for any honest review on these platforms (time-limited offer) ## Supported databases * MySQL @@ -93,7 +90,6 @@ 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 * Purchase a [DbGate Premium](https://www.dbgate.io/purchase/premium/) license -* Write review on [Product Hunt](https://www.producthunt.com/products/dbgate) or [G2](https://www.g2.com/products/dbgate/reviews) - we offer [2-year PREMIUM license](https://dbgate.org/review/) for reviewers (time limited offer) * 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 * 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) diff --git a/app/package.json b/app/package.json index 8db96276c..1fe96dde0 100644 --- a/app/package.json +++ b/app/package.json @@ -117,7 +117,7 @@ "scripts": { "start": "cross-env ELECTRON_START_URL=http://localhost:5001 DEVMODE=1 electron .", "start:local": "cross-env electron .", - "dist": "electron-builder", + "dist": "electron-builder --publish never", "build": "cd ../packages/api && yarn build && cd ../web && yarn build && cd ../../app && yarn dist", "build:local": "cd ../packages/api && yarn build && cd ../web && yarn build && cd ../../app && yarn predist", "postinstall": "yarn rebuild && patch-package", @@ -128,7 +128,7 @@ "devDependencies": { "copyfiles": "^2.2.0", "cross-env": "^6.0.3", - "electron": "30.0.2", + "electron": "38.6.0", "electron-builder": "25.1.8" } } diff --git a/app/src/electron.js b/app/src/electron.js index d78de3702..46b137162 100644 --- a/app/src/electron.js +++ b/app/src/electron.js @@ -85,7 +85,7 @@ function formatKeyText(keyText) { return keyText.replace('CtrlOrCommand+', 'Ctrl+'); } -function commandItem(item) { +function commandItem(item, disableAll = false) { const id = item.command; const command = commands[id]; if (item.skipInApp) { @@ -95,7 +95,7 @@ function commandItem(item) { id, label: command ? command.menuName || command.toolbarName || command.name : id, accelerator: formatKeyText(command ? command.keyText : undefined), - enabled: command ? command.enabled : false, + enabled: command ? command.enabled && !disableAll : false, click() { if (mainWindow) { mainWindow.webContents.send('run-command', id); @@ -107,14 +107,14 @@ function commandItem(item) { }; } -function buildMenu() { +function buildMenu(disableAll = false) { let template = _cloneDeepWith(mainMenuDefinition({ editMenu: true, isMac: isMac() }), item => { if (item.divider) { return { type: 'separator' }; } if (item.command) { - return commandItem(item); + return commandItem(item, disableAll); } }); @@ -129,7 +129,7 @@ function buildMenu() { { label: 'DbGate', submenu: [ - commandItem({ command: 'about.show' }), + commandItem({ command: 'about.show' }, disableAll), { role: 'services' }, { role: 'hide' }, { role: 'hideOthers' }, @@ -145,7 +145,10 @@ function buildMenu() { } ipcMain.on('update-commands', async (event, arg) => { - commands = JSON.parse(arg); + const parsed = JSON.parse(arg); + commands = parsed.commands; + const isModalOpened = parsed.isModalOpened; + const dbgatePage = parsed.dbgatePage; for (const key of Object.keys(commands)) { const menu = mainMenu.getMenuItemById(key); if (!menu) continue; @@ -153,14 +156,14 @@ ipcMain.on('update-commands', async (event, arg) => { // rebuild menu if (menu.label != command.text || menu.accelerator != command.keyText) { - mainMenu = buildMenu(); + mainMenu = buildMenu(isModalOpened || !!dbgatePage); Menu.setApplicationMenu(mainMenu); // mainWindow.setMenu(mainMenu); return; } - menu.enabled = command.enabled; + menu.enabled = command.enabled && !isModalOpened && !dbgatePage; } }); ipcMain.on('quit-app', async (event, arg) => { diff --git a/app/yarn.lock b/app/yarn.lock index fc23b421a..9b55f6bc6 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -16,9 +16,9 @@ ajv-keywords "^3.4.1" "@electron/asar@^3.2.7": - version "3.2.17" - resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.17.tgz#91d28087aad80d1a1c8cc4e667c6476edf50f949" - integrity sha512-OcWImUI686w8LkghQj9R2ynZ2ME693Ek6L1SiaAgqGKzBaTIZw3fHDqN82Rcl+EU1Gm9EgkJ5KLIY/q5DCRbbA== + version "3.4.1" + resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.4.1.tgz#4e9196a4b54fba18c56cd8d5cac67c5bdc588065" + integrity sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA== dependencies: commander "^5.0.0" glob "^7.1.6" @@ -98,6 +98,18 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@isaacs/balanced-match@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29" + integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ== + +"@isaacs/brace-expansion@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz#4b3dabab7d8e75a429414a96bd67bf4c1d13e0f3" + integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA== + dependencies: + "@isaacs/balanced-match" "^4.0.1" + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -202,16 +214,23 @@ "@types/node" "*" "@types/ms@*": - version "0.7.34" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" - integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" + integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== -"@types/node@*", "@types/node@^20.9.0": - version "20.12.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.10.tgz#8f0c3f12b0f075eee1fe20c1afb417e9765bef76" - integrity sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw== +"@types/node@*": + version "24.10.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.10.0.tgz#6b79086b0dfc54e775a34ba8114dcc4e0221f31f" + integrity sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A== dependencies: - undici-types "~5.26.4" + undici-types "~7.16.0" + +"@types/node@^22.7.7": + version "22.19.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.0.tgz#849606ef3920850583a4e7ee0930987c35ad80be" + integrity sha512-xpr/lmLPQEj+TUnHmR+Ab91/glhJvsqcjB+yY0Ix9GO70H6Lb4FHH5GeqdOE5btAx7eIMwuHkp4H2MSkLcqWbA== + dependencies: + undici-types "~6.21.0" "@types/plist@^3.0.1": version "3.0.5" @@ -229,9 +248,9 @@ "@types/node" "*" "@types/verror@^1.10.3": - version "1.10.10" - resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.10.tgz#d5a4b56abac169bfbc8b23d291363a682e6fa087" - integrity sha512-l4MM0Jppn18hb9xmM6wwD1uTdShpf9Pn80aXTStnK1C94gtPvJcV2FrDmbOQUAQfJ1cKZHktkQUDwEqaAKXMMg== + version "1.10.11" + resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.11.tgz#d3d6b418978c8aa202d41e5bb3483227b6ecc1bb" + integrity sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg== "@types/yauzl@^2.9.1": version "2.10.3" @@ -241,9 +260,9 @@ "@types/node" "*" "@xmldom/xmldom@^0.8.8": - version "0.8.10" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" - integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw== + version "0.8.11" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz#b79de2d67389734c57c52595f7a7305e30c2d608" + integrity sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw== "@yarnpkg/lockfile@^1.1.0": version "1.1.0" @@ -263,14 +282,14 @@ agent-base@6, agent-base@^6.0.2: debug "4" agent-base@^7.1.0, agent-base@^7.1.2: - version "7.1.3" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" - integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + version "7.1.4" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8" + integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== agentkeepalive@^4.2.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" - integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + version "4.6.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== dependencies: humanize-ms "^1.2.1" @@ -303,9 +322,9 @@ ansi-regex@^5.0.1: integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" - integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + version "6.2.2" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1" + integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" @@ -315,9 +334,9 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: color-convert "^2.0.1" ansi-styles@^6.1.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" - integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + version "6.2.3" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" + integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== app-builder-bin@5.0.0-alpha.10: version "5.0.0-alpha.10" @@ -363,9 +382,9 @@ app-builder-lib@25.1.8: temp-file "^3.4.0" "aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + version "2.1.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.1.0.tgz#75500a190313d95c64e871e7e4284c6ac219f0b1" + integrity sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew== are-we-there-yet@^3.0.0: version "3.0.1" @@ -395,10 +414,10 @@ async-exit-hook@^2.0.1: resolved "https://registry.yarnpkg.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz#8bd8b024b0ec9b1c01cccb9af9db29bd717dfaf3" integrity sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw== -async@^3.2.3: - version "3.2.5" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== +async@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" @@ -447,33 +466,33 @@ boolean@^3.0.1: integrity sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw== brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== dependencies: balanced-match "^1.0.0" -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== -buffer-equal-constant-time@1.0.1: +buffer-equal-constant-time@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== @@ -499,10 +518,10 @@ builder-util-runtime@9.2.10: debug "^4.3.4" sax "^1.2.4" -builder-util-runtime@9.2.5: - version "9.2.5" - resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.5.tgz#0afdffa0adb5c84c14926c7dd2cf3c6e96e9be83" - integrity sha512-HjIDfhvqx/8B3TDN4GbABQcgpewTU4LMRTQPkVpKYV3lsuxEJoIfvg09GyWTNmfVNSUAYf+fbTN//JX4TH20pg== +builder-util-runtime@9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz#0daedde0f6d381f2a00a50a407b166fe7dca1a67" + integrity sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ== dependencies: debug "^4.3.4" sax "^1.2.4" @@ -571,7 +590,15 @@ cacheable-request@^7.0.2: normalize-url "^6.0.1" responselike "^2.0.0" -chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2: +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -744,9 +771,9 @@ cross-env@^6.0.3: cross-spawn "^7.0.0" cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + version "6.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57" + integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw== dependencies: nice-try "^1.0.4" path-key "^2.0.1" @@ -754,26 +781,19 @@ cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" which "^2.0.1" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -debug@^4.3.3: - version "4.4.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== dependencies: ms "^2.1.3" @@ -825,9 +845,9 @@ delegates@^1.0.0: integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== detect-libc@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" - integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + version "2.1.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" + integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== detect-node@^2.0.4: version "2.1.0" @@ -878,9 +898,18 @@ dotenv-expand@^11.0.6: dotenv "^16.4.5" dotenv@^16.4.5: - version "16.4.7" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" - integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== + version "16.6.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.6.1.tgz#773f0e69527a8315c7285d5ee73c4459d20a8020" + integrity sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" eastasianwidth@^0.2.0: version "0.2.0" @@ -936,11 +965,11 @@ electron-publish@25.1.7: mime "^2.5.2" electron-updater@^6.3.4: - version "6.3.4" - resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.3.4.tgz#3934bc89875bb524c2cbbd11041114e97c0c2496" - integrity sha512-uZUo7p1Y53G4tl6Cgw07X1yF8Jlz6zhaL7CQJDZ1fVVkOaBfE2cWtx80avwDVi8jHp+I/FWawrMgTAeCCNIfAg== + version "6.6.2" + resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.6.2.tgz#3e65e044f1a99b00d61e200e24de8e709c69ce99" + integrity sha512-Cr4GDOkbAUqRHP5/oeOmH/L2Bn6+FQPxVLZtPbcmKZC63a1F3uu5EefYOssgZXG3u/zBlubbJ5PJdITdMVggbw== dependencies: - builder-util-runtime "9.2.5" + builder-util-runtime "9.3.1" fs-extra "^10.1.0" js-yaml "^4.1.0" lazy-val "^1.0.5" @@ -949,13 +978,13 @@ electron-updater@^6.3.4: semver "^7.6.3" tiny-typed-emitter "^2.1.0" -electron@30.0.2: - version "30.0.2" - resolved "https://registry.yarnpkg.com/electron/-/electron-30.0.2.tgz#95ba019216bf8be9f3097580123e33ea37497733" - integrity sha512-zv7T+GG89J/hyWVkQsLH4Y/rVEfqJG5M/wOBIGNaDdqd8UV9/YZPdS7CuFeaIj0H9LhCt95xkIQNpYB/3svOkQ== +electron@38.6.0: + version "38.6.0" + resolved "https://registry.yarnpkg.com/electron/-/electron-38.6.0.tgz#c862bff41d42776e307bf5cc92503dda23612339" + integrity sha512-68OFNxJlrEStA+t8k5atzf4frJddvRR1N1oalr49Ll8YZ0+0nEsDhw4UNhTCoZKTjSYcxFF/4rt+sco+OlnB3g== dependencies: "@electron/get" "^2.0.0" - "@types/node" "^20.9.0" + "@types/node" "^22.7.7" extract-zip "^2.0.1" emoji-regex@^8.0.0: @@ -976,9 +1005,9 @@ encoding@^0.1.13: iconv-lite "^0.6.2" end-of-stream@^1.1.0: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + version "1.4.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== dependencies: once "^1.4.0" @@ -992,27 +1021,42 @@ err-code@^2.0.2: resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + es6-error@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== escalade@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^4.0.0: version "4.0.0" @@ -1020,9 +1064,9 @@ escape-string-regexp@^4.0.0: integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== exponential-backoff@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" - integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== + version "3.1.3" + resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz#51cf92c1c0493c766053f9d3abee4434c244d2f6" + integrity sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA== extract-zip@^2.0.1: version "2.0.1" @@ -1064,10 +1108,10 @@ filelist@^1.0.4: dependencies: minimatch "^5.0.1" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -1079,20 +1123,22 @@ find-yarn-workspace-root@^2.0.0: micromatch "^4.0.2" foreground-child@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" - integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== dependencies: - cross-spawn "^7.0.0" + cross-spawn "^7.0.6" signal-exit "^4.0.1" form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + version "4.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" + integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" mime-types "^2.1.12" fs-extra@^10.0.0, fs-extra@^10.1.0: @@ -1105,9 +1151,9 @@ fs-extra@^10.0.0, fs-extra@^10.1.0: universalify "^2.0.0" fs-extra@^11.1.1: - version "11.2.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.2.0.tgz#e70e17dfad64232287d01929399e0ea7c86b0e5b" - integrity sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw== + version "11.3.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.2.tgz#c838aeddc6f4a8c74dd15f85e11fe5511bfe02a4" + integrity sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" @@ -1168,16 +1214,29 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" es-errors "^1.3.0" + es-object-atoms "^1.1.1" function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" get-stream@^5.1.0: version "5.2.0" @@ -1241,12 +1300,10 @@ globalthis@^1.0.1: define-properties "^1.2.1" gopd "^1.0.1" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== got@^11.7.0, got@^11.8.5: version "11.8.6" @@ -1282,22 +1339,24 @@ has-property-descriptors@^1.0.0: dependencies: es-define-property "^1.0.0" -has-proto@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== -hasown@^2.0.0: +hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -1312,9 +1371,9 @@ hosted-git-info@^4.1.0: lru-cache "^6.0.0" http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" - integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + version "4.2.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz#205f4db64f8562b76a4ff9235aa5279839a09dd5" + integrity sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ== http-proxy-agent@^5.0.0: version "5.0.0" @@ -1412,13 +1471,10 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ip-address@^9.0.5: - version "9.0.5" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" - integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== - dependencies: - jsbn "1.1.0" - sprintf-js "^1.1.3" +ip-address@^10.0.1: + version "10.1.0" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.1.0.tgz#d8dcffb34d0e02eb241427444a6e23f5b0595aa4" + integrity sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q== is-ci@^2.0.0: version "2.0.0" @@ -1487,9 +1543,9 @@ isbinaryfile@^4.0.8: integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== isbinaryfile@^5.0.0: - version "5.0.4" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.4.tgz#2a2edefa76cafa66613fe4c1ea52f7f031017bdf" - integrity sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ== + version "5.0.6" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.6.tgz#01eac28867aeffaebaee7eaf21d1dd3a67d7c0c7" + integrity sha512-I+NmIfBHUl+r2wcDd6JwE9yWje/PIVY/R5/CmV8dXLZd5K+L9X2klAOwfAHNnondLXkbHyTAleQAWonpTJBTtw== isexe@^2.0.0: version "2.0.0" @@ -1506,14 +1562,13 @@ jackspeak@^3.1.2: "@pkgjs/parseargs" "^0.11.0" jake@^10.8.5: - version "10.9.1" - resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.1.tgz#8dc96b7fcc41cb19aa502af506da4e1d56f5e62b" - integrity sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w== + version "10.9.4" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.4.tgz#d626da108c63d5cfb00ab5c25fadc7e0084af8e6" + integrity sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA== dependencies: - async "^3.2.3" - chalk "^4.0.2" + async "^3.2.6" filelist "^1.0.4" - minimatch "^3.1.2" + picocolors "^1.1.1" js-yaml@^4.1.0: version "4.1.0" @@ -1522,11 +1577,6 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbn@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" - integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== - json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -1555,9 +1605,9 @@ jsonfile@^4.0.0: graceful-fs "^4.1.6" jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + version "6.2.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62" + integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg== dependencies: universalify "^2.0.0" optionalDependencies: @@ -1580,11 +1630,11 @@ jsonwebtoken@^9.0.2: semver "^7.5.4" jwa@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" - integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + version "1.4.2" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.2.tgz#16011ac6db48de7b102777e57897901520eec7b9" + integrity sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw== dependencies: - buffer-equal-constant-time "1.0.1" + buffer-equal-constant-time "^1.0.1" ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" @@ -1729,12 +1779,17 @@ matcher@^3.0.0: dependencies: escape-string-regexp "^4.0.0" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + micromatch@^4.0.2: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: @@ -1770,13 +1825,13 @@ mimic-response@^3.1.0: integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== minimatch@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" - integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + version "10.1.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.1.1.tgz#e6e61b9b0c1dcab116b5a7d1458e8b6ae9e73a55" + integrity sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ== dependencies: - brace-expansion "^2.0.1" + "@isaacs/brace-expansion" "^5.0.0" -minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -1871,11 +1926,6 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -1892,9 +1942,9 @@ nice-try@^1.0.4: integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== node-abi@^3.45.0: - version "3.71.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.71.0.tgz#52d84bbcd8575efb71468fbaa1f9a49b2c242038" - integrity sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw== + version "3.80.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.80.0.tgz#d7390951f27caa129cceeec01e1c20fc9f07581c" + integrity sha512-LyPuZJcI9HVwzXK1GPxWNzrr+vr8Hp/3UqlmWxxh8p54U1ZbclOqbSog9lWHaCX+dBaiGi6n/hIX+mKu74GmPA== dependencies: semver "^7.3.5" @@ -1904,9 +1954,9 @@ node-addon-api@^1.6.3: integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg== node-api-version@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/node-api-version/-/node-api-version-0.2.0.tgz#5177441da2b1046a4d4547ab9e0972eed7b1ac1d" - integrity sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg== + version "0.2.1" + resolved "https://registry.yarnpkg.com/node-api-version/-/node-api-version-0.2.1.tgz#19bad54f6d65628cbee4e607a325e4488ace2de9" + integrity sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q== dependencies: semver "^7.3.5" @@ -2081,6 +2131,11 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -2119,9 +2174,9 @@ promise-retry@^2.0.1: retry "^0.12.0" pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + version "3.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.3.tgz#151d979f1a29668dc0025ec589a455b53282268d" + integrity sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA== dependencies: end-of-stream "^1.1.0" once "^1.3.1" @@ -2261,9 +2316,9 @@ sanitize-filename@^1.6.3: truncate-utf8-bytes "^1.0.0" sax@^1.2.4: - version "1.3.0" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" - integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== + version "1.4.3" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.3.tgz#fcebae3b756cdc8428321805f4b70f16ec0ab5db" + integrity sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ== semver-compare@^1.0.0: version "1.0.0" @@ -2280,15 +2335,10 @@ semver@^6.2.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2: - version "7.6.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.1.tgz#60bfe090bf907a25aa8119a72b9f90ef7ca281b2" - integrity sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA== - -semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: - version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^7.3.2, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== serialize-error@^7.0.1: version "7.0.1" @@ -2372,11 +2422,11 @@ socks-proxy-agent@^7.0.0: socks "^2.6.2" socks@^2.6.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" - integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== + version "2.8.7" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.7.tgz#e2fb1d9a603add75050a2067db8c381a0b5669ea" + integrity sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A== dependencies: - ip-address "^9.0.5" + ip-address "^10.0.1" smart-buffer "^4.2.0" source-map-support@^0.5.19: @@ -2392,7 +2442,7 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sprintf-js@^1.1.2, sprintf-js@^1.1.3: +sprintf-js@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== @@ -2454,9 +2504,9 @@ string_decoder@~1.1.1: ansi-regex "^5.0.1" strip-ansi@^7.0.1: - version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" - integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + version "7.1.2" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba" + integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA== dependencies: ansi-regex "^6.0.1" @@ -2522,9 +2572,9 @@ tmp@^0.0.33: os-tmpdir "~1.0.2" tmp@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" - integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + version "0.2.5" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.5.tgz#b06bcd23f0f3c8357b426891726d16015abfd8f8" + integrity sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow== to-regex-range@^5.0.1: version "5.0.1" @@ -2546,14 +2596,19 @@ type-fest@^0.13.1: integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== typescript@^5.4.3: - version "5.7.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6" - integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg== + version "5.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +undici-types@~7.16.0: + version "7.16.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" + integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== unique-filename@^2.0.0: version "2.0.1" @@ -2592,9 +2647,9 @@ uri-js@^4.2.2: punycode "^2.1.0" utf8-byte-length@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61" - integrity sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA== + version "1.0.5" + resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e" + integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA== util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" diff --git a/common/fixYmlHashes.js b/common/fixYmlHashes.js new file mode 100644 index 000000000..bf317ef23 --- /dev/null +++ b/common/fixYmlHashes.js @@ -0,0 +1,110 @@ +import fs from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import YAML from 'yaml'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +async function sha512Base64(filePath) { + const buf = await fs.readFile(filePath); + const h = createHash('sha512'); + h.update(buf); + return h.digest('base64'); +} + +async function fileSize(filePath) { + const st = await fs.stat(filePath); + return st.size; +} + +async function fixOneYaml(ymlPath, distDir) { + let raw; + try { + raw = await fs.readFile(ymlPath, 'utf8'); + } catch (e) { + console.error(`✗ Cannot read ${ymlPath}:`, e.message); + return; + } + + let doc; + try { + doc = YAML.parse(raw); + } catch (e) { + console.error(`✗ Cannot parse YAML ${ymlPath}:`, e.message); + return; + } + + if (!doc || !Array.isArray(doc.files)) { + console.warn(`! ${path.basename(ymlPath)} has no 'files' array — skipped.`); + return; + } + + let changed = false; + + // Update each files[i].sha512 and files[i].size based on files[i].url + for (const entry of doc.files) { + if (!entry?.url) continue; + + const target = path.resolve(distDir, entry.url); + try { + const [hash, size] = await Promise.all([sha512Base64(target), fileSize(target)]); + if (entry.sha512 !== hash || entry.size !== size) { + console.log(`• ${path.basename(ymlPath)}: refresh ${entry.url}`); + entry.sha512 = hash; + entry.size = size; + changed = true; + } + } catch (e) { + console.warn( + `! Missing or unreadable file for ${entry.url} (referenced by ${path.basename(ymlPath)}): ${e.message}` + ); + } + } + + // Update top-level sha512 for the primary "path" file if present + if (doc.path) { + const primary = path.resolve(distDir, doc.path); + try { + const hash = await sha512Base64(primary); + if (doc.sha512 !== hash) { + console.log(`• ${path.basename(ymlPath)}: refresh top-level sha512 for path=${doc.path}`); + doc.sha512 = hash; + changed = true; + } + } catch (e) { + console.warn(`! Primary 'path' file not found for ${path.basename(ymlPath)}: ${doc.path} (${e.message})`); + } + } + + if (changed) { + const out = YAML.stringify(doc); + await fs.writeFile(ymlPath, out, 'utf8'); + console.log(`✓ Updated ${path.basename(ymlPath)}`); + } else { + console.log(`= No changes for ${path.basename(ymlPath)}`); + } +} + +async function main() { + const distDir = path.resolve(process.argv[2] ?? path.join(__dirname, '..', 'app', 'dist')); + const entries = await fs.readdir(distDir); + const ymls = entries.filter(f => f.toLowerCase().endsWith('.yml')); + + if (ymls.length === 0) { + console.warn(`No .yml files found in ${distDir}`); + return; + } + + console.log(`Scanning ${distDir}`); + for (const y of ymls) { + await fixOneYaml(path.join(distDir, y), distDir); + } +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/common/translations-cli/extract.js b/common/translations-cli/extract.js index 9c6374594..618e1dddb 100644 --- a/common/translations-cli/extract.js +++ b/common/translations-cli/extract.js @@ -6,7 +6,7 @@ const { getFiles } = require('./helpers'); const readFilePromise = promisify(fs.readFile); -const translationRegex = /_t\(\s*['"]([^'"]+)['"]\s*,\s*\{\s*defaultMessage\s*:\s*['"]([^'"]+)['"]\s*\}/g; +const translationRegex = /_t\(\s*['"]([^'"]+)['"]\s*,\s*\{\s*defaultMessage\s*:\s*(?:'([^'\\]*(?:\\.[^'\\]*)*)'|"([^"\\]*(?:\\.[^"\\]*)*)"|\`([^`\\]*(?:\\.[^`\\]*)*(?:\{[^}]*\}[^`\\]*(?:\\.[^`\\]*)*)*)\`)(?:\s*,\s*[^}]*)*\s*\}/g; /** * @param {string} file @@ -20,7 +20,8 @@ async function extractTranslationsFromFile(file) { let match; while ((match = translationRegex.exec(content)) !== null) { - const [_, key, defaultText] = match; + const [_, key, singleQuotedText, doubleQuotedText, templateLiteral] = match; + const defaultText = singleQuotedText || doubleQuotedText || templateLiteral; translations[key] = defaultText; } diff --git a/e2e-tests/cypress/e2e/charts.cy.js b/e2e-tests/cypress/e2e/charts.cy.js index b1196aa2a..0bd54c4b0 100644 --- a/e2e-tests/cypress/e2e/charts.cy.js +++ b/e2e-tests/cypress/e2e/charts.cy.js @@ -110,7 +110,7 @@ describe('Charts', () => { cy.themeshot('new-object-window'); }); - it('Database chat - charts', () => { + it.only('Database chat - charts', () => { cy.contains('MySql-connection').click(); cy.contains('MyChinook').click(); cy.testid('TabsPanel_buttonNewObject').click(); @@ -119,8 +119,7 @@ describe('Charts', () => { cy.get('body').realType('show me chart of most popular genres'); cy.get('body').realPress('{enter}'); cy.testid('DatabaseChatTab_executeAllQueries', { timeout: 30000 }).click(); - cy.wait(5000); - cy.testid('chart-canvas').should($c => expect($c[0].toDataURL()).to.match(/^data:image\/png;base64/)); + cy.testid('chart-canvas', { timeout: 30000 }).should($c => expect($c[0].toDataURL()).to.match(/^data:image\/png;base64/)); cy.themeshot('database-chat-chart'); }); diff --git a/package.json b/package.json index df09f2e42..0b5eb153e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.6.6-beta.13", + "version": "6.6.12-premium-beta.5", "name": "dbgate-all", "workspaces": [ "packages/*", @@ -52,6 +52,7 @@ "generatePadFile": "node generatePadFile", "fillPackagedPlugins": "node fillPackagedPlugins", "resetPackagedPlugins": "node resetPackagedPlugins", + "fixYmlHashes": "cd common && yarn init -y && yarn add yaml -W && cd .. && node common/fixYmlHashes.js app/dist", "prettier": "prettier --write packages/api/src && prettier --write packages/datalib/src && prettier --write packages/filterparser/src && prettier --write packages/sqltree/src && prettier --write packages/tools/src && prettier --write packages/types && prettier --write packages/web/src && prettier --write app/src", "copy:docker:build": "copyfiles packages/api/dist/* docker -f && copyfiles packages/web/public/* docker -u 2 && copyfiles \"packages/web/public/**/*\" docker -u 2 && copyfiles \"plugins/dist/**/*\" docker/plugins -u 2", "copy:packer:build": "copyfiles packages/api/dist/* packer/build -f && copyfiles packages/web/public/* packer/build -u 2 && copyfiles \"packages/web/public/**/*\" packer/build -u 2 && copyfiles \"plugins/dist/**/*\" packer/build/plugins -u 2 && copyfiles packer/install-packages.sh packer/build -f && yarn install:drivers:packer", diff --git a/packages/api/.env b/packages/api/.env index 2cfdd13f7..2e7ce8a5b 100644 --- a/packages/api/.env +++ b/packages/api/.env @@ -2,7 +2,7 @@ DEVMODE=1 SHELL_SCRIPTING=1 ALLOW_DBGATE_PRIVATE_CLOUD=1 DEVWEB=1 -LOCAL_AUTH_PROXY=1 +# LOCAL_AUTH_PROXY=1 # LOCAL_AI_GATEWAY=true # REDIRECT_TO_DBGATE_CLOUD_LOGIN=1 diff --git a/packages/api/src/controllers/cloud.js b/packages/api/src/controllers/cloud.js index 407eafcad..ad348b1f7 100644 --- a/packages/api/src/controllers/cloud.js +++ b/packages/api/src/controllers/cloud.js @@ -9,6 +9,8 @@ const { putCloudContent, removeCloudCachedConnection, getPromoWidgetData, + getPromoWidgetList, + getPromoWidgetPreview, } = require('../utility/cloudIntf'); const connections = require('./connections'); const socket = require('../utility/socket'); @@ -296,6 +298,16 @@ module.exports = { return data; }, + promoWidgetList_meta: true, + async promoWidgetList() { + return getPromoWidgetList(); + }, + + promoWidgetPreview_meta: true, + async promoWidgetPreview({ campaign, variant }) { + return getPromoWidgetPreview(campaign, variant); + }, + // chatStream_meta: { // raw: true, // method: 'post', diff --git a/packages/api/src/controllers/databaseConnections.js b/packages/api/src/controllers/databaseConnections.js index 383531e02..161ab1e32 100644 --- a/packages/api/src/controllers/databaseConnections.js +++ b/packages/api/src/controllers/databaseConnections.js @@ -29,7 +29,17 @@ const generateDeploySql = require('../shell/generateDeploySql'); const { createTwoFilesPatch } = require('diff'); const diff2htmlPage = require('../utility/diff2htmlPage'); const processArgs = require('../utility/processArgs'); -const { testConnectionPermission, hasPermission, loadPermissionsFromRequest, loadTablePermissionsFromRequest, getTablePermissionRole, loadDatabasePermissionsFromRequest, getDatabasePermissionRole, getTablePermissionRoleLevelIndex, testDatabaseRolePermission } = require('../utility/hasPermission'); +const { + testConnectionPermission, + hasPermission, + loadPermissionsFromRequest, + loadTablePermissionsFromRequest, + getTablePermissionRole, + loadDatabasePermissionsFromRequest, + getDatabasePermissionRole, + getTablePermissionRoleLevelIndex, + testDatabaseRolePermission, +} = require('../utility/hasPermission'); const { MissingCredentialsError } = require('../utility/exceptions'); const pipeForkLogs = require('../utility/pipeForkLogs'); const crypto = require('crypto'); @@ -100,7 +110,7 @@ module.exports = { socket.emitChanged(`database-status-changed`, { conid, database }); }, - handle_ping() { }, + handle_ping() {}, // session event handlers @@ -256,23 +266,24 @@ module.exports = { auditLogger: auditLogSessionGroup && select?.from?.name?.pureName ? response => { - sendToAuditLog(req, { - category: 'dbop', - component: 'DatabaseConnectionsController', - event: 'sql.select', - action: 'select', - severity: 'info', - conid, - database, - schemaName: select?.from?.name?.schemaName, - pureName: select?.from?.name?.pureName, - sumint1: response?.rows?.length, - sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${select?.from?.name?.pureName + sendToAuditLog(req, { + category: 'dbop', + component: 'DatabaseConnectionsController', + event: 'sql.select', + action: 'select', + severity: 'info', + conid, + database, + schemaName: select?.from?.name?.schemaName, + pureName: select?.from?.name?.pureName, + sumint1: response?.rows?.length, + sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${ + select?.from?.name?.pureName }`, - sessionGroup: auditLogSessionGroup, - message: `Loaded table data from ${select?.from?.name?.pureName}`, - }); - } + sessionGroup: auditLogSessionGroup, + message: `Loaded table data from ${select?.from?.name?.pureName}`, + }); + } : null, } ); @@ -335,21 +346,21 @@ module.exports = { auditLogger: auditLogSessionGroup && options?.pureName ? response => { - sendToAuditLog(req, { - category: 'dbop', - component: 'DatabaseConnectionsController', - event: 'nosql.collectionData', - action: 'select', - severity: 'info', - conid, - database, - pureName: options?.pureName, - sumint1: response?.result?.rows?.length, - sessionParam: `${conid}::${database}::${options?.pureName}`, - sessionGroup: auditLogSessionGroup, - message: `Loaded collection data ${options?.pureName}`, - }); - } + sendToAuditLog(req, { + category: 'dbop', + component: 'DatabaseConnectionsController', + event: 'nosql.collectionData', + action: 'select', + severity: 'info', + conid, + database, + pureName: options?.pureName, + sumint1: response?.result?.rows?.length, + sessionParam: `${conid}::${database}::${options?.pureName}`, + sessionGroup: auditLogSessionGroup, + message: `Loaded collection data ${options?.pureName}`, + }); + } : null, } ); @@ -455,10 +466,18 @@ module.exports = { [changeSet.inserts, 'create_update_delete'], [changeSet.deletes, 'create_update_delete'], [changeSet.updates, 'update_only'], - ] + ]; for (const [operations, requiredRole] of fieldsAndRoles) { for (const operation of operations) { - const role = getTablePermissionRole(conid, database, 'tables', operation.schemaName, operation.pureName, tablePermissions, databasePermissions); + const role = getTablePermissionRole( + conid, + database, + 'tables', + operation.schemaName, + operation.pureName, + tablePermissions, + databasePermissions + ); if (getTablePermissionRoleLevelIndex(role) < getTablePermissionRoleLevelIndex(requiredRole)) { throw new Error('DBGM-00262 Permission not granted'); } @@ -628,7 +647,15 @@ module.exports = { function applyTablePermissionRole(list, objectTypeField) { const res = []; for (const item of list ?? []) { - const tablePermissionRole = getTablePermissionRole(conid, database, objectTypeField, item.schemaName, item.pureName, tablePermissions, databasePermissionRole); + const tablePermissionRole = getTablePermissionRole( + conid, + database, + objectTypeField, + item.schemaName, + item.pureName, + tablePermissions, + databasePermissionRole + ); if (tablePermissionRole != 'deny') { res.push({ ...item, @@ -647,7 +674,7 @@ module.exports = { functions: applyTablePermissionRole(opened.structure.functions, 'functions'), triggers: applyTablePermissionRole(opened.structure.triggers, 'triggers'), collections: applyTablePermissionRole(opened.structure.collections, 'collections'), - } + }; return res; } @@ -881,17 +908,17 @@ module.exports = { return { ...(command == 'backup' ? driver.backupDatabaseCommand( - connection, - { outputFile, database, options, selectedTables, skippedTables, argsFormat }, - // @ts-ignore - externalTools - ) + connection, + { outputFile, database, options, selectedTables, skippedTables, argsFormat }, + // @ts-ignore + externalTools + ) : driver.restoreDatabaseCommand( - connection, - { inputFile, database, options, argsFormat }, - // @ts-ignore - externalTools - )), + connection, + { inputFile, database, options, argsFormat }, + // @ts-ignore + externalTools + )), transformMessage: driver.transformNativeCommandMessage ? message => driver.transformNativeCommandMessage(message, command) : null, @@ -990,7 +1017,10 @@ module.exports = { async executeSessionQuery({ sesid, conid, database, sql }, req) { await testConnectionPermission(conid, req); logger.info({ sesid, sql }, 'DBGM-00010 Processing query'); - sessions.dispatchMessage(sesid, 'Query execution started'); + sessions.dispatchMessage(sesid, { + message: 'Query execution started', + sql, + }); const opened = await this.ensureOpened(conid, database); opened.subprocess.send({ msgtype: 'executeSessionQuery', sql, sesid }); diff --git a/packages/api/src/controllers/sessions.js b/packages/api/src/controllers/sessions.js index 14c8a7bed..20eba95c8 100644 --- a/packages/api/src/controllers/sessions.js +++ b/packages/api/src/controllers/sessions.js @@ -83,6 +83,16 @@ module.exports = { socket.emit(`session-recordset-${sesid}`, { jslid, resultIndex }); }, + handle_endrecordset(sesid, props) { + const { jslid, rowCount, durationMs } = props; + this.dispatchMessage(sesid, { + message: `Query returned ${rowCount} rows in ${durationMs} ms`, + rowCount, + durationMs, + jslid, + }); + }, + handle_stats(sesid, stats) { jsldata.notifyChangedStats(stats); }, @@ -97,6 +107,12 @@ module.exports = { socket.emit(`session-initialize-file-${jslid}`); }, + handle_changedCurrentDatabase(sesid, props) { + const { database } = props; + this.dispatchMessage(sesid, `Current database changed to ${database}`); + socket.emit(`session-changedb-${sesid}`, { database }); + }, + handle_ping() {}, create_meta: true, @@ -182,7 +198,10 @@ module.exports = { }); logger.info({ sesid, sql }, 'DBGM-00019 Processing query'); - this.dispatchMessage(sesid, 'Query execution started'); + this.dispatchMessage(sesid, { + message: 'Query execution started', + sql, + }); session.subprocess.send({ msgtype: 'executeQuery', sql, diff --git a/packages/api/src/utility/cloudIntf.js b/packages/api/src/utility/cloudIntf.js index b27880689..2f66efa30 100644 --- a/packages/api/src/utility/cloudIntf.js +++ b/packages/api/src/utility/cloudIntf.js @@ -283,6 +283,7 @@ async function updatePremiumPromoWidget() { `${DBGATE_CLOUD_URL}/premium-promo-widget?identifier=${promoWidgetData?.identifier ?? 'empty'}&tags=${tags}`, { headers: { + ...getLicenseHttpHeaders(), ...(await getCloudInstanceHeaders()), 'x-app-version': currentVersion.version, }, @@ -308,7 +309,8 @@ async function refreshPublicFiles(isRefresh) { } catch (err) { logger.error(extractErrorLogData(err), 'DBGM-00166 Error updating cloud files'); } - if (!isProApp()) { + const configSettings = await config.get(); + if (!isProApp() || configSettings?.trialDaysLeft != null) { await updatePremiumPromoWidget(); } } @@ -480,6 +482,16 @@ async function getPromoWidgetData() { return promoWidgetData; } +async function getPromoWidgetPreview(campaign, variant) { + const resp = await axios.default.get(`${DBGATE_CLOUD_URL}/premium-promo-widget-preview/${campaign}/${variant}`); + return resp.data; +} + +async function getPromoWidgetList() { + const resp = await axios.default.get(`${DBGATE_CLOUD_URL}/promo-widget-list`); + return resp.data; +} + module.exports = { createDbGateIdentitySession, startCloudTokenChecking, @@ -498,4 +510,6 @@ module.exports = { readCloudTestTokenHolder, getPublicIpInfo, getPromoWidgetData, + getPromoWidgetPreview, + getPromoWidgetList, }; diff --git a/packages/api/src/utility/handleQueryStream.js b/packages/api/src/utility/handleQueryStream.js index 7f9e0cd2c..eb1d3a0fa 100644 --- a/packages/api/src/utility/handleQueryStream.js +++ b/packages/api/src/utility/handleQueryStream.js @@ -14,6 +14,7 @@ class QueryStreamTableWriter { this.currentChangeIndex = 1; this.initializedFile = false; this.sesid = sesid; + this.started = new Date().getTime(); } initializeFromQuery(structure, resultIndex, chartDefinition, autoDetectCharts = false, options = {}) { @@ -119,6 +120,13 @@ class QueryStreamTableWriter { this.chartProcessor = null; } } + process.send({ + msgtype: 'endrecordset', + jslid: this.jslid, + rowCount: this.currentRowCount, + sesid: this.sesid, + durationMs: new Date().getTime() - this.started, + }); resolve(); }); } else { @@ -149,6 +157,7 @@ class StreamHandler { // this.error = this.error.bind(this); this.done = this.done.bind(this); this.info = this.info.bind(this); + this.changedCurrentDatabase = this.changedCurrentDatabase.bind(this); // use this for cancelling - not implemented // this.stream = null; @@ -167,6 +176,10 @@ class StreamHandler { } } + changedCurrentDatabase(database) { + process.send({ msgtype: 'changedCurrentDatabase', database, sesid: this.sesid }); + } + recordset(columns, options) { if (this.rowsLimitOverflow) { return; diff --git a/packages/datalib/package.json b/packages/datalib/package.json index b82b4585a..12b52917e 100644 --- a/packages/datalib/package.json +++ b/packages/datalib/package.json @@ -3,6 +3,10 @@ "name": "dbgate-datalib", "main": "lib/index.js", "typings": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/dbgate/dbgate.git" + }, "scripts": { "build": "tsc", "test": "jest", diff --git a/packages/datalib/src/TableGridDisplay.ts b/packages/datalib/src/TableGridDisplay.ts index 9d25f44b8..1453104a3 100644 --- a/packages/datalib/src/TableGridDisplay.ts +++ b/packages/datalib/src/TableGridDisplay.ts @@ -39,7 +39,8 @@ export class TableGridDisplay extends GridDisplay { public getDictionaryDescription: DictionaryDescriptionFunc = null, isReadOnly = false, public isRawMode = false, - public currentSettings = null + public currentSettings = null, + public areReferencesAllowed = true ) { super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion, currentSettings); @@ -102,11 +103,11 @@ export class TableGridDisplay extends GridDisplay { isChecked: this.isColumnChecked(col), hintColumnNames: this.getFkDictionaryDescription(col.isForeignKeyUnique ? col.foreignKey : null)?.columns?.map(columnName => - shortenIdentifier(`hint_${col.uniqueName}_${columnName}`, this.driver.dialect.maxIdentifierLength) + shortenIdentifier(`hint_${col.uniqueName}_${columnName}`, this.driver?.dialect?.maxIdentifierLength) ) || null, hintColumnDelimiter: this.getFkDictionaryDescription(col.isForeignKeyUnique ? col.foreignKey : null) ?.delimiter, - uniqueNameShorten: shortenIdentifier(col.uniqueName, this.driver.dialect.maxIdentifierLength), + uniqueNameShorten: shortenIdentifier(col.uniqueName, this.driver?.dialect?.maxIdentifierLength), isExpandable: !!col.foreignKey, })) || [] ); @@ -117,7 +118,7 @@ export class TableGridDisplay extends GridDisplay { if (this.isExpandedColumn(column.uniqueName)) { const table = this.getFkTarget(column); if (table) { - const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength); + const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver?.dialect?.maxIdentifierLength); const subcolumns = this.getDisplayColumns(table, column.uniquePath); this.addReferenceToSelect(select, parentAlias, column); @@ -130,7 +131,7 @@ export class TableGridDisplay extends GridDisplay { } addReferenceToSelect(select: Select, parentAlias: string, column: DisplayColumn) { - const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength); + const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver?.dialect?.maxIdentifierLength); if ((select.from.relations || []).find(x => x.alias == childAlias)) return; const table = this.getFkTarget(column); if (table && table.primaryKey) { @@ -195,11 +196,11 @@ export class TableGridDisplay extends GridDisplay { this.addReferenceToSelect( select, parentUniqueName - ? shortenIdentifier(`${parentUniqueName}_ref`, this.driver.dialect.maxIdentifierLength) + ? shortenIdentifier(`${parentUniqueName}_ref`, this.driver?.dialect?.maxIdentifierLength) : 'basetbl', column ); - const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver.dialect.maxIdentifierLength); + const childAlias = shortenIdentifier(`${column.uniqueName}_ref`, this.driver?.dialect?.maxIdentifierLength); select.columns.push( ...hintDescription.columns.map( columnName => @@ -208,7 +209,7 @@ export class TableGridDisplay extends GridDisplay { columnName, alias: shortenIdentifier( `hint_${column.uniqueName}_${columnName}`, - this.driver.dialect.maxIdentifierLength + this.driver?.dialect?.maxIdentifierLength ), source: { alias: childAlias }, } as ColumnRefExpression) @@ -248,6 +249,7 @@ export class TableGridDisplay extends GridDisplay { } processReferences(select: Select, displayedColumnInfo: DisplayedColumnInfo, options) { + if (!this.areReferencesAllowed) return; this.addJoinsFromExpandedColumns(select, this.columns, 'basetbl', displayedColumnInfo); if (!options.isExport && this.displayOptions.showHintColumns) { this.addHintsToSelect(select); diff --git a/packages/filterparser/package.json b/packages/filterparser/package.json index 1f3d32570..94dd86ef2 100644 --- a/packages/filterparser/package.json +++ b/packages/filterparser/package.json @@ -3,6 +3,10 @@ "name": "dbgate-filterparser", "main": "lib/index.js", "typings": "lib/index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/dbgate/dbgate.git" + }, "scripts": { "build": "tsc", "start": "tsc --watch", diff --git a/packages/tools/src/nameTools.ts b/packages/tools/src/nameTools.ts index b63922ac9..e9bf3c26d 100644 --- a/packages/tools/src/nameTools.ts +++ b/packages/tools/src/nameTools.ts @@ -1,4 +1,5 @@ import _cloneDeep from 'lodash/cloneDeep'; +import _uniq from 'lodash/uniq'; import _isString from 'lodash/isString'; import type { ColumnInfo, @@ -75,9 +76,27 @@ export function findForeignKeyForColumn(table: TableInfo, column: ColumnInfo | s return (table.foreignKeys || []).find(fk => fk.columns.find(col => col.columnName == column.columnName)); } +export function getConflictingColumnNames(columns: ColumnInfo[]): Set { + const conflictingNames = new Set( + _uniq(columns.map(x => x.columnName).filter((item, index, arr) => arr.indexOf(item) !== index)) + ); + return conflictingNames; +} + export function makeUniqueColumnNames(res: ColumnInfo[]) { const usedNames = new Set(); + const conflictingNames = getConflictingColumnNames(res); for (let i = 0; i < res.length; i++) { + if ( + conflictingNames.has(res[i].columnName) && + res[i].pureName && + !usedNames.has(`${res[i].pureName}_${res[i].columnName}`) + ) { + res[i].columnName = `${res[i].pureName}_${res[i].columnName}`; + usedNames.add(res[i].columnName); + continue; + } + if (usedNames.has(res[i].columnName)) { let suffix = 2; while (usedNames.has(`${res[i].columnName}${suffix}`)) suffix++; diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index 0daf4c172..c583ff88a 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -21,6 +21,7 @@ export interface StreamOptions { error?: (error) => void; done?: (result) => void; info?: (info) => void; + changedCurrentDatabase?: (database: string) => void; } export type CollectionOperationInfo = diff --git a/packages/web/index.html.tpl b/packages/web/index.html.tpl index 040ba47de..d061ca7d2 100644 --- a/packages/web/index.html.tpl +++ b/packages/web/index.html.tpl @@ -26,12 +26,23 @@ + if (localStorage.getItem('currentThemeType') == 'dark') { + document.documentElement.style.setProperty('--theme-background', '#111'); + document.documentElement.style.setProperty('--theme-foreground', '#e3e3e3'); + } else { + document.documentElement.style.setProperty('--theme-background', '#fff'); + document.documentElement.style.setProperty('--theme-foreground', '#262626'); + } + diff --git a/packages/web/src/elements/TableControl.svelte b/packages/web/src/elements/TableControl.svelte index ab0544281..cedd0f20c 100644 --- a/packages/web/src/elements/TableControl.svelte +++ b/packages/web/src/elements/TableControl.svelte @@ -27,6 +27,7 @@ import { evaluateCondition } from 'dbgate-sqltree'; import { compileCompoudEvalCondition } from 'dbgate-filterparser'; import { chevronExpandIcon } from '../icons/expandIcons'; + import { _val } from '../translations'; export let columns: (TableControlColumn | false)[]; export let rows = null; @@ -368,7 +369,7 @@ {/if} {/key} {:else} - {row[col.fieldName] || ''} + { _val(row[col.fieldName]) || '' } {/if} {/each} diff --git a/packages/web/src/forms/FormPasswordFieldRaw.svelte b/packages/web/src/forms/FormPasswordFieldRaw.svelte index b2a8f0e39..6d8b96e4b 100644 --- a/packages/web/src/forms/FormPasswordFieldRaw.svelte +++ b/packages/web/src/forms/FormPasswordFieldRaw.svelte @@ -5,6 +5,7 @@ import { getFormContext } from './FormProviderCore.svelte'; import TextField from './TextField.svelte'; + import { _t } from '../translations'; export let name; export let disabled = false; @@ -29,7 +30,7 @@ setFieldValue(name, e.target['value']); } }} - placeholder={isCrypted ? '(Password is encrypted)' : undefined} + placeholder={isCrypted ? _t('common.passwordEncrypted', { defaultMessage: 'Password is encrypted' }) : undefined} type={isCrypted || showPassword ? 'text' : 'password'} /> {#if !isCrypted} diff --git a/packages/web/src/forms/FormTextFieldRaw.svelte b/packages/web/src/forms/FormTextFieldRaw.svelte index 6d9dee15b..5e7473112 100644 --- a/packages/web/src/forms/FormTextFieldRaw.svelte +++ b/packages/web/src/forms/FormTextFieldRaw.svelte @@ -1,6 +1,7 @@ {#each blocks as block, i} {#if block.type in componentMap} - + {/if} {/each} diff --git a/packages/web/src/jsonui/JsonUiCountdown.svelte b/packages/web/src/jsonui/JsonUiCountdown.svelte new file mode 100644 index 000000000..db11a62f1 --- /dev/null +++ b/packages/web/src/jsonui/JsonUiCountdown.svelte @@ -0,0 +1,87 @@ + + +{#if validTo} +
{ + if (link) { + openWebLink(link); + } + }} + > + Offer ends in:
+ {#each parts as part} + + {part.num} + {part.unit} + + {/each} +
+{/if} + + diff --git a/packages/web/src/jsonui/JsonUiHighlight.svelte b/packages/web/src/jsonui/JsonUiHighlight.svelte new file mode 100644 index 000000000..4b083ee89 --- /dev/null +++ b/packages/web/src/jsonui/JsonUiHighlight.svelte @@ -0,0 +1,35 @@ + + +
{ + if (link) { + openWebLink(link); + } + }} +> + {text} +
+ + diff --git a/packages/web/src/jsonui/JsonUiLinkButton.svelte b/packages/web/src/jsonui/JsonUiLinkButton.svelte index e3d2ce311..e9a00925c 100644 --- a/packages/web/src/jsonui/JsonUiLinkButton.svelte +++ b/packages/web/src/jsonui/JsonUiLinkButton.svelte @@ -5,9 +5,6 @@ export let text: string; export let link: string; export let colorClass: string = ''; - - // very light url guard - const safe = /^(https?:)?\/\//i.test(link) || link.startsWith('/');
diff --git a/packages/web/src/jsonui/JsonUiLinkButtonBlock.svelte b/packages/web/src/jsonui/JsonUiLinkButtonBlock.svelte new file mode 100644 index 000000000..9800e831e --- /dev/null +++ b/packages/web/src/jsonui/JsonUiLinkButtonBlock.svelte @@ -0,0 +1,21 @@ + + +
+ {#each items as item} + openWebLink(item.link)} value={item.text} skipWidth {colorClass} /> + {/each} +
+ + diff --git a/packages/web/src/jsonui/JsonUiMarkdown.svelte b/packages/web/src/jsonui/JsonUiMarkdown.svelte new file mode 100644 index 000000000..cfe522772 --- /dev/null +++ b/packages/web/src/jsonui/JsonUiMarkdown.svelte @@ -0,0 +1,15 @@ + + +
+ +
+ + diff --git a/packages/web/src/macro/MacroDetail.svelte b/packages/web/src/macro/MacroDetail.svelte index f58efa16b..4290510c6 100644 --- a/packages/web/src/macro/MacroDetail.svelte +++ b/packages/web/src/macro/MacroDetail.svelte @@ -6,6 +6,7 @@ import MacroHeader from './MacroHeader.svelte'; import MacroInfoTab from './MacroInfoTab.svelte'; + import { _t } from '../translations'; const selectedMacro = getContext('selectedMacro') as any; @@ -17,7 +18,7 @@
- Execute - ($selectedMacro = null)}>Close + {_t('common.execute', { defaultMessage: 'Execute' })} + ($selectedMacro = null)}>{_t('common.close', { defaultMessage: 'Close' })}
diff --git a/packages/web/src/macro/MacroInfoTab.svelte b/packages/web/src/macro/MacroInfoTab.svelte index 8ed71e4e7..79112d8ca 100644 --- a/packages/web/src/macro/MacroInfoTab.svelte +++ b/packages/web/src/macro/MacroInfoTab.svelte @@ -5,6 +5,7 @@ import WidgetTitle from '../widgets/WidgetTitle.svelte'; import MacroParameters from './MacroParameters.svelte'; + import { _t } from '../translations'; const selectedMacro = getContext('selectedMacro') as any; @@ -13,23 +14,23 @@
- Execute - + {_t('common.execute', { defaultMessage: 'Execute' })} +
- Parameters + {_t('common.parameters', { defaultMessage: 'Parameters' })} {#if $selectedMacro?.args && $selectedMacro?.args?.length > 0} {#key $selectedMacro?.name} {/key} {:else} -
This macro has no parameters
+
{_t('datagrid.macros.noParameters', { defaultMessage: 'This macro has no parameters' })}
{/if}
- Description + {_t('common.description', { defaultMessage: 'Description' })}
{$selectedMacro?.description}
diff --git a/packages/web/src/macro/MacroManager.svelte b/packages/web/src/macro/MacroManager.svelte index edfea466e..b97140424 100644 --- a/packages/web/src/macro/MacroManager.svelte +++ b/packages/web/src/macro/MacroManager.svelte @@ -8,6 +8,7 @@ import SearchBoxWrapper from '../elements/SearchBoxWrapper.svelte'; import SearchInput from '../elements/SearchInput.svelte'; import macros from './macros'; + import { _t } from '../translations'; let filter = ''; export let managerSize; @@ -16,7 +17,7 @@ - + (macroCondition ? macroCondition(x) : true))} diff --git a/packages/web/src/macro/macros.js b/packages/web/src/macro/macros.js index f131e3b6c..e08e0292a 100644 --- a/packages/web/src/macro/macros.js +++ b/packages/web/src/macro/macros.js @@ -1,37 +1,39 @@ +import { __t } from '../translations'; + const macros = [ { - title: 'Remove diacritics', + title: __t('datagrid.macros.removeDiacritics', { defaultMessage: 'Remove diacritics' }), name: 'removeDiacritics', - group: 'Text', - description: 'Removes diacritics from selected cells', + group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }), + description: __t('datagrid.macros.removeDiacriticsDescription', { defaultMessage: 'Removes diacritics from selected cells' }), type: 'transformValue', code: `return modules.lodash.deburr(value)`, }, { - title: 'Search & replace text', + title: __t('datagrid.macros.searchReplaceText', { defaultMessage: 'Search & replace text' }), name: 'stringReplace', - group: 'Text', - description: 'Search & replace text or regular expression', + group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }), + description: __t('datagrid.macros.searchReplaceTextDescription', { defaultMessage: 'Search & replace text or regular expression' }), type: 'transformValue', args: [ { type: 'text', - label: 'Find', + label: __t('datagrid.macros.searchReplaceTextFind', { defaultMessage: 'Find' }), name: 'find', }, { type: 'text', - label: 'Replace with', + label: __t('datagrid.macros.searchReplaceTextReplaceWith', { defaultMessage: 'Replace with' }), name: 'replace', }, { type: 'checkbox', - label: 'Case sensitive', + label: __t('datagrid.macros.searchReplaceTextCaseSensitive', { defaultMessage: 'Case sensitive' }), name: 'caseSensitive', }, { type: 'checkbox', - label: 'Regular expression', + label: __t('datagrid.macros.searchReplaceTextIsRegex', { defaultMessage: 'Regular expression' }), name: 'isRegex', }, ], @@ -42,16 +44,16 @@ return value ? value.toString().replace(new RegExp(rtext, rflags), args.replace `, }, { - title: 'Change text case', + title: __t('datagrid.macros.changeTextCase', { defaultMessage: 'Change text case' }), name: 'changeTextCase', - group: 'Text', - description: 'Uppercase, lowercase and other case functions', + group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }), + description: __t('datagrid.macros.changeTextCaseDescription', { defaultMessage: 'Uppercase, lowercase and other case functions' }), type: 'transformValue', args: [ { type: 'select', options: ['toUpper', 'toLower', 'lowerCase', 'upperCase', 'kebabCase', 'snakeCase', 'camelCase', 'startCase'], - label: 'Type', + label: __t('datagrid.macros.changeTextCaseType', { defaultMessage: 'Type' }), name: 'type', default: 'toUpper', }, @@ -59,81 +61,81 @@ return value ? value.toString().replace(new RegExp(rtext, rflags), args.replace code: `return modules.lodash[args.type](value)`, }, { - title: 'Pad left', + title: __t('datagrid.macros.padLeft', { defaultMessage: 'Pad left' }), name: 'padLeft', - group: 'Text', + group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }), args: [ { type: 'text', - label: 'Character', + label: __t('datagrid.macros.padCharacter', { defaultMessage: 'Character' }), name: 'character', default: '0', }, { type: 'text', - label: 'Length', + label: __t('datagrid.macros.padLength', { defaultMessage: 'Length' }), name: 'length', default: '3', }, ], description: - 'Returns string of a specified length in which the beginning of the current string is padded with spaces or other character', + __t('datagrid.macros.padLeftDescription', { defaultMessage: 'Returns string of a specified length in which the beginning of the current string is padded with spaces or other character' }), type: 'transformValue', code: `return modules.lodash.padStart(value, +args.length, args.character)`, }, { - title: 'Pad right', + title: __t('datagrid.macros.padRight', { defaultMessage: 'Pad right' }), name: 'padRight', - group: 'Text', + group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }), args: [ { type: 'text', - label: 'Character', + label: __t('datagrid.macros.padCharacter', { defaultMessage: 'Character' }), name: 'character', default: '0', }, { type: 'text', - label: 'Length', + label: __t('datagrid.macros.padLength', { defaultMessage: 'Length' }), name: 'length', default: '3', }, ], description: - 'Returns string of a specified length in which the end of the current string is padded with spaces or other character', + __t('datagrid.macros.padRightDescription', { defaultMessage: 'Returns string of a specified length in which the end of the current string is padded with spaces or other character' }), type: 'transformValue', code: `return modules.lodash.padEnd(value, +args.length, args.character)`, }, { - title: 'Trim', + title: __t('datagrid.macros.trim', { defaultMessage: 'Trim' }), name: 'trim', - group: 'Text', - description: 'Removes leading and trailing whitespace ', + group: __t('datagrid.macros.textGroup', { defaultMessage: 'Text' }), + description: __t('datagrid.macros.trimDescription', { defaultMessage: 'Removes leading and trailing whitespace' }), type: 'transformValue', code: `return modules.lodash.trim(value)`, }, { - title: 'Row index', + title: __t('datagrid.macros.rowIndex', { defaultMessage: 'Row index' }), name: 'rowIndex', - group: 'Tools', - description: 'Index of row from 1 (autoincrement)', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.rowIndexDescription', { defaultMessage: 'Index of row from 1 (autoincrement)' }), type: 'transformValue', code: `return rowIndex + 1`, }, { - title: 'Generate UUID', + title: __t('datagrid.macros.generateUUID', { defaultMessage: 'Generate UUID' }), name: 'uuidv1', - group: 'Tools', - description: 'Generate unique identifier', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.generateUUIDDescription', { defaultMessage: 'Generate unique identifier' }), type: 'transformValue', args: [ { type: 'select', options: [ { value: 'uuidv1', name: 'V1 - from timestamp' }, - { value: 'uuidv4', name: 'V4 - random generated' }, + { value: 'uuidv4', name: 'V4 - random generated'}, ], - label: 'Version', + label: __t('datagrid.macros.version', { defaultMessage: 'Version' }), name: 'version', default: 'uuidv1', }, @@ -141,26 +143,26 @@ return value ? value.toString().replace(new RegExp(rtext, rflags), args.replace code: `return modules[args.version]()`, }, { - title: 'Convert to integer', + title: __t('datagrid.macros.toInt', { defaultMessage: 'Convert to integer' }), name: 'toInt', - group: 'Tools', - description: 'Converts to integral number', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.toIntDescription', { defaultMessage: 'Converts to integral number' }), type: 'transformValue', code: `return modules.lodash.isNaN(parseInt(value)) ? null : parseInt(value)`, }, { - title: 'Convert to number', + title: __t('datagrid.macros.toNumber', { defaultMessage: 'Convert to number' }), name: 'toNumber', - group: 'Tools', - description: 'Converts to number', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.toNumberDescription', { defaultMessage: 'Converts to number' }), type: 'transformValue', code: `return modules.lodash.isNaN(parseFloat(value)) ? null : parseFloat(value)`, }, { - title: 'Convert to boolean', + title: __t('datagrid.macros.toBoolean', { defaultMessage: 'Convert to boolean' }), name: 'toBoolean', - group: 'Tools', - description: 'Converts to boolean', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.toBooleanDescription', { defaultMessage: 'Converts to boolean' }), type: 'transformValue', code: ` if (modules.lodash.isString(value)) { @@ -176,10 +178,10 @@ return !!value; `, }, { - title: 'Convert to string', + title: __t('datagrid.macros.toString', { defaultMessage: 'Convert to string' }), name: 'toString', - group: 'Tools', - description: 'Converts to string', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.toStringDescription', { defaultMessage: 'Converts to string' }), type: 'transformValue', code: ` if (value==null) return null; @@ -188,15 +190,15 @@ return !!value; `, }, { - title: 'Current date', + title: __t('datagrid.macros.currentDate', { defaultMessage: 'Current date' }), name: 'currentDate', - group: 'Tools', - description: 'Gets current date', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.currentDateDescription', { defaultMessage: 'Gets current date' }), type: 'transformValue', args: [ { type: 'text', - label: 'Format', + label: __t('datagrid.macros.format', { defaultMessage: 'Format' }), name: 'format', default: 'YYYY-MM-DD HH:mm:ss', }, @@ -204,10 +206,10 @@ return !!value; code: `return modules.moment().format(args.format)`, }, { - title: 'Duplicate columns', + title: __t('datagrid.macros.duplicateColumns', { defaultMessage: 'Duplicate columns' }), name: 'duplicateColumns', - group: 'Tools', - description: 'Duplicate selected columns', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.duplicateColumnsDescription', { defaultMessage: 'Duplicate selected columns' }), type: 'transformRow', code: ` return { @@ -218,22 +220,22 @@ return !!value; args: [ { type: 'text', - label: 'Prefix', + label: __t('datagrid.macros.prefix', { defaultMessage: 'Prefix' }), name: 'prefix', }, { type: 'text', - label: 'Postfix', + label: __t('datagrid.macros.postfix', { defaultMessage: 'Postfix' }), name: 'postfix', default: '_copy', }, ], }, { - title: 'Split columns', + title: __t('datagrid.macros.splitColumns', { defaultMessage: 'Split columns' }), name: 'splitColumns', - group: 'Tools', - description: 'Split selected columns', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.splitColumnsDescription', { defaultMessage: 'Split selected columns' }), type: 'transformRow', code: ` const res = {...row}; @@ -252,22 +254,22 @@ return !!value; args: [ { type: 'text', - label: 'Delimiter', + label: __t('datagrid.macros.delimiter', { defaultMessage: 'Delimiter' }), name: 'delimiter', default: ',', }, ], }, { - title: 'Calculation', + title: __t('datagrid.macros.calculation', { defaultMessage: 'Calculation' }), name: 'calculation', - group: 'Tools', - description: 'Custom expression. Use row.column_name for accessing column values, value for original value', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.calculationDescription', { defaultMessage: 'Custom expression. Use row.column_name for accessing column values, value for original value' }), type: 'transformValue', args: [ { type: 'text', - label: 'Expression', + label: __t('datagrid.macros.expression', { defaultMessage: 'Expression' }), name: 'expression', default: 'value', }, @@ -275,10 +277,10 @@ return !!value; code: `return eval(args.expression);`, }, { - title: 'Extract date fields', + title: __t('datagrid.macros.extractDateFields', { defaultMessage: 'Extract date fields' }), name: 'extractDateFields', - group: 'Tools', - description: 'Extract yaear, month, day and other date/time fields from selection and adds it as new columns', + group: __t('datagrid.macros.toolsGroup', { defaultMessage: 'Tools' }), + description: __t('datagrid.macros.extractDateFieldsDescription', { defaultMessage: 'Extract year, month, day and other date/time fields from selection and adds it as new columns' }), type: 'transformRow', code: ` let mom = null; @@ -311,37 +313,37 @@ return !!value; args: [ { type: 'text', - label: 'Year name', + label: __t('datagrid.macros.yearName', { defaultMessage: 'Year name' }), name: 'year', default: 'year', }, { type: 'text', - label: 'Month name', + label: __t('datagrid.macros.monthName', { defaultMessage: 'Month name' }) , name: 'month', default: 'month', }, { type: 'text', - label: 'Day name', + label: __t('datagrid.macros.dayName', { defaultMessage: 'Day name' }), name: 'day', default: 'day', }, { type: 'text', - label: 'Hour name', + label: __t('datagrid.macros.hourName', { defaultMessage: 'Hour name' }), name: 'hour', default: 'hour', }, { type: 'text', - label: 'Minute name', + label: __t('datagrid.macros.minuteName', { defaultMessage: 'Minute name' }), name: 'minute', default: 'minute', }, { type: 'text', - label: 'Second name', + label: __t('datagrid.macros.secondName', { defaultMessage: 'Second name' }), name: 'second', default: 'second', }, diff --git a/packages/web/src/modals/CloseTabModal.svelte b/packages/web/src/modals/CloseTabModal.svelte index d86451435..62d67f22c 100644 --- a/packages/web/src/modals/CloseTabModal.svelte +++ b/packages/web/src/modals/CloseTabModal.svelte @@ -9,6 +9,8 @@ import ModalBase from './ModalBase.svelte'; import { closeCurrentModal } from './modalTools'; import { commandsCustomized } from '../stores'; + import { _t } from '../translations'; + import _ from 'lodash'; export let tabs; export let onConfirm; @@ -27,10 +29,10 @@ - Confirm close tabs + {_t('datagrid.closeTabs.header', { defaultMessage: 'Confirm close tabs' })}
- Following files are modified, really close tabs? After closing, you could reopen them in history + {_t('datagrid.closeTabs.modifiedFiles', { defaultMessage: 'Following files are modified, really close tabs? After closing, you could reopen them in history' })} widget
@@ -41,7 +43,7 @@ { closeCurrentModal(); onConfirm(); @@ -49,7 +51,7 @@ /> { closeCurrentModal(); onCancel(); diff --git a/packages/web/src/modals/CommandModal.svelte b/packages/web/src/modals/CommandModal.svelte index 20a3f1280..f336013ad 100644 --- a/packages/web/src/modals/CommandModal.svelte +++ b/packages/web/src/modals/CommandModal.svelte @@ -11,6 +11,7 @@ import KeyboardModal from './KeyboardModal.svelte'; import ModalBase from './ModalBase.svelte'; import { closeCurrentModal, showModal } from './modalTools'; + import { _t } from '../translations'; export let command; @@ -23,16 +24,16 @@ - Configure commmand + {_t('commandModal.configure', { defaultMessage: 'Configure command' })} - - + +
- + @@ -56,7 +57,7 @@ /> { closeCurrentModal(); apiCall('config/update-settings', { @@ -64,7 +65,7 @@ }); }} /> - + diff --git a/packages/web/src/modals/EditCellDataModal.svelte b/packages/web/src/modals/EditCellDataModal.svelte index b2980b76e..2912f59aa 100644 --- a/packages/web/src/modals/EditCellDataModal.svelte +++ b/packages/web/src/modals/EditCellDataModal.svelte @@ -13,6 +13,7 @@ import { parseCellValue, safeJsonParse, stringifyCellValue } from 'dbgate-tools'; import { showSnackbarError } from '../utility/snackbar'; import ErrorMessageModal from './ErrorMessageModal.svelte'; + import { _t } from '../translations'; export let onSave; export let value; @@ -49,14 +50,14 @@ if (parsed) { textValue = JSON.stringify(parsed, null, 2); } else { - showModal(ErrorMessageModal, { message: 'Not valid JSON' }); + showModal(ErrorMessageModal, { message: _t('dataGrid.formatJson.invalid', { defaultMessage: 'Not valid JSON' }) }); } } -
Edit cell value
+
{_t('dataGrid.editCellValue', { defaultMessage: 'Edit cell value' })}
@@ -72,21 +73,21 @@ closeCurrentModal(); }} /> - +
- + - Code highlighting: + {_t('dataGrid.codeHighlighting', { defaultMessage: 'Code highlighting:' })} (syntaxMode = e.detail)} options={[ - { value: 'text', label: 'None (raw text)' }, + { value: 'text', label: _t('dataGrid.codeHighlighting.none', { defaultMessage: 'None (raw text)' }) }, { value: 'json', label: 'JSON' }, - { value: 'html', label: 'HTML' }, + { value: 'html', label: 'HTML'}, { value: 'xml', label: 'XML' }, ]} /> diff --git a/packages/web/src/modals/ErrorMessageModal.svelte b/packages/web/src/modals/ErrorMessageModal.svelte index 6cb052901..76be00b2b 100644 --- a/packages/web/src/modals/ErrorMessageModal.svelte +++ b/packages/web/src/modals/ErrorMessageModal.svelte @@ -6,8 +6,9 @@ import ModalBase from './ModalBase.svelte'; import { closeCurrentModal } from './modalTools'; + import { _t } from '../translations'; - export let title = 'Error'; + export let title = _t('common.error', { defaultMessage: 'Error' }); export let message; export let showAsCode = false; @@ -30,7 +31,7 @@ {/if}
- +
diff --git a/packages/web/src/modals/InputTextModal.svelte b/packages/web/src/modals/InputTextModal.svelte index 7ce64667e..22dbd1545 100644 --- a/packages/web/src/modals/InputTextModal.svelte +++ b/packages/web/src/modals/InputTextModal.svelte @@ -6,6 +6,7 @@ import FormTextField from '../forms/FormTextField.svelte'; import ModalBase from './ModalBase.svelte'; import { closeCurrentModal } from './modalTools'; + import { _t } from '../translations'; export let header; export let value; @@ -29,7 +30,7 @@ handleSubmit(e.detail)} data-testid="InputTextModal_ok" /> - + diff --git a/packages/web/src/modals/KeyboardModal.svelte b/packages/web/src/modals/KeyboardModal.svelte index 9d3d849e9..dbb2925e3 100644 --- a/packages/web/src/modals/KeyboardModal.svelte +++ b/packages/web/src/modals/KeyboardModal.svelte @@ -5,6 +5,7 @@ import keycodes from '../utility/keycodes'; import ModalBase from './ModalBase.svelte'; import { closeCurrentModal } from './modalTools'; + import { _t } from '../translations'; export let onChange; let value; @@ -38,7 +39,7 @@ -
Show desired key combination and press ENTER
+
_{_t('commandModal.showKeyCombination', { defaultMessage: 'Show desired key combination and press ENTER' })}
diff --git a/packages/web/src/modals/NewCollectionModal.svelte b/packages/web/src/modals/NewCollectionModal.svelte index 17c117d36..16f1c9028 100644 --- a/packages/web/src/modals/NewCollectionModal.svelte +++ b/packages/web/src/modals/NewCollectionModal.svelte @@ -10,6 +10,7 @@ import ErrorMessageModal from './ErrorMessageModal.svelte'; import ModalBase from './ModalBase.svelte'; import { closeCurrentModal, showModal } from './modalTools'; + import { _t } from '../translations'; export let driver; export let dbid; @@ -44,14 +45,14 @@ - Create {driver?.collectionSingularLabel ?? 'collection/container'} + {_t('dbObject.createCollection', { defaultMessage: 'Create collection/container'})} handleSubmit(e.detail)} disabled={isSaving} /> - + diff --git a/packages/web/src/modals/NewObjectModal.svelte b/packages/web/src/modals/NewObjectModal.svelte index 99d140694..786fef7c1 100644 --- a/packages/web/src/modals/NewObjectModal.svelte +++ b/packages/web/src/modals/NewObjectModal.svelte @@ -7,6 +7,7 @@ import { isProApp } from '../utility/proTools'; import ModalBase from './ModalBase.svelte'; import { closeCurrentModal } from './modalTools'; + import { _t } from '../translations'; export let multiTabIndex = undefined; @@ -14,8 +15,8 @@ { icon: 'icon sql-file', colorClass: 'color-icon-blue', - title: 'Query', - description: 'SQL query editor', + title: _t('common.query', { defaultMessage: 'Query' }), + description: _t('common.queryEditor', { defaultMessage: 'SQL query editor' }), action: () => { newQuery({ multiTabIndex }); }, @@ -25,47 +26,47 @@ { icon: 'icon connection', colorClass: 'color-icon-yellow', - title: 'Connection', - description: 'Database connection stored locally', + title: _t('common.connection', { defaultMessage: 'Connection' }), + description: _t('newObject.connectionLocal', { defaultMessage: 'Database connection stored locally' }), command: 'new.connection', changeWidget: 'database', testid: 'NewObjectModal_connection', - disabledMessage: 'You are not allowed to create new connections', + disabledMessage: _t('newObject.connectionLocalDisabled', { defaultMessage: 'You are not allowed to create new connections' }), }, { icon: 'icon cloud-connection', colorClass: 'color-icon-blue', - title: 'Connection on Cloud', - description: 'Database connection stored on DbGate Cloud', + title: _t('common.connectionOnCloud', { defaultMessage: 'Connection on Cloud' }), + description: _t('newObject.connectionOnCloudDescription', { defaultMessage: 'Database connection stored on DbGate Cloud' }), command: 'new.connectionOnCloud', changeWidget: 'cloud-private', testid: 'NewObjectModal_connectionOnCloud', - disabledMessage: 'For creating connections on DbGate Cloud, you need to be logged in', + disabledMessage: _t('newObject.connectionOnCloudDisabled', { defaultMessage: 'For creating connections on DbGate Cloud, you need to be logged in' }), }, { icon: 'icon query-design', colorClass: 'color-icon-red', - title: 'Query Designer', - description: 'Design SQL queries visually', + title: _t('common.queryDesigner', { defaultMessage: 'Query Designer' }), + description: _t('newObject.queryDesignerDescription', { defaultMessage: 'Design SQL queries visually' }), command: 'new.queryDesign', testid: 'NewObjectModal_queryDesign', - disabledMessage: 'Query Designer is not available for current database', + disabledMessage: _t('newObject.queryDesignerDisabled', { defaultMessage: 'Query Designer is not available for current database' }), isProFeature: true, }, { icon: 'icon diagram', colorClass: 'color-icon-blue', - title: 'ER Diagram', - description: 'Visualize database structure', + title: _t('common.erDiagram', { defaultMessage: 'ER Diagram' }), + description: _t('newObject.erDiagramDescription', { defaultMessage: 'Visualize database structure' }), command: 'new.diagram', testid: 'NewObjectModal_diagram', - disabledMessage: 'ER Diagram is not available for current database', + disabledMessage: _t('newObject.erDiagramDisabled', { defaultMessage: 'ER Diagram is not available for current database' }), }, { icon: 'icon perspective', colorClass: 'color-icon-yellow', - title: 'Perspective', - description: 'Join complex data from multiple databases', + title: _t('common.perspective', { defaultMessage: 'Perspective' }), + description: _t('newObject.perspectiveDescription', { defaultMessage: 'Join complex data from multiple databases' }), command: 'new.perspective', testid: 'NewObjectModal_perspective', isProFeature: true, @@ -73,55 +74,56 @@ { icon: 'icon table', colorClass: 'color-icon-blue', - title: 'Table', - description: 'Create table in the current database', + title: _t('common.table', { defaultMessage: 'Table' }), + description: _t('newObject.tableDescription', { defaultMessage: 'Create table in the current database' }), command: 'new.table', testid: 'NewObjectModal_table', - disabledMessage: 'Table creation is not available for current database', + disabledMessage: _t('newObject.tableDisabled', { defaultMessage: 'Table creation is not available for current database' }), }, { icon: 'icon sql-generator', colorClass: 'color-icon-green', - title: 'SQL Generator', - description: 'Generate SQL scripts for database objects', + title: _t('common.sqlGenerator', { defaultMessage: 'SQL Generator' }), + description: _t('newObject.sqlGeneratorDescription', { defaultMessage: 'Generate SQL scripts for database objects' }), command: 'sql.generator', testid: 'NewObjectModal_sqlGenerator', - disabledMessage: 'SQL Generator is not available for current database', + disabledMessage: _t('newObject.sqlGeneratorDisabled', { defaultMessage: 'SQL Generator is not available for current database' }), }, { icon: 'icon export', colorClass: 'color-icon-green', - title: 'Export database', - description: 'Export to file like CSV, JSON, Excel, or other DB', + title: _t('common.exportDatabase', { defaultMessage: 'Export database' }), + description: _t('newObject.exportDescription', { defaultMessage: 'Export to file like CSV, JSON, Excel, or other DB' }), command: 'database.export', + isProFeature: true, testid: 'NewObjectModal_databaseExport', - disabledMessage: 'Export is not available for current database', + disabledMessage: _t('newObject.exportDisabled', { defaultMessage: 'Export is not available for current database' }), }, { icon: 'icon compare', colorClass: 'color-icon-red', - title: 'Compare database', - description: 'Compare database schemas', + title: _t('common.compare', { defaultMessage: 'Compare database' }), + description: _t('newObject.compareDescription', { defaultMessage: 'Compare database schemas' }), command: 'database.compare', testid: 'NewObjectModal_databaseCompare', - disabledMessage: 'Database comparison is not available for current database', + disabledMessage: _t('newObject.compareDisabled', { defaultMessage: 'Database comparison is not available for current database' }), isProFeature: true, }, { icon: 'icon ai', colorClass: 'color-icon-blue', - title: 'Database Chat', - description: 'Chat with your database using AI', + title: _t('common.databaseChat', { defaultMessage: 'Database Chat' }), + description: _t('newObject.databaseChatDescription', { defaultMessage: 'Chat with your database using AI' }), command: 'database.chat', isProFeature: true, - disabledMessage: 'Database chat is not available for current database', + disabledMessage: _t('newObject.databaseChatDisabled', { defaultMessage: 'Database chat is not available for current database' }), testid: 'NewObjectModal_databaseChat', }, ]; -
Create new
+
{_t('common.createNew', { defaultMessage: 'Create new' })}
{#each NEW_ITEMS as item} {@const enabled = item.command diff --git a/packages/web/src/modals/SetFilterModal.svelte b/packages/web/src/modals/SetFilterModal.svelte index 436d734ff..38e224852 100644 --- a/packages/web/src/modals/SetFilterModal.svelte +++ b/packages/web/src/modals/SetFilterModal.svelte @@ -10,6 +10,7 @@ import { closeCurrentModal } from './modalTools'; import FormRadioGroupItem from '../forms/FormRadioGroupItem.svelte'; import FormValues from '../forms/FormValues.svelte'; + import { _t } from '../translations'; export let condition1; export let onFilter; @@ -44,10 +45,10 @@ -
Set filter
+
{_t('filter.setFilter', {defaultMessage: 'Set filter'})}
-
Show rows where
+
{_t('filter.showRowsWhere', {defaultMessage: 'Show rows where'})}
@@ -62,9 +63,9 @@
- + {#if !filterBehaviour.disableOr} - + {/if}
@@ -84,7 +85,7 @@
- +
diff --git a/packages/web/src/modals/SetFilterModal_Select.svelte b/packages/web/src/modals/SetFilterModal_Select.svelte index dd4b54b15..2f0ffee8d 100644 --- a/packages/web/src/modals/SetFilterModal_Select.svelte +++ b/packages/web/src/modals/SetFilterModal_Select.svelte @@ -1,56 +1,57 @@ + + +
SQL Script
+ +
+ +
+ +
+ + { + newQuery({ + initialData: sql, + }); + + closeCurrentModal(); + }} + data-testid="ShowSqlModal_openScriptButton" + /> +
+
+ + diff --git a/packages/web/src/modals/ValueLookupModal.svelte b/packages/web/src/modals/ValueLookupModal.svelte index a4c24ac8b..7b3701ac6 100644 --- a/packages/web/src/modals/ValueLookupModal.svelte +++ b/packages/web/src/modals/ValueLookupModal.svelte @@ -16,6 +16,7 @@ import { apiCall } from '../utility/api'; import ErrorInfo from '../elements/ErrorInfo.svelte'; import { base64ToHex } from 'dbgate-tools'; + import { _t } from '../translations'; export let onConfirm; export let conid; @@ -74,15 +75,15 @@ - Choose value from {field} + {_t('dataGrid.chooseValue', { defaultMessage: 'Choose value from {field}', values: { field } })}
- +
{#if isLoading} - + {/if} {#if !isLoading && rows} @@ -112,7 +113,7 @@ }, { fieldName: 'value', - header: 'Value', + header: _t('dataGrid.value', { defaultMessage: 'Value' }), formatter: row => (row.value == null ? '(NULL)' : row.value?.$binary?.base64 ? base64ToHex(row.value.$binary.base64) : row.value), }, ]} @@ -147,7 +148,7 @@ }} /> {/if} - +
diff --git a/packages/web/src/plugins/ThemeDark.svelte b/packages/web/src/plugins/ThemeDark.svelte index 7afba20f4..d36e5a766 100644 --- a/packages/web/src/plugins/ThemeDark.svelte +++ b/packages/web/src/plugins/ThemeDark.svelte @@ -75,7 +75,7 @@ --token-base: #303030; --token-text: #ddd; - --token-keyword: white; + --token-keyword: #096dd9; --token-selector-tag: white; --token-literal: white; --token-section: white; diff --git a/packages/web/src/query/MessageView.svelte b/packages/web/src/query/MessageView.svelte index 465e53713..99c82d6bf 100644 --- a/packages/web/src/query/MessageView.svelte +++ b/packages/web/src/query/MessageView.svelte @@ -4,6 +4,8 @@ import RowsFilterSwitcher from '../forms/RowsFilterSwitcher.svelte'; import SearchInput from '../elements/SearchInput.svelte'; import { filterName } from 'dbgate-tools'; + import InlineButton from '../buttons/InlineButton.svelte'; + import FontIcon from '../icons/FontIcon.svelte'; export let items: any[]; export let showProcedure = false; @@ -12,8 +14,10 @@ export let startLine = 0; export let onMessageClick = null; export let onExplainError = null; + export let engine = null; export let filter = ''; + export let onClear = null; $: time0 = items[0] && new Date(items[0].time).getTime(); @@ -37,6 +41,17 @@
+ {#if onClear} + { + onClear(); + }} + > + + Clear + + {/if} 0 ? items[index - 1] : null} {onMessageClick} {onExplainError} + {engine} /> {/each} diff --git a/packages/web/src/query/MessageViewRow.svelte b/packages/web/src/query/MessageViewRow.svelte index 4102e7425..90740388c 100644 --- a/packages/web/src/query/MessageViewRow.svelte +++ b/packages/web/src/query/MessageViewRow.svelte @@ -17,6 +17,10 @@ import FontIcon from '../icons/FontIcon.svelte'; import { plusExpandIcon } from '../icons/expandIcons'; import InlineButton from '../buttons/InlineButton.svelte'; + import SqlHighlighter from '../elements/SqlHighlighter.svelte'; + import { showModal } from '../modals/modalTools'; + import ShowSqlModal from '../modals/ShowSqlModal.svelte'; + import openNewTab from '../utility/openNewTab'; export let row; export let index; @@ -29,6 +33,7 @@ export let previousRow = null; export let onMessageClick = null; export let onExplainError = null; + export let engine = null; let isExpanded = false; @@ -55,10 +60,39 @@ }}> Explain {/if} + {#if row.jslid} + { + openNewTab({ + title: 'Query data #', + icon: 'img query-data', + tabComponent: 'ArchiveFileTab', + props: { + jslid: row.jslid, + }, + }); + }}> Show Data + {/if} + {#if row.sql} + 100 ? '...' : '')} + inline + onClick={() => { + showModal(ShowSqlModal, { + sql: row.sql, + engine, + }); + }} + /> + {/if} {moment(row.time).format('HH:mm:ss')} {formatDuration(new Date(row.time).getTime() - time0)} - {previousRow ? formatDuration(new Date(row.time).getTime() - new Date(previousRow.time).getTime()) : 'n/a'} + {previousRow ? formatDuration(new Date(row.time).getTime() - new Date(previousRow.time).getTime()) : 'n/a'} {#if showProcedure} {row.procedure || ''} {/if} diff --git a/packages/web/src/query/SocketMessageView.svelte b/packages/web/src/query/SocketMessageView.svelte index 90e66f44f..4bc6f7db5 100644 --- a/packages/web/src/query/SocketMessageView.svelte +++ b/packages/web/src/query/SocketMessageView.svelte @@ -12,12 +12,13 @@ export let showLine = false; export let showCaller = false; export let eventName; - export let executeNumber; + export let executeNumber = null; export let showNoMessagesAlert = false; export let startLine = 0; export let onChangeErrors = null; export let onMessageClick = null; export let onExplainError = null; + export let engine = null; const cachedMessagesRef = createRef([]); const lastErrorMessageCountRef = createRef(0); @@ -43,6 +44,11 @@ return () => {}; }); + function handleClearMessages() { + cachedMessagesRef.set([]); + displayedMessages = []; + } + $: { if (executeNumber >= 0) { displayedMessages = []; @@ -79,5 +85,7 @@ {showCaller} {startLine} {onExplainError} + {engine} + onClear={executeNumber == null ? handleClearMessages : null} /> {/if} diff --git a/packages/web/src/settings/ConnectionAdvancedDriverFields.svelte b/packages/web/src/settings/ConnectionAdvancedDriverFields.svelte index ddacf3375..43ff82431 100644 --- a/packages/web/src/settings/ConnectionAdvancedDriverFields.svelte +++ b/packages/web/src/settings/ConnectionAdvancedDriverFields.svelte @@ -4,6 +4,7 @@ import { getFormContext } from '../forms/FormProviderCore.svelte'; import FormTextAreaField from '../forms/FormTextAreaField.svelte'; import FormArgumentList from '../forms/FormArgumentList.svelte'; + import { _t } from '../translations'; const { values } = getFormContext(); @@ -16,8 +17,8 @@ $: advancedFields = driver?.getAdvancedConnectionFields ? driver?.getAdvancedConnectionFields() : null; - - + + {#if advancedFields} diff --git a/packages/web/src/settings/ConnectionDriverFields.svelte b/packages/web/src/settings/ConnectionDriverFields.svelte index 32076ef62..9eec3f334 100644 --- a/packages/web/src/settings/ConnectionDriverFields.svelte +++ b/packages/web/src/settings/ConnectionDriverFields.svelte @@ -87,13 +87,13 @@ !driver.isElectronOnly || electron) @@ -109,7 +109,7 @@ {#if $authTypes && driver?.showConnectionField('authType', $values, showConnectionFieldArgs) && driver?.authTypeFirst} {#key $authTypes} {:else} @@ -164,8 +164,8 @@ name="useDatabaseUrl" matchValueToOption={(value, option) => !!option.value == !!value} options={[ - { label: 'Fill database connection details', value: '', default: true }, - { label: 'Use database URL', value: '1' }, + { label: _t('connection.fillDetails', { defaultMessage: 'Fill database connection details' }), value: '', default: true }, + { label: _t('connection.useUrl', { defaultMessage: 'Use database URL' }), value: '1' }, ]} />
@@ -173,7 +173,7 @@ {#if driver?.showConnectionField('databaseUrl', $values, showConnectionFieldArgs)}
- Under docker, localhost and 127.0.0.1 will not work, use dockerhost instead + { _t('connection.dockerWarning', { defaultMessage: 'Under docker, localhost and 127.0.0.1 will not work, use dockerhost instead' }) }
{/if} {/if} @@ -280,7 +280,7 @@
@@ -418,7 +418,7 @@ {#if driver?.showConnectionField('treeKeySeparator', $values, showConnectionFieldArgs)} {/if} {#if defaultDatabase && driver?.showConnectionField('singleDatabase', $values, showConnectionFieldArgs)} + {/if} {#if driver}
{#if electron} {:else}
{#if $platformInfo && $platformInfo.sshAuthSock} - SSH Agent found + {_t('connection.sshTunnel.agentFound', {defaultMessage: "SSH Agent found"})} {:else} - SSH Agent not found + {_t('connection.sshTunnel.agentNotFound', {defaultMessage: "SSH Agent not found"})} {/if}
{/if} diff --git a/packages/web/src/settings/ConnectionSslFields.svelte b/packages/web/src/settings/ConnectionSslFields.svelte index 24936f42f..a50928458 100644 --- a/packages/web/src/settings/ConnectionSslFields.svelte +++ b/packages/web/src/settings/ConnectionSslFields.svelte @@ -7,6 +7,7 @@ import getElectron from '../utility/getElectron'; import FormPasswordField from '../forms/FormPasswordField.svelte'; import { openedConnections, openedSingleDatabaseConnections } from '../stores'; + import { _t } from '../translations'; const { values, setFieldValue } = getFormContext(); const electron = getElectron(); @@ -15,21 +16,21 @@ $: isConnected = $openedConnections.includes($values._id) || $openedSingleDatabaseConnections.includes($values._id); - - + + - + diff --git a/packages/web/src/settings/SettingsModal.svelte b/packages/web/src/settings/SettingsModal.svelte index a68f98941..ba062e1ed 100644 --- a/packages/web/src/settings/SettingsModal.svelte +++ b/packages/web/src/settings/SettingsModal.svelte @@ -44,6 +44,10 @@ import AiSettingsTab from './AiSettingsTab.svelte'; import { _t } from '../translations'; import hasPermission from '../utility/hasPermission'; + import ConfirmModal from '../modals/ConfirmModal.svelte'; + import { showModal } from '../modals/modalTools'; + import { internalRedirectTo } from '../clientAuth'; + import { getSelectedLanguage } from '../translations'; const electron = getElectron(); let restartWarning = false; @@ -93,7 +97,7 @@ ORDER BY -
Settings
+
{_t('settings.title', { defaultMessage: 'Settings' })}
{#if electron} -
Appearance
+
{_t('settings.appearance', { defaultMessage: 'Appearance' })}
{#if restartWarning}
- Native menu settings will be applied after app restart + {_t('settings.nativeMenuRestartWarning', { defaultMessage: 'Native menu settings will be applied after app restart' })}
{/if} {/if} - + /> -
Data grid
+
{_t('settings.dataGrid.title', { defaultMessage: 'Data grid' })}
- + - + - + -
SQL editor
+
{_t('settings.sqlEditor', { defaultMessage: 'SQL editor' })}
- +
- + ($currentEditorWrapEnabled = e.target.checked)} @@ -243,33 +248,33 @@ ORDER BY -
Connection
+
{_t('settings.connection', { defaultMessage: 'Connection' })}
{ @@ -282,17 +287,17 @@ ORDER BY -
Query sessions
+
{_t('settings.session', { defaultMessage: 'Query sessions' })}
-
Application theme
+
{_t('settings.appearance', { defaultMessage: 'Application theme' })}
{ @@ -352,19 +357,19 @@ ORDER BY
- More themes are available as plugins + {_t('settings.appearance.moreThemes', { defaultMessage: 'More themes are available as' })} plugins
- After installing theme plugin (try search "theme" in available extensions) new themes will be available here. + {_t('settings.appearance.afterInstalling', { defaultMessage: 'After installing theme plugin (try search "theme" in available extensions) new themes will be available here.' })}
-
Editor theme
+
{_t('settings.appearance.editorTheme', { defaultMessage: 'Editor theme' })}
- + ({ label: theme, value: theme }))} value={$currentEditorTheme} on:change={e => ($currentEditorTheme = e.detail)} @@ -373,7 +378,7 @@ ORDER BY
- +
- + ($currentEditorFontSize = e.target['value'])} @@ -396,7 +401,7 @@ ORDER BY
- +
@@ -405,68 +410,68 @@ ORDER BY
-
Default actions
+
{_t('settings.defaultActions', { defaultMessage: 'Default actions' })}
- +
-
Behaviour
+
{_t('settings.behaviour', { defaultMessage: 'Behaviour' })}
- +
- When you single-click or select a file in the "Tables, Views, Functions" view, it - is shown in a preview mode and reuses an existing tab (preview tab). This is useful if you are quickly browsing - tables and don't want every visited table to have its own tab. When you start editing the table or use double-click - to open the table from the "Tables" view, a new tab is dedicated to that table. + {_t('settings.behaviour.singleClickPreview', { defaultMessage: 'When you single-click or select a file in the "Tables, Views, Functions" view, it is shown in a preview mode and reuses an existing tab (preview tab). This is useful if you are quickly browsing tables and don\'t want every visited table to have its own tab. When you start editing the table or use double-click to open the table from the "Tables" view, a new tab is dedicated to that table.' })}
-
Confirmations
+
{_t('settings.confirmations', { defaultMessage: 'Confirmations' })}
- +
-
Other
+
{_t('settings.other', { defaultMessage: 'Other' })}
- + {#if isProApp()} {/if}
-
License
+
{_t('settings.other.license', { defaultMessage: 'License' })}
{ licenseKeyCheckResult = await apiCall('config/check-license', { licenseKey: value }); @@ -536,28 +538,28 @@ ORDER BY
{#if licenseKeyCheckResult.status == 'ok'}
- License key is valid + { _t('settings.other.licenseKey.valid', { defaultMessage: 'License key is valid' }) }
{#if licenseKeyCheckResult.validTo}
- License valid to: {licenseKeyCheckResult.validTo} + { _t('settings.other.licenseKey.validTo', { defaultMessage: 'License valid to:' }) } {licenseKeyCheckResult.validTo}
{/if} {#if licenseKeyCheckResult.expiration} -
License key expiration: {safeFormatDate(licenseKeyCheckResult.expiration)}
+
{ _t('settings.other.licenseKey.expiration', { defaultMessage: 'License key expiration:' }) } {safeFormatDate(licenseKeyCheckResult.expiration)}
{/if} {:else if licenseKeyCheckResult.status == 'error'}
- {licenseKeyCheckResult.errorMessage ?? 'License key is invalid'} + {licenseKeyCheckResult.errorMessage ?? _t('settings.other.licenseKey.invalid', { defaultMessage: 'License key is invalid' })} {#if licenseKeyCheckResult.expiration} -
License key expiration: {safeFormatDate(licenseKeyCheckResult.expiration)}
+
{ _t('settings.other.licenseKey.expiration', { defaultMessage: 'License key expiration:' }) } {safeFormatDate(licenseKeyCheckResult.expiration)}
{/if}
{#if licenseKeyCheckResult.isExpired}
{ licenseKeyCheckResult = await apiCall('config/get-new-license', { oldLicenseKey: licenseKey }); @@ -574,24 +576,32 @@ ORDER BY -
External tools
+
{_t('settings.externalTools', { defaultMessage: 'External tools' })}
- + - +
@@ -602,7 +612,7 @@ ORDER BY
- +
diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index 6ab382f5e..6b169ef82 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -9,6 +9,7 @@ import { safeJsonParse } from 'dbgate-tools'; import { apiCall } from './utility/api'; import { getOpenedTabsStorageName, isAdminPage } from './utility/pageDefs'; import { switchCurrentDatabase } from './utility/common'; +import { tick } from 'svelte'; export interface TabDefinition { title: string; @@ -187,6 +188,8 @@ export const seenPremiumPromoWidget = writableWithStorage(null, 'seenPremiumProm export const cloudConnectionsStore = writable({}); +export const promoWidgetPreview = writable(null); + export const DEFAULT_OBJECT_SEARCH_SETTINGS = { pureName: true, schemaName: false, @@ -225,6 +228,12 @@ currentTheme.subscribe(value => { }); export const getCurrentTheme = () => currentThemeValue; +let extensionsValue: ExtensionsDirectory = null; +extensions.subscribe(value => { + extensionsValue = value; +}); +export const getExtensions = () => extensionsValue; + export const currentThemeDefinition = derived( [currentTheme, extensions, systemThemeStore], ([$currentTheme, $extensions, $systemTheme]) => { @@ -236,7 +245,9 @@ currentThemeDefinition.subscribe(value => { if (value?.themeType && getCurrentTheme()) { localStorage.setItem('currentThemeType', value?.themeType); } else { - localStorage.removeItem('currentThemeType'); + if (extensionsValue?.themes?.length > 0) { + localStorage.removeItem('currentThemeType'); + } } }); export const openedConnectionsWithTemporary = derived( @@ -307,17 +318,40 @@ openedTabs.subscribe(value => { }); export const getOpenedTabs = () => openedTabsValue; +let openedModalsValue = []; +openedModals.subscribe(value => { + openedModalsValue = value; + + tick().then(() => { + dispatchUpdateCommands(); + }); +}); +export const getOpenedModals = () => openedModalsValue; + let commandsValue = null; commands.subscribe(value => { commandsValue = value; - const electron = getElectron(); - if (electron) { - electron.send('update-commands', JSON.stringify(value)); - } + tick().then(() => { + dispatchUpdateCommands(); + }); }); export const getCommands = () => commandsValue; +function dispatchUpdateCommands() { + const electron = getElectron(); + if (electron) { + electron.send( + 'update-commands', + JSON.stringify({ + isModalOpened: openedModalsValue?.length > 0, + commands: commandsValue, + dbgatePage: window['dbgate_page'], + }) + ); + } +} + let activeTabValue = null; activeTab.subscribe(value => { activeTabValue = value; @@ -363,12 +397,6 @@ export const getCurrentDatabase = () => currentDatabaseValue; let currentSettingsValue = null; export const getCurrentSettings = () => currentSettingsValue || {}; -let extensionsValue: ExtensionsDirectory = null; -extensions.subscribe(value => { - extensionsValue = value; -}); -export const getExtensions = () => extensionsValue; - let openedConnectionsValue = null; openedConnections.subscribe(value => { openedConnectionsValue = value; @@ -415,12 +443,6 @@ selectedDatabaseObjectAppObject.subscribe(value => { }); export const getSelectedDatabaseObjectAppObject = () => selectedDatabaseObjectAppObjectValue; -let openedModalsValue = []; -openedModals.subscribe(value => { - openedModalsValue = value; -}); -export const getOpenedModals = () => openedModalsValue; - let focusedConnectionOrDatabaseValue = null; focusedConnectionOrDatabase.subscribe(value => { focusedConnectionOrDatabaseValue = value; diff --git a/packages/web/src/tableeditor/ColumnEditorModal.svelte b/packages/web/src/tableeditor/ColumnEditorModal.svelte index 8b94b8f0d..75914a766 100644 --- a/packages/web/src/tableeditor/ColumnEditorModal.svelte +++ b/packages/web/src/tableeditor/ColumnEditorModal.svelte @@ -27,41 +27,41 @@ {columnInfo ? 'Edit column' : `Add column ${(tableInfo?.columns || []).length + 1}`}{columnInfo ? _t('columnEditor.editColumn', { defaultMessage: 'Edit column' }) : _t('columnEditor.addColumn', { defaultMessage: 'Add column {columnNumber}', values: { columnNumber: (tableInfo?.columns || []).length + 1 } })}
- + {#if !driver?.dialect?.specificNullabilityImplementation} {/if} - + {#if !driver?.dialect?.disableAutoIncrement} - + {/if} - + {#if driver?.dialect?.columnProperties?.isUnsigned} - + {/if} {#if driver?.dialect?.columnProperties?.isZerofill} - + {/if} {#if driver?.dialect?.columnProperties?.columnComment} - + {/if} {#if driver?.dialect?.columnProperties?.isSparse} - + {/if} { closeCurrentModal(); @@ -85,11 +85,11 @@ /> {/if} - + {#if columnInfo} { closeCurrentModal(); setTableInfo(tbl => editorDeleteColumn(tbl, columnInfo, addDataCommand)); diff --git a/packages/web/src/tableeditor/ColumnsConstraintEditorModal.svelte b/packages/web/src/tableeditor/ColumnsConstraintEditorModal.svelte index 431671266..d888a2749 100644 --- a/packages/web/src/tableeditor/ColumnsConstraintEditorModal.svelte +++ b/packages/web/src/tableeditor/ColumnsConstraintEditorModal.svelte @@ -9,13 +9,15 @@ import { editorAddConstraint, editorDeleteConstraint, editorModifyConstraint } from 'dbgate-tools'; import TextField from '../forms/TextField.svelte'; import SelectField from '../forms/SelectField.svelte'; + import { _t, __t } from '../translations'; + import _ from 'lodash'; export let constraintInfo; export let setTableInfo; export let tableInfo; export let constraintLabel; export let constraintType; - export let constraintNameLabel = 'Constraint name'; + export let constraintNameLabel = _t('tableEditor.constraintName', { defaultMessage: 'Constraint name' }); export let getExtractConstraintProps; export let hideConstraintName = false; @@ -41,7 +43,7 @@ {constraintInfo ? `Edit ${constraintLabel}` : `Add ${constraintLabel}`}{constraintInfo ? _t('tableEdit.editConstraintLabel', { defaultMessage: 'Edit {constraintLabel}', values: { constraintLabel } }) : _t('tableEdit.addConstraintLabel', { defaultMessage: 'Add {constraintLabel}', values: { constraintLabel } })}
@@ -65,7 +67,7 @@ {#each columns as column, index}
-
Column {index + 1}
+
{_t('common.column', { defaultMessage: 'Column ' })}{index + 1}
{#key column.columnName} { const x = [...columns]; @@ -104,11 +106,11 @@ {/each}
-
Add new column
+
{_t('columnsConstraintEditor.addNewColumn', { defaultMessage: 'Add new column' })}
{#key columns.length} { @@ -123,7 +125,7 @@ isNative options={[ { - label: 'Choose column', + label: _t('columnsConstraintEditor.chooseColumn', { defaultMessage: 'Choose column' }) , value: '', }, ...(tableInfo?.columns?.map(col => ({ @@ -139,7 +141,7 @@ { closeCurrentModal(); @@ -151,11 +153,11 @@ }} /> - + {#if constraintInfo} { closeCurrentModal(); diff --git a/packages/web/src/tableeditor/DataTypeEditor.svelte b/packages/web/src/tableeditor/DataTypeEditor.svelte index c518475f0..6693c030c 100644 --- a/packages/web/src/tableeditor/DataTypeEditor.svelte +++ b/packages/web/src/tableeditor/DataTypeEditor.svelte @@ -1,6 +1,7 @@ - + diff --git a/packages/web/src/tableeditor/ForeignKeyEditorModal.svelte b/packages/web/src/tableeditor/ForeignKeyEditorModal.svelte index 7d4c82871..e6a6eac54 100644 --- a/packages/web/src/tableeditor/ForeignKeyEditorModal.svelte +++ b/packages/web/src/tableeditor/ForeignKeyEditorModal.svelte @@ -60,11 +60,11 @@ - {constraintInfo ? `Edit foreign key` : `Add foreign key`} + {constraintInfo ? _t('foreignKeyEditor.editForeignKey', { defaultMessage: 'Edit foreign key' }) : _t('foreignKeyEditor.addForeignKey', { defaultMessage: 'Add foreign key' })}
-
Constraint name
+
{_t('tableEditor.constraintName', { defaultMessage: 'Constraint name' })}
-
Referenced table
+
{_t('foreignKeyEditor.referencedTable', { defaultMessage: 'Referenced table' })}
-
On update action
+
{_t('foreignKeyEditor.onUpdateAction', { defaultMessage: 'On update action' })}
-
On delete action
+
{_t('foreignKeyEditor.onDeleteAction', { defaultMessage: 'On delete action' })}
- Base column - {tableInfo.pureName} + {_t('foreignKeyEditor.baseColumn', { defaultMessage: 'Base column - ' })}{tableInfo.pureName}
- Ref column - {refTableName || '(table not set)'} + {_t('foreignKeyEditor.refColumn', { defaultMessage: 'Ref column - ' })}{refTableName || _t('foreignKeyEditor.tableNotSet', { defaultMessage: '(table not set)' })}
@@ -195,7 +195,7 @@ { columns = [...columns, {}]; @@ -217,12 +217,12 @@ }} /> - + {#if constraintInfo} { closeCurrentModal(); setTableInfo(tbl => editorDeleteConstraint(tbl, constraintInfo)); diff --git a/packages/web/src/tableeditor/IndexEditorModal.svelte b/packages/web/src/tableeditor/IndexEditorModal.svelte index a86186ebc..df1dff3f4 100644 --- a/packages/web/src/tableeditor/IndexEditorModal.svelte +++ b/packages/web/src/tableeditor/IndexEditorModal.svelte @@ -3,6 +3,7 @@ import FormCheckboxField from '../forms/FormCheckboxField.svelte'; import SelectField from '../forms/SelectField.svelte'; import TextField from '../forms/TextField.svelte'; + import { _t } from '../translations'; import ColumnsConstraintEditorModal from './ColumnsConstraintEditorModal.svelte'; @@ -29,7 +30,7 @@ {...$$restProps} constraintLabel="index" constraintType="index" - constraintNameLabel="Index name" + constraintNameLabel={_t('indexEditor.indexName', { defaultMessage: 'Index name' })} {constraintInfo} {setTableInfo} {tableInfo} @@ -61,15 +62,14 @@
- (isUnique = e.target.checked)} disabled={isReadOnly} /> Is unique - index + (isUnique = e.target.checked)} disabled={isReadOnly} /> {_t('indexEditor.isUnique', { defaultMessage: 'Is unique index' })}
{#if driver?.dialect?.filteredIndexes}
-
Filtered index condition
+
{_t('indexEditor.filteredIndexCondition', { defaultMessage: 'Filtered index condition' })}
import ColumnsConstraintEditorModal from './ColumnsConstraintEditorModal.svelte'; + import { _t } from '../translations'; export let constraintInfo; export let setTableInfo; export let tableInfo; export let driver; - export let constraintLabel = 'primary key'; + export let constraintLabel = _t('tableEditor.primaryKey', { defaultMessage: 'primary key' }); export let constraintType = 'primaryKey'; diff --git a/packages/web/src/tableeditor/PrimaryKeyLikeListControl.svelte b/packages/web/src/tableeditor/PrimaryKeyLikeListControl.svelte index 3f8de6aac..61e353ea0 100644 --- a/packages/web/src/tableeditor/PrimaryKeyLikeListControl.svelte +++ b/packages/web/src/tableeditor/PrimaryKeyLikeListControl.svelte @@ -9,13 +9,14 @@ import { showModal } from '../modals/modalTools'; import PrimaryKeyEditorModal from './PrimaryKeyEditorModal.svelte'; + import { _t } from '../translations'; export let tableInfo; export let setTableInfo; export let isWritable; export let driver; - export let constraintLabel = 'primary key'; + export let constraintLabel = _t('tableEditor.primaryKey', { defaultMessage: 'primary key' }); export let constraintType = 'primaryKey'; $: columns = tableInfo?.columns; @@ -35,7 +36,12 @@ 0 ? addKeyConstraint : null} hideDisplayName={driver?.dialect?.anonymousPrimaryKey} clickable @@ -51,7 +57,7 @@ columns={[ { fieldName: 'columns', - header: 'Columns', + header: _t('tableEditor.columns', { defaultMessage: 'Columns' }), slot: 0, sortable: true, }, @@ -70,7 +76,7 @@ onClick={e => { e.stopPropagation(); setTableInfo(tbl => editorDeleteConstraint(tbl, row)); - }}>Remove{_t('common.remove', { defaultMessage: 'Remove' })} diff --git a/packages/web/src/tableeditor/TableEditor.svelte b/packages/web/src/tableeditor/TableEditor.svelte index 8b7d54e4b..95da33274 100644 --- a/packages/web/src/tableeditor/TableEditor.svelte +++ b/packages/web/src/tableeditor/TableEditor.svelte @@ -3,8 +3,8 @@ registerCommand({ id: 'tableEditor.addColumn', - category: 'Table editor', - name: 'Add column', + category: __t('tableEditor', { defaultMessage: 'Table editor'}), + name: __t('tableEditor.addColumn', { defaultMessage: 'Add column'}), icon: 'icon add-column', toolbar: true, isRelatedToTab: true, @@ -14,8 +14,8 @@ registerCommand({ id: 'tableEditor.addPrimaryKey', - category: 'Table editor', - name: 'Add primary key', + category: __t('tableEditor', { defaultMessage: 'Table editor'}), + name: __t('tableEditor.addPrimaryKey', { defaultMessage: 'Add primary key'}), icon: 'icon add-key', toolbar: true, isRelatedToTab: true, @@ -25,8 +25,8 @@ registerCommand({ id: 'tableEditor.addForeignKey', - category: 'Table editor', - name: 'Add foreign key', + category: __t('tableEditor', { defaultMessage: 'Table editor'}), + name: __t('tableEditor.addForeignKey', { defaultMessage: 'Add foreign key'}), icon: 'icon add-key', toolbar: true, isRelatedToTab: true, @@ -36,8 +36,8 @@ registerCommand({ id: 'tableEditor.addIndex', - category: 'Table editor', - name: 'Add index', + category: __t('tableEditor', { defaultMessage: 'Table editor'}), + name: __t('tableEditor.addIndex', { defaultMessage: 'Add index'}), icon: 'icon add-key', toolbar: true, isRelatedToTab: true, @@ -47,8 +47,8 @@ registerCommand({ id: 'tableEditor.addUnique', - category: 'Table editor', - name: 'Add unique', + category: __t('tableEditor', { defaultMessage: 'Table editor'}), + name: __t('tableEditor.addUnique', { defaultMessage: 'Add unique'}), icon: 'icon add-key', toolbar: true, isRelatedToTab: true, @@ -83,6 +83,7 @@ import UniqueEditorModal from './UniqueEditorModal.svelte'; import ObjectFieldsEditor from '../elements/ObjectFieldsEditor.svelte'; import PrimaryKeyLikeListControl from './PrimaryKeyLikeListControl.svelte'; + import { __t, _t } from '../translations'; export const activator = createActivator('TableEditor', true); @@ -171,9 +172,9 @@ {#if tableInfo && (tableFormOptions || isCreateTable)} {#key resetCounter} = 0 ? schemaList : null} values={_.pick(tableInfo, ['schemaName', 'pureName', ...(tableFormOptions ?? []).map(x => x.name)])} onChangeValues={vals => { @@ -187,15 +188,15 @@ ({ ...x, ordinal: index + 1 }))} - title={`Columns (${columns?.length || 0})`} - emptyMessage="No columns defined" + title={_t('tableEditor.columns', { defaultMessage: 'Columns ({columnCount})', values: { columnCount: columns?.length || 0 } })} + emptyMessage={_t('tableEditor.nocolumnsdefined', { defaultMessage: 'No columns defined' })} clickable on:clickrow={e => showModal(ColumnEditorModal, { columnInfo: e.detail, tableInfo, setTableInfo, driver })} onAddNew={isWritable ? addColumn : null} displayNameFieldName="columnName" multipleItemsActions={[ { - text: 'Remove', + text: _t('tableEditor.remove', { defaultMessage: 'Remove' }), icon: 'icon delete', onClick: selected => { setTableInfo(tbl => { @@ -205,7 +206,7 @@ }, }, { - text: 'Copy names', + text: _t('tableEditor.copynames', { defaultMessage: 'Copy names' }), icon: 'icon copy', onClick: selected => { const names = selected.map(x => x.columnName).join('\n'); @@ -213,7 +214,7 @@ }, }, { - text: 'Copy definitions', + text: _t('tableEditor.copydefinitions', { defaultMessage: 'Copy definitions' }), icon: 'icon copy', onClick: selected => { const names = selected @@ -226,55 +227,55 @@ columns={[ !driver?.dialect?.specificNullabilityImplementation && { fieldName: 'notNull', - header: 'Nullability', + header: _t('tableEditor.nullability', { defaultMessage: 'Nullability' }), sortable: true, slot: 0, }, { fieldName: 'dataType', - header: 'Data Type', + header: _t('tableEditor.dataType', { defaultMessage: 'Data type' }), sortable: true, filterable: true, }, { fieldName: 'defaultValue', - header: 'Default value', + header: _t('tableEditor.defaultValue', { defaultMessage: 'Default value' }), sortable: true, filterable: true, }, driver?.dialect?.columnProperties?.isSparse && { fieldName: 'isSparse', - header: 'Is Sparse', + header: _t('tableEditor.isSparse', { defaultMessage: 'Is Sparse' }), sortable: true, slot: 1, }, { fieldName: 'computedExpression', - header: 'Computed Expression', + header: _t('tableEditor.computedExpression', { defaultMessage: 'Computed Expression' }), sortable: true, filterable: true, }, driver?.dialect?.columnProperties?.isPersisted && { fieldName: 'isPersisted', - header: 'Is Persisted', + header: _t('tableEditor.isPersisted', { defaultMessage: 'Is Persisted' }), sortable: true, slot: 2, }, driver?.dialect?.columnProperties?.isUnsigned && { fieldName: 'isUnsigned', - header: 'Unsigned', + header: _t('tableEditor.isUnsigned', { defaultMessage: 'Unsigned' }), sortable: true, slot: 4, }, driver?.dialect?.columnProperties?.isZerofill && { fieldName: 'isZerofill', - header: 'Zero fill', + header: _t('tableEditor.isZeroFill', { defaultMessage: 'Zero fill' }), sortable: true, slot: 5, }, driver?.dialect?.columnProperties?.columnComment && { fieldName: 'columnComment', - header: 'Comment', + header: _t('tableEditor.columnComment', { defaultMessage: 'Comment' }), sortable: true, filterable: true, }, @@ -287,19 +288,19 @@ : null, ]} > - {row?.notNull ? 'NOT NULL' : 'NULL'} - {row?.isSparse ? 'YES' : 'NO'} - {row?.isPersisted ? 'YES' : 'NO'} + {row?.notNull ? _t('tableEditor.notnull', { defaultMessage: 'NOT NULL' }) : _t('tableEditor.null', { defaultMessage: 'NULL' })} + {row?.isSparse ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })} + {row?.isPersisted ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })} { e.stopPropagation(); setTableInfo(tbl => editorDeleteColumn(tbl, row)); - }}>Remove{_t('tableEditor.remove', { defaultMessage: 'Remove' })} - {row?.isUnsigned ? 'YES' : 'NO'} - {row?.isZerofill ? 'YES' : 'NO'} + {row?.isUnsigned ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })} + {row?.isZerofill ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })} @@ -320,20 +321,20 @@ 0 ? addIndex : null} - title={`Indexes (${indexes?.length || 0})`} - emptyMessage={isWritable ? 'No index defined' : null} + title={_t('tableEditor.indexes', { defaultMessage: 'Indexes ({indexCount})', values: { indexCount: indexes?.length || 0 } })} + emptyMessage={isWritable ? _t('tableEditor.noindexdefined', { defaultMessage: 'No index defined' }) : null} clickable on:clickrow={e => showModal(IndexEditorModal, { constraintInfo: e.detail, tableInfo, setTableInfo, driver })} columns={[ { fieldName: 'columns', - header: 'Columns', + header: _t('tableEditor.columns', { defaultMessage: 'Columns' }), slot: 0, sortable: true, }, { fieldName: 'unique', - header: 'Unique', + header: _t('tableEditor.unique', { defaultMessage: 'Unique' }), slot: 1, sortable: true, }, @@ -347,13 +348,13 @@ > {row?.columns.map(x => x.columnName).join(', ')} - {row?.isUnique ? 'YES' : 'NO'} + {row?.isUnique ? _t('tableEditor.yes', { defaultMessage: 'YES' }) : _t('tableEditor.no', { defaultMessage: 'NO' })} { e.stopPropagation(); setTableInfo(tbl => editorDeleteConstraint(tbl, row)); - }}>Remove{_t('common.remove', { defaultMessage: 'Remove' })} @@ -363,14 +364,14 @@ 0 ? addUnique : null} - title={`Unique constraints (${uniques?.length || 0})`} - emptyMessage={isWritable ? 'No unique defined' : null} + title={_t('tableEditor.uniqueConstraints', { defaultMessage: 'Unique constraints ({constraintCount})', values: { constraintCount: uniques?.length || 0 } })} + emptyMessage={isWritable ? _t('tableEditor.nouniquedefined', { defaultMessage: 'No unique defined' }) : null} clickable on:clickrow={e => showModal(UniqueEditorModal, { constraintInfo: e.detail, tableInfo, setTableInfo })} columns={[ { fieldName: 'columns', - header: 'Columns', + header: _t('tableEditor.columns', { defaultMessage: 'Columns' }), slot: 0, sortable: true, }, @@ -390,7 +391,7 @@ onClick={e => { e.stopPropagation(); setTableInfo(tbl => editorDeleteConstraint(tbl, row)); - }}>Remove{_t('common.remove', { defaultMessage: 'Remove' })} @@ -400,13 +401,13 @@ 0 ? addForeignKey : null} - title={`Foreign keys (${foreignKeys?.length || 0})`} - emptyMessage={isWritable ? 'No foreign key defined' : null} + title={_t('tableEditor.foreignKeys', { defaultMessage: 'Foreign keys ({foreignKeyCount})', values: { foreignKeyCount: foreignKeys?.length || 0 } })} + emptyMessage={isWritable ? _t('tableEditor.noforeignkeydefined', { defaultMessage: 'No foreign key defined' }) : null} clickable onRemove={row => setTableInfo(tbl => editorDeleteConstraint(tbl, row))} on:clickrow={e => showModal(ForeignKeyEditorModal, { constraintInfo: e.detail, tableInfo, setTableInfo, dbInfo })} /> - + {/if}
diff --git a/packages/web/src/tableeditor/UniqueEditorModal.svelte b/packages/web/src/tableeditor/UniqueEditorModal.svelte index c136f7e43..5328671e3 100644 --- a/packages/web/src/tableeditor/UniqueEditorModal.svelte +++ b/packages/web/src/tableeditor/UniqueEditorModal.svelte @@ -1,5 +1,6 @@
-
+
{#each groupedTabs as tabGroup}
{#if !$lockedDatabaseMode} @@ -713,7 +722,7 @@ {/each}
- {#if allowSplitTab} + {#if allowSplitTab && isProApp()}
splitTab(multiTabIndex)} @@ -723,6 +732,22 @@
{/if} + + {#if !isProApp()} +
{ + openWebLink( + `https://www.dbgate.io/purchase/${isElectronAvailable() ? 'premium' : 'team-premium'}/?utm_campaign=premiumUpgradeButton` + ); + }} + title="Upgrade to Premium" + data-testid="TabsPanel_buttonUpgrade" + > + Upgrade +
+ {/if} +
showModal(NewObjectModal, { multiTabIndex })} @@ -756,6 +781,18 @@ color: var(--theme-font-2); cursor: pointer; } + .upgrade-button { + background: linear-gradient(135deg, #1686c8, #8a25b1); + border: 1px solid var(--theme-border); + border-radius: 10px; + color: white; + cursor: pointer; + font-size: 10pt; + padding: 5px; + } + .upgrade-button:hover { + background: linear-gradient(135deg, #0f5a85, #5c1870); + } .icon-button:hover { color: var(--theme-font-1); } @@ -769,6 +806,10 @@ right: 35px; bottom: 0; } + + .tabs-upgrade-button { + right: 120px; + } .tabs.can-split { right: 60px; } diff --git a/packages/web/src/tabs/ArchiveFileTab.svelte b/packages/web/src/tabs/ArchiveFileTab.svelte index 6f3ab527c..d82922f7d 100644 --- a/packages/web/src/tabs/ArchiveFileTab.svelte +++ b/packages/web/src/tabs/ArchiveFileTab.svelte @@ -6,8 +6,8 @@ registerCommand({ id: 'archiveFile.save', group: 'save', - category: 'Archive file', - name: 'Save', + category: __t('command.archiveFile', { defaultMessage: 'Archive file' }), + name: __t('command.archiveFile.save', { defaultMessage: 'Save' }), toolbar: true, isRelatedToTab: true, icon: 'icon save', @@ -17,8 +17,8 @@ registerCommand({ id: 'archiveFile.saveAs', - category: 'Archive file', - name: 'Save as', + category: __t('command.archiveFile', { defaultMessage: 'Archive file' }), + name: __t('command.archiveFile.saveAs', { defaultMessage: 'Save as' }), icon: 'icon save', isRelatedToTab: true, testEnabled: () => getCurrentEditor() != null, @@ -49,6 +49,7 @@ import { changeTab, markTabSaved, markTabUnsaved, sleep } from '../utility/common'; import createActivator, { getActiveComponent } from '../utility/createActivator'; import createUndoReducer from '../utility/createUndoReducer'; + import { __t } from '../translations'; export const activator = createActivator('ArchiveFileTab', true); diff --git a/packages/web/src/tabs/CollectionDataTab.svelte b/packages/web/src/tabs/CollectionDataTab.svelte index 434149abe..186ecc372 100644 --- a/packages/web/src/tabs/CollectionDataTab.svelte +++ b/packages/web/src/tabs/CollectionDataTab.svelte @@ -8,8 +8,8 @@ registerCommand({ id: 'collectionTable.save', group: 'save', - category: 'Collection data', - name: 'Save', + category: __t('command.collectionData', { defaultMessage: 'Collection data' }), + name: __t('command.collectionData.save', { defaultMessage: 'Save' }), // keyText: 'CtrlOrCommand+S', toolbar: true, isRelatedToTab: true, @@ -56,6 +56,7 @@ import useEditorData from '../query/useEditorData'; import { markTabSaved, markTabUnsaved } from '../utility/common'; import { getNumberIcon } from '../icons/FontIcon.svelte'; + import { __t } from '../translations'; export let tabid; export let conid; diff --git a/packages/web/src/tabs/ConnectionTab.svelte b/packages/web/src/tabs/ConnectionTab.svelte index 37275a039..fa1352dbd 100644 --- a/packages/web/src/tabs/ConnectionTab.svelte +++ b/packages/web/src/tabs/ConnectionTab.svelte @@ -300,7 +300,7 @@ contentTestId="ConnectionTab_tabControlContent" tabs={[ { - label: 'General', + label: _t('common.general', { defaultMessage: 'General' }), component: ConnectionDriverFields, props: { getDatabaseList, currentConnection }, testid: 'ConnectionTab_tabGeneral', @@ -316,7 +316,7 @@ testid: 'ConnectionTab_tabSsl', }, { - label: 'Advanced', + label: _t('common.advanced', { defaultMessage: 'Advanced' }), component: ConnectionAdvancedDriverFields, testid: 'ConnectionTab_tabAdvanced', }, @@ -383,7 +383,7 @@ {/if} {#if isTesting}
- Testing connection + {_t('common.testingConnection', { defaultMessage: 'Testing connection' })}
{/if}
diff --git a/packages/web/src/tabs/DiagramTab.svelte b/packages/web/src/tabs/DiagramTab.svelte index 735f29670..73657781a 100644 --- a/packages/web/src/tabs/DiagramTab.svelte +++ b/packages/web/src/tabs/DiagramTab.svelte @@ -3,7 +3,7 @@ registerFileCommands({ idPrefix: 'diagram', - category: 'Diagram', + category: __t('command.diagram', { defaultMessage: 'Diagram' }), getCurrentEditor, folder: 'diagrams', format: 'json', @@ -32,6 +32,7 @@ import DiagramSettings from '../designer/DiagramSettings.svelte'; import { derived } from 'svelte/store'; import { isProApp } from '../utility/proTools'; + import { __t } from '../translations'; export let tabid; export let conid; diff --git a/packages/web/src/tabs/FavoriteEditorTab.svelte b/packages/web/src/tabs/FavoriteEditorTab.svelte index 587772bf0..14252fc05 100644 --- a/packages/web/src/tabs/FavoriteEditorTab.svelte +++ b/packages/web/src/tabs/FavoriteEditorTab.svelte @@ -3,7 +3,7 @@ registerFileCommands({ idPrefix: 'favoriteJsonEditor', - category: 'Favorite JSON editor', + category: __t('command.favoriteJsonEditor', { defaultMessage: 'Favorite JSON editor' }), getCurrentEditor, folder: null, format: null, @@ -15,15 +15,15 @@ registerCommand({ id: 'favoriteJsonEditor.save', group: 'save', - name: 'Save', - category: 'Favorite JSON editor', + name: __t('command.favoriteJsonEditor.save', { defaultMessage: 'Save' }), + category: __t('command.favoriteJsonEditor', { defaultMessage: 'Favorite JSON editor' }), testEnabled: () => getCurrentEditor() != null, onClick: () => getCurrentEditor().save(), }); registerCommand({ id: 'favoriteJsonEditor.preview', - name: 'Preview', - category: 'Favorite JSON editor', + name: __t('command.favoriteJsonEditor.preview', { defaultMessage: 'Preview' }), + category: __t('command.favoriteJsonEditor', { defaultMessage: 'Favorite JSON editor' }), keyText: 'F5 | CtrlOrCommand+Enter', testEnabled: () => getCurrentEditor() != null, onClick: () => getCurrentEditor().preview(), @@ -43,6 +43,7 @@ import { openFavorite } from '../appobj/FavoriteFileAppObject.svelte'; import createActivator, { getActiveComponent } from '../utility/createActivator'; import { apiCall } from '../utility/api'; + import { __t } from '../translations'; export let tabid; export let savedFile; diff --git a/packages/web/src/tabs/JsonLinesEditorTab.svelte b/packages/web/src/tabs/JsonLinesEditorTab.svelte index c2804999c..76fd6dae9 100644 --- a/packages/web/src/tabs/JsonLinesEditorTab.svelte +++ b/packages/web/src/tabs/JsonLinesEditorTab.svelte @@ -17,7 +17,7 @@ id: 'jsonl.save', group: 'save', category: 'JSON Lines editor', - name: 'Save', + name: __t('command.jsonl.save', { defaultMessage: 'Save' }), toolbar: true, isRelatedToTab: true, icon: 'icon save', @@ -28,7 +28,7 @@ registerCommand({ id: 'jsonl.preview', category: 'JSON Lines editor', - name: 'Preview', + name: __t('command.jsonl.preview', { defaultMessage: 'Preview' }), icon: 'icon preview', keyText: 'F5', testEnabled: () => getCurrentEditor() != null, @@ -38,7 +38,7 @@ registerCommand({ id: 'jsonl.previewNewTab', category: 'JSON Lines editor', - name: 'Preview in new tab', + name: __t('command.jsonl.previewNewTab', { defaultMessage: 'Preview in new tab' }), icon: 'icon preview', testEnabled: () => getCurrentEditor() != null, onClick: () => getCurrentEditor().previewMewTab(), @@ -47,7 +47,7 @@ registerCommand({ id: 'jsonl.closePreview', category: 'JSON Lines editor', - name: 'Close preview', + name: __t('command.jsonl.closePreview', { defaultMessage: 'Close preview' }), icon: 'icon close', testEnabled: () => getCurrentEditor()?.isPreview(), onClick: () => getCurrentEditor().closePreview(), @@ -74,6 +74,7 @@ import VerticalSplitter from '../elements/VerticalSplitter.svelte'; import JslDataGrid from '../datagrid/JslDataGrid.svelte'; import ToolStripCommandSplitButton from '../buttons/ToolStripCommandSplitButton.svelte'; + import { __t } from '../translations'; export let tabid; export let archiveFolder; diff --git a/packages/web/src/tabs/MarkdownEditorTab.svelte b/packages/web/src/tabs/MarkdownEditorTab.svelte index 3df2c9826..e73eb11e5 100644 --- a/packages/web/src/tabs/MarkdownEditorTab.svelte +++ b/packages/web/src/tabs/MarkdownEditorTab.svelte @@ -16,7 +16,7 @@ registerCommand({ id: 'markdown.preview', category: 'Markdown', - name: 'Preview', + name: __t('command.markdown.preview', { defaultMessage: 'Preview' }), icon: 'icon run', toolbar: true, isRelatedToTab: true, @@ -38,6 +38,7 @@ import openNewTab from '../utility/openNewTab'; import { setSelectedTab } from '../utility/common'; import createActivator, { getActiveComponent } from '../utility/createActivator'; + import { __t } from '../translations'; export let tabid; diff --git a/packages/web/src/tabs/QueryDataTab.svelte b/packages/web/src/tabs/QueryDataTab.svelte index f188f1d83..7fa070633 100644 --- a/packages/web/src/tabs/QueryDataTab.svelte +++ b/packages/web/src/tabs/QueryDataTab.svelte @@ -5,8 +5,8 @@ registerCommand({ id: 'queryData.stopLoading', - category: 'Query data', - name: 'Stop loading', + category: __t('command.queryData', { defaultMessage: 'Query data' }), + name: __t('command.queryData.stopLoading', { defaultMessage: 'Stop loading' }), icon: 'icon stop', testEnabled: () => getCurrentEditor()?.isLoading(), onClick: () => getCurrentEditor().stopLoading(), @@ -32,6 +32,7 @@ import yaml from 'js-yaml'; import JslChart from '../charts/JslChart.svelte'; import ToolStripButton from '../buttons/ToolStripButton.svelte'; + import { __t } from '../translations'; export const activator = createActivator('QueryDataTab', true); diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index fd55fee86..facb19f1a 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -2,21 +2,22 @@ import registerCommand from '../commands/registerCommand'; import { copyTextToClipboard } from '../utility/clipboard'; import yaml from 'js-yaml'; + import { __t, _t } from '../translations'; const getCurrentEditor = () => getActiveComponent('QueryTab'); registerCommand({ id: 'query.formatCode', - category: 'Query', - name: 'Format code', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.formatCode', { defaultMessage: 'Format code' }), keyText: 'Shift+Alt+F', testEnabled: () => getCurrentEditor()?.isSqlEditor(), onClick: () => getCurrentEditor().formatCode(), }); registerCommand({ id: 'query.switchAiAssistant', - category: 'Query', - name: 'AI Assistant', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.AiAssistant', { defaultMessage: 'AI Assistant' }), keyText: 'Shift+Alt+A', icon: 'icon ai', testEnabled: () => isProApp(), @@ -24,23 +25,23 @@ }); registerCommand({ id: 'query.insertSqlJoin', - category: 'Query', - name: 'Insert SQL Join', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.insertSqlJoin', { defaultMessage: 'Insert SQL Join' }), keyText: 'CtrlOrCommand+J', testEnabled: () => getCurrentEditor()?.isSqlEditor(), onClick: () => getCurrentEditor().insertSqlJoin(), }); registerCommand({ id: 'query.toggleVisibleResultTabs', - category: 'Query', - name: 'Toggle visible result tabs', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.toggleVisibleResultTabs', { defaultMessage: 'Toggle visible result tabs' }), keyText: 'CtrlOrCommand+Shift+R', testEnabled: () => !!getCurrentEditor(), onClick: () => getCurrentEditor().toggleVisibleResultTabs(), }); registerFileCommands({ idPrefix: 'query', - category: 'Query', + category: __t('command.query', { defaultMessage: 'Query' }), getCurrentEditor, folder: 'sql', format: 'text', @@ -54,8 +55,8 @@ }); registerCommand({ id: 'query.executeCurrent', - category: 'Query', - name: 'Execute current', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.executeCurrent', { defaultMessage: 'Execute current' }), keyText: 'CtrlOrCommand+Shift+Enter', testEnabled: () => getCurrentEditor() != null && !getCurrentEditor()?.isBusy() && getCurrentEditor()?.hasConnection(), @@ -63,56 +64,56 @@ }); registerCommand({ id: 'query.toggleAutoExecute', - category: 'Query', - name: 'Toggle auto execute', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.toggleAutoExecute', { defaultMessage: 'Toggle auto execute' }), testEnabled: () => getCurrentEditor() != null, onClick: () => getCurrentEditor().toggleAutoExecute(), }); registerCommand({ id: 'query.toggleFixedConnection', - category: 'Query', - name: 'Toggle fixed connection', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.toggleFixedConnection', { defaultMessage: 'Toggle fixed connection' }), testEnabled: () => getCurrentEditor() != null, onClick: () => getCurrentEditor().toggleFixedConnection(), }); registerCommand({ id: 'query.beginTransaction', - category: 'Query', - name: 'Begin transaction', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.beginTransaction', { defaultMessage: 'Begin transaction' }), icon: 'icon transaction', testEnabled: () => getCurrentEditor()?.beginTransactionEnabled(), onClick: () => getCurrentEditor().beginTransaction(), }); registerCommand({ id: 'query.autocommitOffSwitch', - category: 'Query', - name: 'Auto commit: OFF', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.autocommitOffSwitch', { defaultMessage: 'Auto commit: OFF' }), icon: 'icon autocommit-off', testEnabled: () => getCurrentEditor()?.autocommitOffSwitchEnabled(), onClick: () => getCurrentEditor().autocommitOffSwitch(), }); registerCommand({ id: 'query.autocommitOnSwitch', - category: 'Query', - name: 'Auto commit: ON', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.autocommitOnSwitch', { defaultMessage: 'Auto commit: ON' }), icon: 'icon autocommit-on', testEnabled: () => getCurrentEditor()?.autocommitOnSwitchEnabled(), onClick: () => getCurrentEditor().autocommitOnSwitch(), }); registerCommand({ id: 'query.commitTransaction', - category: 'Query', - name: 'Commit transaction', - toolbarName: 'Commit', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.commitTransaction', { defaultMessage: 'Commit transaction' }), + toolbarName: __t('command.query.commitTransactionToolbar', { defaultMessage: 'Commit' }), icon: 'icon commit', testEnabled: () => getCurrentEditor()?.endTransactionEnabled(), onClick: () => getCurrentEditor().commitTransaction(), }); registerCommand({ id: 'query.rollbackTransaction', - category: 'Query', - name: 'Rollback transaction', - toolbarName: 'Rollback', + category: __t('command.query', { defaultMessage: 'Query' }), + name: __t('command.query.rollbackTransaction', { defaultMessage: 'Rollback transaction' }), + toolbarName: __t('command.query.rollbackTransactionToolbar', { defaultMessage: 'Rollback' }), icon: 'icon rollback', testEnabled: () => getCurrentEditor()?.endTransactionEnabled(), onClick: () => getCurrentEditor().rollbackTransaction(), @@ -177,27 +178,27 @@ const QUERY_PARAMETER_STYLES = [ { value: '', - text: '(no parameters)', + text: _t('query.noParameters', { defaultMessage: '(no parameters)' }), }, { value: '?', - text: '? (positional)', + text: _t('query.positional', { defaultMessage: '? (positional)' }), }, { value: '@', - text: '@variable', + text: _t('query.variable', { defaultMessage: '@variable' }), }, { value: ':', - text: ':variable', + text: _t('query.named', { defaultMessage: ':variable' }), }, { value: '$', - text: '$variable', + text: _t('query.variable', { defaultMessage: '$variable' }), }, { value: '#', - text: '#variable', + text: _t('query.variable', { defaultMessage: '#variable' }), }, ]; @@ -265,9 +266,11 @@ if (sid) { apiOn(`session-done-${sid}`, handleSessionDone); apiOn(`session-closed-${sid}`, handleSessionClosed); + apiOn(`session-changedb-${sid}`, handleChangedDatabase); return () => { apiOff(`session-done-${sid}`, handleSessionDone); apiOff(`session-closed-${sid}`, handleSessionClosed); + apiOff(`session-changedb-${sid}`, handleChangedDatabase); }; } return () => {}; @@ -566,6 +569,17 @@ handleSessionDone(); }; + const handleChangedDatabase = async props => { + changeTab(tabid, tab => ({ + ...tab, + props: { + ...tab.props, + conid, + database: props.database, + }, + })); + }; + const { editorState, editorValue, setEditorData } = useEditorData({ tabid, loadFromArgs: @@ -757,12 +771,12 @@ @@ -818,11 +832,11 @@ }, })} > - {queryRowsLimit ? `Limit ${queryRowsLimit} rows` : 'Unlimited rows'} {/if} {#if resultCount == 1} - + {/if} @@ -872,7 +886,7 @@ domResultTabs?.openCurrentChart(); }} > - Open chart {/if} {#if isProApp() && !visibleResultTabs && hasPermission('dbops/charts')} @@ -883,7 +897,7 @@ autoDetectCharts = !autoDetectCharts; }} > - Detect chart getCurrentEditor() != null, onClick: () => getCurrentEditor().copyNodeScript(), }); @@ -49,6 +49,7 @@ import { showSnackbarError } from '../utility/snackbar'; import useEffect from '../utility/useEffect'; import useTimerLabel from '../utility/useTimerLabel'; + import { __t } from '../translations'; export let tabid; diff --git a/packages/web/src/tabs/SqlObjectTab.svelte b/packages/web/src/tabs/SqlObjectTab.svelte index c59009c35..d343d9659 100644 --- a/packages/web/src/tabs/SqlObjectTab.svelte +++ b/packages/web/src/tabs/SqlObjectTab.svelte @@ -3,8 +3,8 @@ registerCommand({ id: 'sqlObject.find', - category: 'SQL Object', - name: 'Find', + category: __t('command.sqlObject', { defaultMessage: 'SQL Object' }), + name: __t('command.sqlObject.find', { defaultMessage: 'Find' }), keyText: 'CtrlOrCommand+F', testEnabled: () => getCurrentEditor() != null, onClick: () => getCurrentEditor().find(), @@ -31,6 +31,7 @@ import ToolStripButton from '../buttons/ToolStripButton.svelte'; import openNewTab from '../utility/openNewTab'; import { getBoolSettingsValue } from '../settings/settingsTools'; + import { __t } from '../translations'; export let tabid; export let appObjectData; diff --git a/packages/web/src/tabs/TableDataTab.svelte b/packages/web/src/tabs/TableDataTab.svelte index 0a943d44e..cac6161b2 100644 --- a/packages/web/src/tabs/TableDataTab.svelte +++ b/packages/web/src/tabs/TableDataTab.svelte @@ -1,12 +1,35 @@ @@ -304,7 +328,7 @@ defaultActionId: 'openStructure', }, }); - }}>Structure{_t('datagrid.structure', { defaultMessage: 'Structure' })} collapsedLeftColumnStore.update(x => !x)}>View columns collapsedLeftColumnStore.update(x => !x)}>{_t('tableData.viewColumns', { defaultMessage: 'View columns' })} diff --git a/packages/web/src/tabs/TableStructureTab.svelte b/packages/web/src/tabs/TableStructureTab.svelte index 1e8ab9efb..c3506002d 100644 --- a/packages/web/src/tabs/TableStructureTab.svelte +++ b/packages/web/src/tabs/TableStructureTab.svelte @@ -6,8 +6,8 @@ registerCommand({ id: 'tableStructure.save', group: 'save', - category: 'Table editor', - name: 'Save', + category: __t('command.tableEditor', { defaultMessage: 'Table editor' }), + name: __t('command.tableEditor.save', { defaultMessage: 'Save' }), toolbar: true, isRelatedToTab: true, icon: 'icon save', @@ -17,8 +17,8 @@ registerCommand({ id: 'tableStructure.reset', - category: 'Table editor', - name: 'Reset changes', + category: __t('command.tableEditor', { defaultMessage: 'Table editor' }), + name: __t('command.tableEditor.reset', { defaultMessage: 'Reset changes' }), toolbar: true, isRelatedToTab: true, icon: 'icon close', @@ -57,6 +57,7 @@ import hasPermission from '../utility/hasPermission'; import { changeTab, markTabSaved, markTabUnsaved } from '../utility/common'; import { getBoolSettingsValue } from '../settings/settingsTools'; + import { _t, __t } from '../translations'; export let tabid; export let conid; @@ -197,7 +198,7 @@ defaultActionId: 'openTable', }, }); - }}>Data{_t('common.data', { defaultMessage: 'Data' })} diff --git a/packages/web/src/translations.ts b/packages/web/src/translations.ts index c6bbb56a4..0a97dac06 100644 --- a/packages/web/src/translations.ts +++ b/packages/web/src/translations.ts @@ -1,4 +1,5 @@ import cs from '../../../translations/cs.json'; +import sk from '../../../translations/sk.json'; import MessageFormat, { MessageFunction } from '@messageformat/core'; import { getStringSettingsValue } from './settings/settingsTools'; @@ -6,6 +7,7 @@ import { getStringSettingsValue } from './settings/settingsTools'; const translations = { en: {}, cs, + sk, }; const supportedLanguages = Object.keys(translations); @@ -13,15 +15,22 @@ const compiledMessages: Partial string { + return () => _t(key, options); +} + +export function _val(x: T | (() => T)): T { + return typeof x === 'function' ? (x as () => T)() : x; +} diff --git a/packages/web/src/utility/clipboard.ts b/packages/web/src/utility/clipboard.ts index 2b1dae989..d30ad8bf6 100644 --- a/packages/web/src/utility/clipboard.ts +++ b/packages/web/src/utility/clipboard.ts @@ -2,6 +2,7 @@ import _ from 'lodash'; import { arrayToHexString, stringifyCellValue } from 'dbgate-tools'; import yaml from 'js-yaml'; import { DataEditorTypesBehaviour } from 'dbgate-types'; +import { __t, _t } from '../translations' export function copyTextToClipboard(text) { const oldFocus = document.activeElement; @@ -157,53 +158,53 @@ export function copyRowsToClipboard(format, columns, rows, options) { export const copyRowsFormatDefs = { textWithHeaders: { - label: 'Copy with headers', - name: 'With headers', + label: __t('clipboard.copyWithHeaders', { defaultMessage : 'Copy with headers' }), + name: __t('clipboard.withHeaders', { defaultMessage: 'With headers' }), formatter: clipboardTextFormatter('\t', true), }, textWithoutHeaders: { - label: 'Copy without headers', - name: 'Without headers', + label: __t('clipboard.copyWithoutHeaders', { defaultMessage : 'Copy without headers' }), + name: __t('clipboard.withoutHeaders', { defaultMessage: 'Without headers' }), formatter: clipboardTextFormatter('\t', false), }, headers: { - label: 'Copy only headers', - name: 'Only Headers', + label: __t('clipboard.copyOnlyHeadres', { defaultMessage : 'Copy only headers'}), + name: __t('clipboard.onlyHeaders', { defaultMessage : 'Only Headers' }), formatter: clipboardHeadersFormatter('\t'), }, csv: { - label: 'Copy as CSV', + label: __t('clipboard.copyCSV', { defaultMessage : 'Copy as CSV'}), name: 'CSV', formatter: clipboardTextFormatter(',', true), }, json: { - label: 'Copy as JSON', + label: __t('clipboard.copyJSON', { defaultMessage: 'Copy as JSON'}), name: 'JSON', formatter: clipboardJsonFormatter(), }, jsonLines: { - label: 'Copy as JSON lines/NDJSON', + label: __t('clipboard.copyJSONLines', { defaultMessage : 'Copy as JSON lines/NDJSON' }), name: 'JSON lines/NDJSON', formatter: clipboardJsonLinesFormatter(), }, yaml: { - label: 'Copy as YAML', + label: __t('clipboard.copyYAML', { defaultMessage : 'Copy as YAML'}), name: 'YAML', formatter: clipboardYamlFormatter(), }, inserts: { - label: 'Copy as SQL INSERTs', - name: 'SQL INSERTs', + label: __t('clipboard.copySQLInsert', { defaultMessage : 'Copy as SQL INSERTs'}), + name: __t('clipboard.SQLInsert', { defaultMessage : 'SQL INSERTs' }), formatter: clipboardInsertsFormatter(), }, updates: { - label: 'Copy as SQL UPDATEs', - name: 'SQL UPDATEs', + label: __t('clipboard.copySQLUpdate', { defaultMessage : 'Copy as SQL UPDATEs'}), + name: __t('clipboard.SQLUpdate', { defaultMessage : 'SQL UPDATEs' }), formatter: clipboardUpdatesFormatter(), }, mongoInsert: { - label: 'Copy as Mongo INSERTs', - name: 'Mongo INSERTs', + label: __t('clipboard.copyMongoInsert', { defaultMessage : 'Copy as Mongo INSERTs' }), + name: __t('clipboard.mongoInsert', { defaultMessage : 'Mongo INSERTs' }), formatter: clipboardMongoInsertFormatter(), }, }; diff --git a/packages/web/src/utility/common.ts b/packages/web/src/utility/common.ts index f37ee4320..477d56670 100644 --- a/packages/web/src/utility/common.ts +++ b/packages/web/src/utility/common.ts @@ -3,6 +3,7 @@ import { currentDatabase, getExtensions, getOpenedTabs, loadingSchemaLists, open import _ from 'lodash'; import { getSchemaList } from './metadataLoaders'; import { showSnackbarError } from './snackbar'; +import { _t } from '../translations'; export class LoadingToken { isCanceled = false; @@ -57,8 +58,14 @@ export function setSelectedTab(tabid) { } export function getObjectTypeFieldLabel(objectTypeField, driver?) { - if (objectTypeField == 'matviews') return 'Materialized Views'; - if (objectTypeField == 'collections') return _.startCase(driver?.collectionPluralLabel) ?? 'Collections/Containers'; + if (objectTypeField == 'tables') return _t('dbObject.tables', { defaultMessage: 'Tables' }); + if (objectTypeField == 'views') return _t('dbObject.views', { defaultMessage: 'Views' }); + if (objectTypeField == 'procedures') return _t('dbObject.procedures', { defaultMessage: 'Procedures' }); + if (objectTypeField == 'functions') return _t('dbObject.functions', { defaultMessage: 'Functions' }); + if (objectTypeField == 'triggers') return _t('dbObject.triggers', { defaultMessage: 'Triggers' }); + if (objectTypeField == 'schedulerEvents') return _t('dbObject.schedulerEvents', { defaultMessage: 'Scheduler Events' }); + if (objectTypeField == 'matviews') return _t('dbObject.matviews', { defaultMessage: 'Materialized Views' }); + if (objectTypeField == 'collections') return _t('dbObject.collections', { defaultMessage: 'Collections/Containers' }); return _.startCase(objectTypeField); } diff --git a/packages/web/src/utility/contextMenu.ts b/packages/web/src/utility/contextMenu.ts index d5da4d202..a5bc2a34f 100644 --- a/packages/web/src/utility/contextMenu.ts +++ b/packages/web/src/utility/contextMenu.ts @@ -4,6 +4,7 @@ import invalidateCommands from '../commands/invalidateCommands'; import { runGroupCommand } from '../commands/runCommand'; import { currentDropDownMenu, visibleCommandPalette } from '../stores'; import getAsArray from './getAsArray'; +import { _val } from '../translations'; let isContextMenuSupressed = false; @@ -112,8 +113,9 @@ function mapItem(item, commands) { if (item.command) { const command = commands[item.command]; if (command) { + const commandText = item.text || command.menuName || command.toolbarName || command.name; return { - text: item.text || command.menuName || command.toolbarName || command.name, + text: _val(commandText), keyText: command.keyText || command.keyTextFromGroup || command.disableHandleKeyText, onClick: () => { if (command.isGroupCommand) { diff --git a/packages/web/src/utility/createQuickExportMenu.ts b/packages/web/src/utility/createQuickExportMenu.ts index 467ec1d74..affec534c 100644 --- a/packages/web/src/utility/createQuickExportMenu.ts +++ b/packages/web/src/utility/createQuickExportMenu.ts @@ -1,12 +1,14 @@ import type { QuickExportDefinition } from 'dbgate-types'; import { currentArchive, getCurrentArchive, getExtensions } from '../stores'; import hasPermission from './hasPermission'; +import { _t } from '../translations' +import { isProApp } from './proTools'; export function createQuickExportMenuItems(handler: (fmt: QuickExportDefinition) => Function, advancedExportMenuItem) { const extensions = getExtensions(); return [ - { - text: 'Export advanced...', + isProApp() && { + text: _t('export.exportAdvanced', { defaultMessage : 'Export advanced...'}), ...advancedExportMenuItem, }, { divider: true }, @@ -15,11 +17,11 @@ export function createQuickExportMenuItems(handler: (fmt: QuickExportDefinition) onClick: handler(fmt), })), { divider: true }, - { - text: 'Current archive', + isProApp() && { + text: _t('export.currentArchive', { defaultMessage : 'Current archive'}), onClick: handler({ extension: 'jsonl', - label: 'Current archive', + label: _t('export.currentArchive', { defaultMessage : 'Current archive'}), noFilenameDependency: true, createWriter: (fileName, dataName) => ({ functionName: 'archiveWriter', diff --git a/packages/web/src/widgets/AdminPremiumPromoWidget.svelte b/packages/web/src/widgets/AdminPremiumPromoWidget.svelte index d3f80daed..ec3c9ea16 100644 --- a/packages/web/src/widgets/AdminPremiumPromoWidget.svelte +++ b/packages/web/src/widgets/AdminPremiumPromoWidget.svelte @@ -1,14 +1,17 @@ - {#if $promoWidget?.state == 'data'} - + {#if promoWidgetData?.state == 'data'} + {/if} diff --git a/packages/web/src/widgets/ConnectionList.svelte b/packages/web/src/widgets/ConnectionList.svelte index 0e9227335..01808473c 100644 --- a/packages/web/src/widgets/ConnectionList.svelte +++ b/packages/web/src/widgets/ConnectionList.svelte @@ -47,6 +47,7 @@ getOpenDetailOnArrowsSettings, } from '../settings/settingsTools'; import DropDownButton from '../buttons/DropDownButton.svelte'; + import { _t } from '../translations'; const connections = useConnectionList(); const serverStatus = useServerStatus(); @@ -58,7 +59,7 @@ let domContainer = null; let domFilter = null; - const RECENT_AND_UNSAVED_LABEL = 'Recent & unsaved'; + const RECENT_AND_UNSAVED_LABEL = _t('connection.recentUnsaved', { defaultMessage: 'Recent & unsaved' }); function extractConnectionParent(data, openedConnections, openedSingleDatabaseConnections) { if (data.parent) { @@ -193,12 +194,12 @@ function createSearchMenu() { const res = []; - res.push({ label: 'Search by:', isBold: true, disabled: true }); - res.push({ label: 'Display name', switchValue: 'displayName' }); - res.push({ label: 'Server', switchValue: 'server' }); - res.push({ label: 'User', switchValue: 'user' }); - res.push({ label: 'Database engine', switchValue: 'engine' }); - res.push({ label: 'Database name', switchValue: 'database' }); + res.push({ label: _t('common.searchBy', { defaultMessage: 'Search by:' }), isBold: true, disabled: true }); + res.push({ label: _t('connection.displayName', { defaultMessage: 'Display name' }), switchValue: 'displayName' }); + res.push({ label: _t('connection.server', { defaultMessage: 'Server' }), switchValue: 'server' }); + res.push({ label: _t('connection.user', { defaultMessage: 'User' }), switchValue: 'user' }); + res.push({ label: _t('connection.engine', { defaultMessage: 'Database engine' }), switchValue: 'engine' }); + res.push({ label: _t('connection.database', { defaultMessage: 'Database name' }), switchValue: 'database' }); return res.map(item => ({ ...item, switchStore: connectionAppObjectSearchSettings, @@ -209,7 +210,7 @@ { @@ -227,16 +228,16 @@ {#if $commandsCustomized['new.connection']?.enabled} runCommand('new.connection')} - title="Add new connection" + title={_t('connection.new.title', { defaultMessage: 'Add new connection' })} data-testid="ConnectionList_buttonNewConnection" > - runCommand('new.connection.folder')} title="Add new connection folder"> + runCommand('new.connection.folder')} title={_t('connection.new.folder.title', { defaultMessage: 'Add new connection folder' })}> {/if} - + diff --git a/packages/web/src/widgets/DatabaseWidgetDetailContent.svelte b/packages/web/src/widgets/DatabaseWidgetDetailContent.svelte index 1c79e46d5..7fe3871a1 100644 --- a/packages/web/src/widgets/DatabaseWidgetDetailContent.svelte +++ b/packages/web/src/widgets/DatabaseWidgetDetailContent.svelte @@ -44,7 +44,7 @@ ({ label: x.schemaName, value: x.schemaName })) ?? []) : [ { - label: _t('schema.all_schemas', { + label: _t('schema.allSchemas', { defaultMessage: 'All schemas ({count})', values: { count: objectList?.length ?? 0 }, }), diff --git a/packages/web/src/widgets/SpecialPageLayout.svelte b/packages/web/src/widgets/SpecialPageLayout.svelte index 71534d19b..e57700961 100644 --- a/packages/web/src/widgets/SpecialPageLayout.svelte +++ b/packages/web/src/widgets/SpecialPageLayout.svelte @@ -3,6 +3,8 @@ import { getConfig } from '../utility/metadataLoaders'; import { handleAuthOnStartup } from '../clientAuth'; import { setConfigForPermissions } from '../utility/hasPermission'; + import { visibleTitleBar } from '../stores'; + import TitleBar from './TitleBar.svelte'; async function loadApi() { try { @@ -21,10 +23,22 @@ loadApi(); }); + + const isDark = + localStorage.getItem('currentThemeType') === 'dark' || + (!localStorage.getItem('currentThemeType') && + window.matchMedia && + window.matchMedia('(prefers-color-scheme: dark)').matches); -
-
DbGate
+
+ {#if $visibleTitleBar} +
+ +
+ {/if} + +
DbGate