diff --git a/packages/web/src/appobj/ArchiveFolderAppObject.svelte b/packages/web/src/appobj/ArchiveFolderAppObject.svelte index 8ffa9bec2..ca463e54e 100644 --- a/packages/web/src/appobj/ArchiveFolderAppObject.svelte +++ b/packages/web/src/appobj/ArchiveFolderAppObject.svelte @@ -17,6 +17,7 @@ import InputTextModal from '../modals/InputTextModal.svelte'; import ErrorMessageModal from '../modals/ErrorMessageModal.svelte'; import { apiCall } from '../utility/api'; + import hasPermission from '../utility/hasPermission'; export let data; @@ -140,6 +141,7 @@ await dbgateApi.deployDb(${JSON.stringify( ], data.name != 'default' && + hasPermission('dbops/model/compare') && _.get($currentDatabase, 'connection._id') && { onClick: handleCompareWithCurrentDb, text: `Compare with ${_.get($currentDatabase, 'name')}`, diff --git a/packages/web/src/appobj/ConnectionAppObject.svelte b/packages/web/src/appobj/ConnectionAppObject.svelte index 76521f594..8c3020e5b 100644 --- a/packages/web/src/appobj/ConnectionAppObject.svelte +++ b/packages/web/src/appobj/ConnectionAppObject.svelte @@ -106,6 +106,7 @@ import AboutModal from '../modals/AboutModal.svelte'; import { tick } from 'svelte'; import { getConnectionLabel } from 'dbgate-tools'; + import hasPermission from '../utility/hasPermission'; export let data; export let passProps; @@ -220,26 +221,27 @@ }; return [ - config.runAsPortal == false && [ - { - text: $openedConnections.includes(data._id) ? 'View details' : 'Edit', - onClick: handleOpenConnectionTab, - }, - !$openedConnections.includes(data._id) && { - text: 'Delete', - onClick: handleDelete, - }, - { - text: 'Duplicate', - onClick: handleDuplicate, - }, - ], + config.runAsPortal == false && + !config.storageDatabase && [ + { + text: $openedConnections.includes(data._id) ? 'View details' : 'Edit', + onClick: handleOpenConnectionTab, + }, + !$openedConnections.includes(data._id) && { + text: 'Delete', + onClick: handleDelete, + }, + { + text: 'Duplicate', + onClick: handleDuplicate, + }, + ], !data.singleDatabase && [ !$openedConnections.includes(data._id) && { text: 'Connect', onClick: handleConnect, }, - { onClick: handleNewQuery, text: 'New query', isNewQuery: true }, + hasPermission(`dbops/query`) && { onClick: handleNewQuery, text: 'New query', isNewQuery: true }, $openedConnections.includes(data._id) && data.status && { text: 'Refresh', @@ -249,7 +251,8 @@ text: 'Disconnect', onClick: handleDisconnect, }, - $openedConnections.includes(data._id) && + hasPermission(`dbops/createdb`) && + $openedConnections.includes(data._id) && driver?.supportedCreateDatabase && !data.isReadOnly && { text: 'Create database', diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index ddf2c66d5..4673664f9 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -280,20 +280,27 @@ driver?.databaseEngineTypes?.includes('sql') || driver?.databaseEngineTypes?.includes('document'); return [ - { onClick: handleNewQuery, text: 'New query', isNewQuery: true }, - driver?.databaseEngineTypes?.includes('sql') && { onClick: handleNewTable, text: 'New table' }, - driver?.databaseEngineTypes?.includes('document') && { - onClick: handleNewCollection, - text: `New ${driver?.collectionSingularLabel ?? 'collection/container'}`, - }, - driver?.databaseEngineTypes?.includes('sql') && { onClick: handleQueryDesigner, text: 'Design query' }, + hasPermission(`dbops/query`) && { onClick: handleNewQuery, text: 'New query', isNewQuery: true }, + hasPermission(`dbops/model/edit`) && + !connection.isReadOnly && + driver?.databaseEngineTypes?.includes('sql') && { onClick: handleNewTable, text: 'New table' }, + !connection.isReadOnly && + hasPermission(`dbops/model/edit`) && + driver?.databaseEngineTypes?.includes('document') && { + onClick: handleNewCollection, + text: `New ${driver?.collectionSingularLabel ?? 'collection/container'}`, + }, + hasPermission(`dbops/query`) && + driver?.databaseEngineTypes?.includes('sql') && { onClick: handleQueryDesigner, text: 'Design query' }, driver?.databaseEngineTypes?.includes('sql') && { onClick: handleNewPerspective, text: 'Design perspective query', }, { divider: true }, - isSqlOrDoc && !connection.isReadOnly && { onClick: handleImport, text: 'Import wizard' }, - isSqlOrDoc && { onClick: handleExport, text: 'Export wizard' }, + isSqlOrDoc && + !connection.isReadOnly && + hasPermission(`dbops/import`) && { onClick: handleImport, text: 'Import wizard' }, + isSqlOrDoc && hasPermission(`dbops/export`) && { onClick: handleExport, text: 'Export wizard' }, driver?.databaseEngineTypes?.includes('sql') && hasPermission(`dbops/sql-dump/import`) && !connection.isReadOnly && { onClick: handleSqlRestore, text: 'Restore/import SQL dump' }, @@ -301,7 +308,9 @@ hasPermission(`dbops/sql-dump/export`) && { onClick: handleSqlDump, text: 'Backup/export SQL dump' }, isSqlOrDoc && !connection.isReadOnly && - !connection.singleDatabase && { onClick: handleDropDatabase, text: 'Drop database' }, + !connection.singleDatabase && + isSqlOrDoc && + hasPermission(`dbops/dropdb`) && { onClick: handleDropDatabase, text: 'Drop database' }, { divider: true }, driver?.databaseEngineTypes?.includes('sql') && { onClick: handleCopyName, text: 'Copy database name' }, driver?.databaseEngineTypes?.includes('sql') && { onClick: handleShowDiagram, text: 'Show diagram' }, @@ -309,10 +318,14 @@ hasPermission(`dbops/sql-generator`) && { onClick: handleSqlGenerator, text: 'SQL Generator' }, driver?.supportsDatabaseProfiler && hasPermission(`dbops/profiler`) && { onClick: handleDatabaseProfiler, text: 'Database profiler' }, - isSqlOrDoc && { onClick: handleOpenJsonModel, text: 'Open model as JSON' }, - isSqlOrDoc && { onClick: handleExportModel, text: 'Export DB model - experimental' }, + isSqlOrDoc && + isSqlOrDoc && + hasPermission(`dbops/model/view`) && { onClick: handleOpenJsonModel, text: 'Open model as JSON' }, + isSqlOrDoc && + hasPermission(`dbops/model/view`) && { onClick: handleExportModel, text: 'Export DB model - experimental' }, isSqlOrDoc && _.get($currentDatabase, 'connection._id') && + hasPermission('dbops/model/compare') && (_.get($currentDatabase, 'connection._id') != _.get(connection, '_id') || (_.get($currentDatabase, 'connection._id') == _.get(connection, '_id') && _.get($currentDatabase, 'name') != _.get(connection, 'name'))) && { diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index f228acaf3..92529e8fd 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -98,12 +98,12 @@ isDrop: true, requiresWriteAccess: true, }, - { + hasPermission('dbops/table/rename') && { label: 'Rename table', isRename: true, requiresWriteAccess: true, }, - { + hasPermission('dbops/table/truncate') && { label: 'Truncate table', isTruncate: true, requiresWriteAccess: true, @@ -113,29 +113,29 @@ isCopyTableName: true, requiresWriteAccess: false, }, - { + hasPermission('dbops/table/backup') && { label: 'Create table backup', isDuplicateTable: true, requiresWriteAccess: true, }, - { + hasPermission('dbops/model/view') && { label: 'Show diagram', isDiagram: true, }, { divider: true, }, - { + hasPermission('dbops/export') && { label: 'Export', functionName: 'tableReader', isExport: true, }, - { + hasPermission('dbops/import') && { label: 'Import', isImport: true, requiresWriteAccess: true, }, - { + hasPermission('dbops/charts') && { label: 'Open active chart', isActiveChart: true, }, diff --git a/packages/web/src/buttons/ToolStripExportButton.svelte b/packages/web/src/buttons/ToolStripExportButton.svelte index 4e6311e52..6d800f757 100644 --- a/packages/web/src/buttons/ToolStripExportButton.svelte +++ b/packages/web/src/buttons/ToolStripExportButton.svelte @@ -20,6 +20,7 @@ -{#if quickExportHandlerRef} - -{:else} - +{#if hasPermission('dbops/export')} + {#if quickExportHandlerRef} + + {:else} + + {/if} {/if} diff --git a/packages/web/src/datagrid/CollectionDataGridCore.svelte b/packages/web/src/datagrid/CollectionDataGridCore.svelte index a7b256fcb..b8fbf7e75 100644 --- a/packages/web/src/datagrid/CollectionDataGridCore.svelte +++ b/packages/web/src/datagrid/CollectionDataGridCore.svelte @@ -246,10 +246,15 @@ registerQuickExportHandler(quickExportHandler); - registerMenu({ command: 'collectionDataGrid.openQuery', tag: 'export' }, () => ({ - ...createQuickExportMenu(quickExportHandler, { command: 'collectionDataGrid.export' }), - tag: 'export', - })); + registerMenu({ command: 'collectionDataGrid.openQuery', tag: 'export' }, () => + createQuickExportMenu( + quickExportHandler, + { + command: 'collectionDataGrid.export', + }, + { tag: 'export' } + ) + ); function handleSetLoadedRows(rows) { loadedRows = rows; diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index eeb0f8e5c..c4330a497 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -430,6 +430,7 @@ import { openJsonLinesData } from '../utility/openJsonLinesData'; import contextMenuActivator from '../utility/contextMenuActivator'; import InputTextModal from '../modals/InputTextModal.svelte'; + import hasPermission from '../utility/hasPermission'; export let onLoadNextData = undefined; export let grider = undefined; diff --git a/packages/web/src/datagrid/JslDataGridCore.svelte b/packages/web/src/datagrid/JslDataGridCore.svelte index c25164e6b..18d0cfb33 100644 --- a/packages/web/src/datagrid/JslDataGridCore.svelte +++ b/packages/web/src/datagrid/JslDataGridCore.svelte @@ -186,10 +186,15 @@ }; registerQuickExportHandler(quickExportHandler); - registerMenu(() => ({ - ...createQuickExportMenu(quickExportHandler, { command: 'jslTableGrid.export' }), - tag: 'export', - })); + registerMenu(() => + createQuickExportMenu( + quickExportHandler, + { + command: 'jslTableGrid.export', + }, + { tag: 'export' } + ) + ); function handleSetLoadedRows(rows) { loadedRows = rows; diff --git a/packages/web/src/datagrid/SqlDataGridCore.svelte b/packages/web/src/datagrid/SqlDataGridCore.svelte index 7b8357e3c..df8157d86 100644 --- a/packages/web/src/datagrid/SqlDataGridCore.svelte +++ b/packages/web/src/datagrid/SqlDataGridCore.svelte @@ -5,7 +5,7 @@ id: 'sqlDataGrid.openActiveChart', category: 'Data grid', name: 'Open active chart', - testEnabled: () => getCurrentEditor() != null, + testEnabled: () => getCurrentEditor() != null && hasPermission('dbops/charts'), onClick: () => getCurrentEditor().openActiveChart(), }); @@ -13,7 +13,7 @@ id: 'sqlDataGrid.openQuery', category: 'Data grid', name: 'Open query', - testEnabled: () => getCurrentEditor() != null, + testEnabled: () => getCurrentEditor() != null && hasPermission('dbops/query'), onClick: () => getCurrentEditor().openQuery(), }); @@ -23,7 +23,7 @@ name: 'Export', icon: 'icon export', keyText: 'CtrlOrCommand+E', - testEnabled: () => getCurrentEditor() != null, + testEnabled: () => getCurrentEditor() != null && hasPermission('dbops/export'), onClick: () => getCurrentEditor().exportGrid(), }); @@ -83,6 +83,7 @@ import ChangeSetGrider from './ChangeSetGrider'; import LoadingDataGridCore from './LoadingDataGridCore.svelte'; + import hasPermission from '../utility/hasPermission'; export let conid; export let display; @@ -209,10 +210,14 @@ registerMenu( { command: 'sqlDataGrid.openActiveChart', tag: 'chart' }, { command: 'sqlDataGrid.openQuery', tag: 'export' }, - () => ({ - ...createQuickExportMenu(quickExportHandler, { command: 'sqlDataGrid.export' }), - tag: 'export', - }) + () => + createQuickExportMenu( + quickExportHandler, + { + command: 'sqlDataGrid.export', + }, + { tag: 'export' } + ) ); function handleSetLoadedRows(rows) { diff --git a/packages/web/src/tabs/TableStructureTab.svelte b/packages/web/src/tabs/TableStructureTab.svelte index 8f77b7fc8..6c39a3b2f 100644 --- a/packages/web/src/tabs/TableStructureTab.svelte +++ b/packages/web/src/tabs/TableStructureTab.svelte @@ -61,6 +61,7 @@ import ToolStripContainer from '../buttons/ToolStripContainer.svelte'; import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte'; import ToolStripButton from '../buttons/ToolStripButton.svelte'; + import hasPermission from '../utility/hasPermission'; export let tabid; export let conid; @@ -171,7 +172,7 @@ tableInfo={showTable} dbInfo={$dbInfo} {driver} - setTableInfo={objectTypeField == 'tables' && !$connection?.isReadOnly + setTableInfo={objectTypeField == 'tables' && !$connection?.isReadOnly && hasPermission(`dbops/model/edit`) ? tableInfoUpdater => setEditorData(tbl => tbl diff --git a/packages/web/src/utility/createQuickExportMenu.ts b/packages/web/src/utility/createQuickExportMenu.ts index 69fa70788..10c575257 100644 --- a/packages/web/src/utility/createQuickExportMenu.ts +++ b/packages/web/src/utility/createQuickExportMenu.ts @@ -1,5 +1,6 @@ import type { QuickExportDefinition } from 'dbgate-types'; import { currentArchive, getCurrentArchive, getExtensions } from '../stores'; +import hasPermission from './hasPermission'; export function createQuickExportMenuItems(handler: (fmt: QuickExportDefinition) => Function, advancedExportMenuItem) { const extensions = getExtensions(); @@ -34,10 +35,16 @@ export function createQuickExportMenuItems(handler: (fmt: QuickExportDefinition) export default function createQuickExportMenu( handler: (fmt: QuickExportDefinition) => Function, - advancedExportMenuItem + advancedExportMenuItem, + additionalFields = {} ) { + if (!hasPermission('dbops/export')) { + return null; + } + return { text: 'Export', submenu: createQuickExportMenuItems(handler, advancedExportMenuItem), + ...advancedExportMenuItem, }; }