diff --git a/.github/workflows/build-app-pro-beta.yaml b/.github/workflows/build-app-pro-beta.yaml index 7b2681c28..90ac92766 100644 --- a/.github/workflows/build-app-pro-beta.yaml +++ b/.github/workflows/build-app-pro-beta.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 8a4dc2732a7097b5c4c48b4feb62609111cdf3e0 + ref: 36b6ce878c3c0a0c9623163c8a8b3bdeefc7da53 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-app-pro.yaml b/.github/workflows/build-app-pro.yaml index e16d302d5..7bb5e6c0a 100644 --- a/.github/workflows/build-app-pro.yaml +++ b/.github/workflows/build-app-pro.yaml @@ -39,7 +39,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 8a4dc2732a7097b5c4c48b4feb62609111cdf3e0 + ref: 36b6ce878c3c0a0c9623163c8a8b3bdeefc7da53 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/build-cloud-pro.yaml b/.github/workflows/build-cloud-pro.yaml index bc0b1efd1..8b8540fcf 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: 8a4dc2732a7097b5c4c48b4feb62609111cdf3e0 + ref: 36b6ce878c3c0a0c9623163c8a8b3bdeefc7da53 - 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 cf7c7644d..b076fc8ba 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: 8a4dc2732a7097b5c4c48b4feb62609111cdf3e0 + ref: 36b6ce878c3c0a0c9623163c8a8b3bdeefc7da53 - 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 ed15abe54..6b0b4c02d 100644 --- a/.github/workflows/build-npm-pro.yaml +++ b/.github/workflows/build-npm-pro.yaml @@ -32,7 +32,7 @@ jobs: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 8a4dc2732a7097b5c4c48b4feb62609111cdf3e0 + ref: 36b6ce878c3c0a0c9623163c8a8b3bdeefc7da53 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/.github/workflows/e2e-pro.yaml b/.github/workflows/e2e-pro.yaml index 10a81362f..ae057bcf6 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: 8a4dc2732a7097b5c4c48b4feb62609111cdf3e0 + ref: 36b6ce878c3c0a0c9623163c8a8b3bdeefc7da53 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4b1a6cb..d1c2f15d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ Builds: - linux - application for linux - win - application for Windows +## 6.6.0 +- ADDED: Database chat - AI powered chatbot, which knows your database (Premium) +- ADDED: Firestore support (Premium) +- REMOVED: Query AI assistant (replaced by Database Chat) (Premium) +- FIXED: Chart permissions were ignored (Premium) + ## 6.5.6 - ADDED: New object window - quick access to most common functions - ADDED: Possibility to disable split query by empty line #1162 diff --git a/README.md b/README.md index 2752c9d1c..bd7f381d8 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ DbGate is licensed under GPL-3.0 license and is free to use for any purpose. * libSQL/Turso (Premium) * DuckDB * Firebird +* Firestore (Premium) @@ -81,6 +82,7 @@ DbGate is licensed under GPL-3.0 license and is free to use for any purpose. * Archives - backup your data in NDJSON files on local filesystem (or on DbGate server, when using web application) * NDJSON data viewer and editor - browse NDJSON data, edit data and structure directly on NDJSON files. Works also for big NDSON files * Charts, export chart to HTML page +* AI powered database chat * Show GEO data on map, export map to HTML page * For detailed info, how to run DbGate in docker container, visit [docker hub](https://hub.docker.com/r/dbgate/dbgate) * Extensible plugin architecture diff --git a/e2e-tests/cypress/e2e/browse-data.cy.js b/e2e-tests/cypress/e2e/browse-data.cy.js index 8f9914b7a..409ff66d2 100644 --- a/e2e-tests/cypress/e2e/browse-data.cy.js +++ b/e2e-tests/cypress/e2e/browse-data.cy.js @@ -390,7 +390,7 @@ describe('Data browser data', () => { cy.get('body').realType('find most popular artist'); cy.get('body').realPress('{enter}'); cy.testid('DatabaseChatTab_executeAllQueries', { timeout: 20000 }).click(); - cy.wait(4000); + cy.wait(20000); // cy.contains('Iron Maiden'); cy.themeshot('database-chat'); diff --git a/package.json b/package.json index 3e510521a..489a49e4d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "6.5.7-beta.4", + "version": "6.6.0", "name": "dbgate-all", "workspaces": [ "packages/*", diff --git a/packages/api/src/storageModel.js b/packages/api/src/storageModel.js index 9cb9fa942..4086a5b43 100644 --- a/packages/api/src/storageModel.js +++ b/packages/api/src/storageModel.js @@ -674,6 +674,12 @@ module.exports = { "columnName": "awsRegion", "dataType": "varchar(250)", "notNull": false + }, + { + "pureName": "connections", + "columnName": "connectionDefinition", + "dataType": "text", + "notNull": false } ], "foreignKeys": [], diff --git a/packages/api/src/utility/crypting.js b/packages/api/src/utility/crypting.js index 4ff5df522..822d74c1b 100644 --- a/packages/api/src/utility/crypting.js +++ b/packages/api/src/utility/crypting.js @@ -101,24 +101,26 @@ function decryptObjectPasswordField(obj, field, encryptor = null) { return obj; } +const fieldsToEncrypt = ['password', 'sshPassword', 'sshKeyfilePassword', 'connectionDefinition']; + function encryptConnection(connection, encryptor = null) { if (connection.passwordMode != 'saveRaw') { - connection = encryptObjectPasswordField(connection, 'password', encryptor); - connection = encryptObjectPasswordField(connection, 'sshPassword', encryptor); - connection = encryptObjectPasswordField(connection, 'sshKeyfilePassword', encryptor); + for (const field of fieldsToEncrypt) { + connection = encryptObjectPasswordField(connection, field, encryptor); + } } return connection; } function maskConnection(connection) { if (!connection) return connection; - return _.omit(connection, ['password', 'sshPassword', 'sshKeyfilePassword']); + return _.omit(connection, fieldsToEncrypt); } -function decryptConnection(connection, encryptor = null) { - connection = decryptObjectPasswordField(connection, 'password', encryptor); - connection = decryptObjectPasswordField(connection, 'sshPassword', encryptor); - connection = decryptObjectPasswordField(connection, 'sshKeyfilePassword', encryptor); +function decryptConnection(connection) { + for (const field of fieldsToEncrypt) { + connection = decryptObjectPasswordField(connection, field); + } return connection; } @@ -188,9 +190,9 @@ function recryptObjectPasswordFieldInPlace(obj, field, decryptEncryptor, encrypt } function recryptConnection(connection, decryptEncryptor, encryptEncryptor) { - connection = recryptObjectPasswordField(connection, 'password', decryptEncryptor, encryptEncryptor); - connection = recryptObjectPasswordField(connection, 'sshPassword', decryptEncryptor, encryptEncryptor); - connection = recryptObjectPasswordField(connection, 'sshKeyfilePassword', decryptEncryptor, encryptEncryptor); + for (const field of fieldsToEncrypt) { + connection = recryptObjectPasswordField(connection, field, decryptEncryptor, encryptEncryptor); + } return connection; } diff --git a/packages/types/engines.d.ts b/packages/types/engines.d.ts index c74010947..12fba070f 100644 --- a/packages/types/engines.d.ts +++ b/packages/types/engines.d.ts @@ -241,7 +241,7 @@ export interface EngineDriver extends FilterBehaviourProvider { defaultSocketPath?: string; authTypeLabel?: string; importExportArgs?: any[]; - connect({ server, port, user, password, database, certificateJson }): Promise>; + connect({ server, port, user, password, database, connectionDefinition }): Promise>; close(dbhan: DatabaseHandle): Promise; query(dbhan: DatabaseHandle, sql: string, options?: QueryOptions): Promise; stream(dbhan: DatabaseHandle, sql: string, options: StreamOptions); diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index 6233e5734..e307d6970 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -511,7 +511,8 @@ await dbgateApi.executeQuery(${JSON.stringify( text: _t('database.exportDbModel', { defaultMessage: 'Export DB model' }), }, isProApp() && - driver?.databaseEngineTypes?.includes('sql') && { + driver?.databaseEngineTypes?.includes('sql') && + hasPermission('dbops/chat') && { onClick: handleDatabaseChat, text: _t('database.databaseChat', { defaultMessage: 'Database chat' }), }, diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index e37bd9b1a..c61029a7d 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -723,7 +723,8 @@ if (isProApp()) { icon: 'icon ai', testEnabled: () => getCurrentDatabase() != null && - findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql'), + findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql') && + hasPermission('dbops/chat'), onClick: () => { openNewTab({ title: 'Chat', diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index d2f772e4a..9e898a46c 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -424,6 +424,7 @@ import { _t } from '../translations'; import { isProApp } from '../utility/proTools'; import SaveArchiveModal from '../modals/SaveArchiveModal.svelte'; + import hasPermission from '../utility/hasPermission'; export let onLoadNextData = undefined; export let grider = undefined; @@ -1848,6 +1849,7 @@ // }, isProApp() && { command: 'dataGrid.sendToDataDeploy' }, isProApp() && + hasPermission('dbops/charts') && onOpenChart && { text: 'Open chart', onClick: () => onOpenChart(), diff --git a/packages/web/src/forms/FormFileInputField.svelte b/packages/web/src/forms/FormFileInputField.svelte new file mode 100644 index 000000000..be7205d3e --- /dev/null +++ b/packages/web/src/forms/FormFileInputField.svelte @@ -0,0 +1,58 @@ + + + + + diff --git a/packages/web/src/settings/ConnectionDriverFields.svelte b/packages/web/src/settings/ConnectionDriverFields.svelte index 0e578d650..8830861d3 100644 --- a/packages/web/src/settings/ConnectionDriverFields.svelte +++ b/packages/web/src/settings/ConnectionDriverFields.svelte @@ -18,9 +18,7 @@ import FormDropDownTextField from '../forms/FormDropDownTextField.svelte'; import { getConnectionLabel } from 'dbgate-tools'; import { _t } from '../translations'; - import FilesInput from '../impexp/FilesInput.svelte'; - import SimpleFilesInput from '../impexp/SimpleFilesInput.svelte'; - import FormJsonFileInputField from '../forms/FormJsonFileInputField.svelte'; + import FormFileInputField from '../forms/FormFileInputField.svelte'; export let getDatabaseList; export let currentConnection; @@ -465,8 +463,8 @@ /> {/if} -{#if driver?.showConnectionField('certificateJson', $values, showConnectionFieldArgs)} - +{#if driver?.showConnectionField('connectionDefinition', $values, showConnectionFieldArgs)} + {/if} {#if driver} diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index a2102fa72..41fc77599 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -154,6 +154,7 @@ import RowsLimitModal from '../modals/RowsLimitModal.svelte'; import _ from 'lodash'; import FontIcon from '../icons/FontIcon.svelte'; + import hasPermission from '../utility/hasPermission'; export let tabid; export let conid; @@ -794,7 +795,7 @@ hideDisabled /> - {#if isProApp() && visibleResultTabs && !busy} + {#if isProApp() && visibleResultTabs && !busy && hasPermission('dbops/charts')} {/if} - {#if isProApp() && !visibleResultTabs} + {#if isProApp() && !visibleResultTabs && hasPermission('dbops/charts')} | FileParseResultError} FileParseResult - */ - -/** - * @template [T = any] - * @param {File} file - * @returns {Promise>} - */ export async function parseFileAsJson(file) { try { const text = await file.text(); diff --git a/packages/web/src/utility/parseFileAsString.js b/packages/web/src/utility/parseFileAsString.js new file mode 100644 index 000000000..f34676746 --- /dev/null +++ b/packages/web/src/utility/parseFileAsString.js @@ -0,0 +1,15 @@ +export async function parseFileAsString(file) { + try { + const text = await file.text(); + const data = text; + return { + success: true, + data, + }; + } catch (error) { + return { + success: false, + error: error instanceof Error ? error.message : 'Unknown parsing error', + }; + } +} diff --git a/packages/web/src/widgets/AdminPremiumPromoWidget.svelte b/packages/web/src/widgets/AdminPremiumPromoWidget.svelte index 6d8ef125d..7145fb45e 100644 --- a/packages/web/src/widgets/AdminPremiumPromoWidget.svelte +++ b/packages/web/src/widgets/AdminPremiumPromoWidget.svelte @@ -11,6 +11,7 @@
  • Query designer
  • +
  • AI powered database chat
  • Unlimited DbGate Cloud storage
  • Shared cloud folders
  • Charts from query result
  • @@ -19,8 +20,7 @@
  • Backup & restore database
  • Advanced ER diagram settings
  • Export database model
  • -
  • AI assistant
  • -
  • libSQL, Turso, CosmosDB, Redshift support
  • +
  • Firestore, libSQL, Turso, CosmosDB, Redshift support
  • Amazon and Azure identity providers
  • E-mail support
diff --git a/workflow-templates/includes.tpl.yaml b/workflow-templates/includes.tpl.yaml index 23ec8c1f8..076c0138d 100644 --- a/workflow-templates/includes.tpl.yaml +++ b/workflow-templates/includes.tpl.yaml @@ -7,7 +7,7 @@ checkout-and-merge-pro: repository: dbgate/dbgate-pro token: ${{ secrets.GH_TOKEN }} path: dbgate-pro - ref: 8a4dc2732a7097b5c4c48b4feb62609111cdf3e0 + ref: 36b6ce878c3c0a0c9623163c8a8b3bdeefc7da53 - name: Merge dbgate/dbgate-pro run: | mkdir ../dbgate-pro