diff --git a/webapp/packages/core-sdk/package.json b/webapp/packages/core-sdk/package.json index a2e8b435b8..529d724252 100644 --- a/webapp/packages/core-sdk/package.json +++ b/webapp/packages/core-sdk/package.json @@ -25,6 +25,7 @@ "@cloudbeaver/core-executor": "^0", "@cloudbeaver/core-utils": "^0", "axios": "^1", + "graphql": "^16", "graphql-request": "^6", "mobx": "^6" }, diff --git a/webapp/packages/plugin-data-export/src/DATA_EXPORT_SETTINGS_GROUP.ts b/webapp/packages/plugin-data-export/src/DATA_EXPORT_SETTINGS_GROUP.ts deleted file mode 100644 index 991978c9df..0000000000 --- a/webapp/packages/plugin-data-export/src/DATA_EXPORT_SETTINGS_GROUP.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { ROOT_SETTINGS_GROUP } from '@cloudbeaver/core-settings'; - -export const DATA_EXPORT_SETTINGS_GROUP = ROOT_SETTINGS_GROUP.createSubGroup('plugin_data_export_data_export_settings_group'); diff --git a/webapp/packages/plugin-data-export/src/DataExportMenuService.ts b/webapp/packages/plugin-data-export/src/DataExportMenuService.ts index a488fb5c6e..f42885a63b 100644 --- a/webapp/packages/plugin-data-export/src/DataExportMenuService.ts +++ b/webapp/packages/plugin-data-export/src/DataExportMenuService.ts @@ -11,7 +11,6 @@ import { injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { LocalizationService } from '@cloudbeaver/core-localization'; import { DATA_CONTEXT_NAV_NODE, EObjectFeature } from '@cloudbeaver/core-navigation-tree'; -import { EAdminPermission, SessionPermissionsResource } from '@cloudbeaver/core-root'; import { withTimestamp } from '@cloudbeaver/core-utils'; import { ACTION_EXPORT, ActionService, menuExtractItems, MenuService } from '@cloudbeaver/core-view'; import { @@ -20,24 +19,22 @@ import { DATA_CONTEXT_DV_PRESENTATION, DATA_VIEWER_DATA_MODEL_ACTIONS_MENU, DataViewerPresentationType, + DataViewerService, IDatabaseDataSource, IDataContainerOptions, } from '@cloudbeaver/plugin-data-viewer'; import type { IDataQueryOptions } from '@cloudbeaver/plugin-sql-editor'; -import { DataExportSettingsService } from './DataExportSettingsService'; - const DataExportDialog = importLazyComponent(() => import('./Dialog/DataExportDialog').then(module => module.DataExportDialog)); @injectable() export class DataExportMenuService { constructor( private readonly commonDialogService: CommonDialogService, - private readonly dataExportSettingsService: DataExportSettingsService, private readonly actionService: ActionService, private readonly menuService: MenuService, - private readonly sessionPermissionsResource: SessionPermissionsResource, private readonly localizationService: LocalizationService, + private readonly dataViewerService: DataViewerService, ) {} register(): void { @@ -46,7 +43,7 @@ export class DataExportMenuService { contexts: [DATA_CONTEXT_DV_DDM, DATA_CONTEXT_DV_DDM_RESULT_INDEX], isApplicable: context => { const presentation = context.get(DATA_CONTEXT_DV_PRESENTATION); - return !this.isExportDisabled() && (!presentation || presentation.type === DataViewerPresentationType.Data); + return this.dataViewerService.canExportData && (!presentation || presentation.type === DataViewerPresentationType.Data); }, getItems(context, items) { return [...items, ACTION_EXPORT]; @@ -60,6 +57,7 @@ export class DataExportMenuService { id: 'data-export-base-handler', menus: [DATA_VIEWER_DATA_MODEL_ACTIONS_MENU], contexts: [DATA_CONTEXT_DV_DDM, DATA_CONTEXT_DV_DDM_RESULT_INDEX], + isHidden: (context, action) => !this.dataViewerService.canExportData, actions: [ACTION_EXPORT], isDisabled(context) { const model = context.get(DATA_CONTEXT_DV_DDM)!; @@ -118,7 +116,7 @@ export class DataExportMenuService { return false; } - return !this.isExportDisabled() && context.has(DATA_CONTEXT_CONNECTION); + return this.dataViewerService.canExportData && context.has(DATA_CONTEXT_CONNECTION); }, getItems: (context, items) => [...items, ACTION_EXPORT], }); @@ -141,12 +139,4 @@ export class DataExportMenuService { }, }); } - - private isExportDisabled() { - if (this.sessionPermissionsResource.has(EAdminPermission.admin)) { - return false; - } - - return this.dataExportSettingsService.disabled; - } } diff --git a/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts b/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts deleted file mode 100644 index b8bbf3fcfb..0000000000 --- a/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import '@testing-library/jest-dom'; - -import { coreAdministrationManifest } from '@cloudbeaver/core-administration'; -import { coreAppManifest } from '@cloudbeaver/core-app'; -import { coreAuthenticationManifest } from '@cloudbeaver/core-authentication'; -import { mockAuthentication } from '@cloudbeaver/core-authentication/dist/__custom_mocks__/mockAuthentication'; -import { coreBrowserManifest } from '@cloudbeaver/core-browser'; -import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity'; -import { coreConnectionsManifest } from '@cloudbeaver/core-connections'; -import { coreDialogsManifest } from '@cloudbeaver/core-dialogs'; -import { coreEventsManifest } from '@cloudbeaver/core-events'; -import { coreLocalizationManifest } from '@cloudbeaver/core-localization'; -import { coreNavigationTree } from '@cloudbeaver/core-navigation-tree'; -import { coreProjectsManifest } from '@cloudbeaver/core-projects'; -import { coreRootManifest, ServerConfigResource } from '@cloudbeaver/core-root'; -import { createGQLEndpoint } from '@cloudbeaver/core-root/dist/__custom_mocks__/createGQLEndpoint'; -import '@cloudbeaver/core-root/dist/__custom_mocks__/expectWebsocketClosedMessage'; -import { mockAppInit } from '@cloudbeaver/core-root/dist/__custom_mocks__/mockAppInit'; -import { mockGraphQL } from '@cloudbeaver/core-root/dist/__custom_mocks__/mockGraphQL'; -import { mockServerConfig } from '@cloudbeaver/core-root/dist/__custom_mocks__/resolvers/mockServerConfig'; -import { coreRoutingManifest } from '@cloudbeaver/core-routing'; -import { coreSDKManifest } from '@cloudbeaver/core-sdk'; -import { coreSettingsManifest } from '@cloudbeaver/core-settings'; -import { - expectDeprecatedSettingMessage, - expectNoDeprecatedSettingMessage, -} from '@cloudbeaver/core-settings/dist/__custom_mocks__/expectDeprecatedSettingMessage'; -import { coreStorageManifest } from '@cloudbeaver/core-storage'; -import { coreUIManifest } from '@cloudbeaver/core-ui'; -import { coreViewManifest } from '@cloudbeaver/core-view'; -import { datasourceContextSwitchPluginManifest } from '@cloudbeaver/plugin-datasource-context-switch'; -import { navigationTabsPlugin } from '@cloudbeaver/plugin-navigation-tabs'; -import { navigationTreePlugin } from '@cloudbeaver/plugin-navigation-tree'; -import { objectViewerManifest } from '@cloudbeaver/plugin-object-viewer'; -import { createApp } from '@cloudbeaver/tests-runner'; - -import { DataExportSettingsService } from './DataExportSettingsService'; -import { dataExportManifest } from './manifest'; - -const endpoint = createGQLEndpoint(); -const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint)); -const app = createApp( - dataExportManifest, - coreLocalizationManifest, - coreEventsManifest, - coreRootManifest, - coreSDKManifest, - coreBrowserManifest, - coreSettingsManifest, - coreStorageManifest, - coreViewManifest, - coreAuthenticationManifest, - coreProjectsManifest, - coreUIManifest, - coreRoutingManifest, - coreAdministrationManifest, - coreConnectionsManifest, - coreDialogsManifest, - coreNavigationTree, - coreAppManifest, - datasourceContextSwitchPluginManifest, - navigationTreePlugin, - navigationTabsPlugin, - objectViewerManifest, - coreClientActivityManifest, -); - -const testValueA = true; -const testValueB = true; - -const deprecatedSettings = { - 'plugin_data_export.disabled': testValueB, -}; - -const newSettings = { - ...deprecatedSettings, - 'plugin.data-export.disabled': testValueA, -}; - -test('New settings override deprecated', async () => { - const settings = app.injector.getServiceByClass(DataExportSettingsService); - const config = app.injector.getServiceByClass(ServerConfigResource); - - server.use(endpoint.query('serverConfig', mockServerConfig(newSettings))); - - await config.refresh(); - - expect(settings.disabled).toBe(testValueA); - expectNoDeprecatedSettingMessage(); -}); - -test('Deprecated settings are used if new settings are not defined', async () => { - const settings = app.injector.getServiceByClass(DataExportSettingsService); - const config = app.injector.getServiceByClass(ServerConfigResource); - - server.use(endpoint.query('serverConfig', mockServerConfig(deprecatedSettings))); - - await config.refresh(); - - expect(settings.disabled).toBe(testValueB); - expectDeprecatedSettingMessage(); -}); diff --git a/webapp/packages/plugin-data-export/src/DataExportSettingsService.ts b/webapp/packages/plugin-data-export/src/DataExportSettingsService.ts deleted file mode 100644 index 5210503545..0000000000 --- a/webapp/packages/plugin-data-export/src/DataExportSettingsService.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2024 DBeaver Corp and others - * - * Licensed under the Apache License, Version 2.0. - * you may not use this file except in compliance with the License. - */ -import { Dependency, injectable } from '@cloudbeaver/core-di'; -import { - createSettingsAliasResolver, - ROOT_SETTINGS_LAYER, - SettingsManagerService, - SettingsProvider, - SettingsProviderService, - SettingsResolverService, -} from '@cloudbeaver/core-settings'; -import { schema, schemaExtra } from '@cloudbeaver/core-utils'; - -const defaultSettings = schema.object({ - 'plugin.data-export.disabled': schemaExtra.stringedBoolean().default(false), -}); - -export type DataExportSettings = schema.infer; - -@injectable() -export class DataExportSettingsService extends Dependency { - get disabled(): boolean { - return this.settings.getValue('plugin.data-export.disabled'); - } - readonly settings: SettingsProvider; - - constructor( - private readonly settingsProviderService: SettingsProviderService, - private readonly settingsManagerService: SettingsManagerService, - private readonly settingsResolverService: SettingsResolverService, - ) { - super(); - this.settings = this.settingsProviderService.createSettings(defaultSettings); - this.settingsResolverService.addResolver( - ROOT_SETTINGS_LAYER, - /** @deprecated Use settings instead, will be removed in 23.0.0 */ - createSettingsAliasResolver(this.settingsResolverService, this.settings, { 'plugin.data-export.disabled': 'plugin_data_export.disabled' }), - ); - - this.registerSettings(); - } - - private registerSettings() { - this.settingsManagerService.registerSettings(this.settings, () => [ - // { - // group: DATA_EXPORT_SETTINGS_GROUP, - // key: 'disabled', - // type: ESettingsValueType.Checkbox, - // name: 'Disable data export', - // }, - ]); - } -} diff --git a/webapp/packages/plugin-data-export/src/manifest.ts b/webapp/packages/plugin-data-export/src/manifest.ts index 2c58f37f4f..c2a8e77884 100644 --- a/webapp/packages/plugin-data-export/src/manifest.ts +++ b/webapp/packages/plugin-data-export/src/manifest.ts @@ -15,7 +15,6 @@ export const dataExportManifest: PluginManifest = { providers: [ () => import('./Bootstrap').then(m => m.Bootstrap), () => import('./DataExportMenuService').then(m => m.DataExportMenuService), - () => import('./DataExportSettingsService').then(m => m.DataExportSettingsService), () => import('./DataExportService').then(m => m.DataExportService), () => import('./DataExportProcessService').then(m => m.DataExportProcessService), () => import('./DataTransferProcessorsResource').then(m => m.DataTransferProcessorsResource), diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService.ts index f0296277a1..70b61d8a7b 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService.ts @@ -8,7 +8,13 @@ import { selectFiles } from '@cloudbeaver/core-browser'; import { injectable } from '@cloudbeaver/core-di'; import { NotificationService } from '@cloudbeaver/core-events'; -import { createResultSetBlobValue, ResultSetDataContentAction, ResultSetEditAction, ResultSetFormatAction } from '@cloudbeaver/plugin-data-viewer'; +import { + createResultSetBlobValue, + DataViewerService, + ResultSetDataContentAction, + ResultSetEditAction, + ResultSetFormatAction, +} from '@cloudbeaver/plugin-data-viewer'; import { DataGridContextMenuService } from './DataGridContextMenuService'; @@ -17,6 +23,7 @@ export class DataGridContextMenuSaveContentService { constructor( private readonly dataGridContextMenuService: DataGridContextMenuService, private readonly notificationService: NotificationService, + private readonly dataViewerService: DataViewerService, ) {} register(): void { @@ -38,7 +45,8 @@ export class DataGridContextMenuSaveContentService { }, isHidden: context => { const content = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataContentAction); - return !content.isDownloadable(context.data.key); + + return !content.isDownloadable(context.data.key) || !this.dataViewerService.canExportData; }, isDisabled: context => { const content = context.data.model.source.getAction(context.data.resultIndex, ResultSetDataContentAction); diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerService.ts index 0a93eeb119..03f96962e3 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerService.ts @@ -17,6 +17,10 @@ export class DataViewerService { return this.sessionPermissionsResource.has(EAdminPermission.admin) || !this.dataViewerSettingsService.disableCopyData; } + get canExportData() { + return this.sessionPermissionsResource.has(EAdminPermission.admin) || !this.dataViewerSettingsService.disableExportData; + } + constructor( private readonly dataViewerSettingsService: DataViewerSettingsService, private readonly sessionPermissionsResource: SessionPermissionsResource, diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts index e93a0de0cc..6cefb37dd4 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts @@ -77,11 +77,14 @@ const testValueNew = false; const deprecatedSettings = { 'core.app.dataViewer.disableEdit': testValueDeprecated, + 'plugin.data-viewer.disabled': testValueDeprecated, + 'plugin_data_export.disabled': testValueDeprecated, }; const newSettings = { ...deprecatedSettings, 'plugin.data-viewer.disableEdit': testValueNew, + 'plugin.data-viewer.export.disabled': testValueNew, }; async function setupSettingsService(mockConfig: any = {}) { @@ -99,6 +102,8 @@ test('New settings override deprecated settings', async () => { const settingsService = await setupSettingsService(newSettings); expect(settingsService.disableEdit).toBe(testValueNew); + expect(settingsService.disableExportData).toBe(testValueNew); + expectNoDeprecatedSettingMessage(); }); @@ -106,6 +111,8 @@ test('Deprecated settings are used if new settings are not defined', async () => const settingsService = await setupSettingsService(deprecatedSettings); expect(settingsService.disableEdit).toBe(testValueDeprecated); + expect(settingsService.disableExportData).toBe(testValueDeprecated); + expectDeprecatedSettingMessage(); }); diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.ts index 89881ba7e6..ecd33d456a 100644 --- a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.ts @@ -31,6 +31,7 @@ const defaultSettings = schema.object({ 'plugin.data-viewer.fetchMin': schema.coerce.number().min(FETCH_MIN).default(DEFAULT_FETCH_SIZE), 'plugin.data-viewer.fetchMax': schema.coerce.number().min(FETCH_MIN).default(FETCH_MAX), 'resultset.maxrows': schema.coerce.number().min(FETCH_MIN).max(FETCH_MAX).default(DEFAULT_FETCH_SIZE), + 'plugin.data-viewer.export.disabled': schemaExtra.stringedBoolean().default(false), }); export type DataViewerSettings = schema.infer; @@ -45,6 +46,10 @@ export class DataViewerSettingsService extends Dependency { return this.settings.getValue('plugin.data-viewer.disableCopyData'); } + get disableExportData(): boolean { + return this.settings.getValue('plugin.data-viewer.export.disabled'); + } + get maxFetchSize(): number { return this.settings.getValue('plugin.data-viewer.fetchMax'); } @@ -75,12 +80,17 @@ export class DataViewerSettingsService extends Dependency { 'plugin.data-viewer.disableCopyData': 'core.app.dataViewer.disableCopyData', 'plugin.data-viewer.fetchMin': 'core.app.dataViewer.fetchMin', 'plugin.data-viewer.fetchMax': 'core.app.dataViewer.fetchMax', + 'plugin.data-viewer.export.disabled': 'plugin.data-export.disabled', 'resultset.maxrows': 'core.app.dataViewer.fetchDefault', }), /** @deprecated Use settings instead, will be removed in 25.0.0 */ createSettingsAliasResolver(this.settingsResolverService, this.settings, { 'resultset.maxrows': 'plugin.data-viewer.fetchDefault', }), + /** @deprecated Use settings instead, will be removed in 23.0.0 */ + createSettingsAliasResolver(this.settingsResolverService, this.settings, { + 'plugin.data-viewer.export.disabled': 'plugin_data_export.disabled', + }), ); this.registerSettings(); @@ -147,6 +157,16 @@ export class DataViewerSettingsService extends Dependency { description: 'settings_data_editor_fetch_max_description', group: DATA_EDITOR_SETTINGS_GROUP, }, + { + group: DATA_EDITOR_SETTINGS_GROUP, + key: 'plugin.data-viewer.export.disabled', + type: ESettingsValueType.Checkbox, + name: 'settings_data_editor_disable_data_export_name', + description: 'settings_data_editor_disable_data_export_description', + access: { + scope: ['server'], + }, + }, ]; if (!this.serverSettingsManagerService.providedSettings.has('resultset.maxrows')) { diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentation.tsx b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentation.tsx index e32b393f31..4e89471c42 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentation.tsx +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/ImageValuePresentation.tsx @@ -57,11 +57,23 @@ export const ImageValuePresentation: TabContainerPanelComponent) { + if (!data.canSave) { + event.preventDefault(); + } + } + return ( - {data.src && } + {data.src && ( + + )} {isTruncatedMessageDisplay && ( {isDownloadable && ( @@ -99,14 +111,15 @@ export const ImageValuePresentation: TabContainerPanelComponent string | null; + onContextMenu?: (event: React.MouseEvent) => void; } -export const ImageRenderer = observer(function ImageRenderer({ srcGetter, className }) { +export const ImageRenderer = observer(function ImageRenderer({ srcGetter, className, onContextMenu }) { const src = srcGetter(); if (!src) { return null; } - return ; + return ; }); diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/useValuePanelImageValue.ts b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/useValuePanelImageValue.ts index 2beb0c44ce..1990675532 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/useValuePanelImageValue.ts +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/ImageValue/useValuePanelImageValue.ts @@ -24,6 +24,7 @@ import { ResultSetFormatAction } from '../../DatabaseDataModel/Actions/ResultSet import { ResultSetSelectAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction'; import type { IDatabaseDataModel } from '../../DatabaseDataModel/IDatabaseDataModel'; import type { IDatabaseResultSet } from '../../DatabaseDataModel/IDatabaseResultSet'; +import { DataViewerService } from '../../DataViewerService'; interface Props { model: IDatabaseDataModel; @@ -32,6 +33,7 @@ interface Props { export function useValuePanelImageValue({ model, resultIndex }: Props) { const notificationService = useService(NotificationService); + const dataViewerService = useService(DataViewerService); const selectAction = model.source.getAction(resultIndex, ResultSetSelectAction); const formatAction = model.source.getAction(resultIndex, ResultSetFormatAction); const contentAction = model.source.getAction(resultIndex, ResultSetDataContentAction); @@ -88,6 +90,10 @@ export function useValuePanelImageValue({ model, resultIndex }: Props) { return this.contentAction.retrieveBlobFromCache(this.selectedCell); }, get canSave() { + if (!this.dataViewerService.canExportData) { + return false; + } + if (this.truncated && this.selectedCell) { return this.contentAction.isDownloadable(this.selectedCell); } @@ -158,6 +164,6 @@ export function useValuePanelImageValue({ model, resultIndex }: Props) { upload: action.bound, loadFullImage: action.bound, }, - { model, resultIndex, notificationService, selectAction, formatAction, contentAction, editAction }, + { model, resultIndex, notificationService, selectAction, formatAction, contentAction, editAction, dataViewerService }, ); } diff --git a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx index 8ee7861d22..7cbe46a391 100644 --- a/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx +++ b/webapp/packages/plugin-data-viewer/src/ValuePanelPresentation/TextValue/TextValuePresentation.tsx @@ -18,6 +18,7 @@ import { ResultSetEditAction } from '../../DatabaseDataModel/Actions/ResultSet/R import { ResultSetFormatAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction'; import { ResultSetSelectAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction'; import type { IDatabaseResultSet } from '../../DatabaseDataModel/IDatabaseResultSet'; +import { DataViewerService } from '../../DataViewerService'; import type { IDataValuePanelProps } from '../../TableViewer/ValuePanel/DataValuePanelService'; import { getDefaultLineWrapping } from './getDefaultLineWrapping'; import { isTextValueReadonly } from './isTextValueReadonly'; @@ -36,6 +37,7 @@ export const TextValuePresentation: TabContainerPanelComponent