diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx index 062519da18..e1511f2824 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/CellRenderer/CellRenderer.tsx @@ -26,7 +26,6 @@ export const CellRenderer: React.FC> = observer(function const selectionContext = useContext(DataGridSelectionContext); const editingContext = useContext(EditingContext); const editor = dataGridContext?.model.source.getEditor(dataGridContext.resultIndex); - const dataGridApi = dataGridContext?.getDataGridApi(); const mouse = useMouse({}); const classes: string[] = []; @@ -45,6 +44,8 @@ export const CellRenderer: React.FC> = observer(function } const handleMouseDown = useCallback((event: React.MouseEvent) => { + const dataGridApi = dataGridContext?.getDataGridApi(); + if (dataGridApi) { dataGridApi.selectCell({ idx: column.idx, rowIdx }); } @@ -58,7 +59,7 @@ export const CellRenderer: React.FC> = observer(function event.shiftKey, true ); - }, [column, rowIdx, selectionContext]); + }, [column, rowIdx, dataGridContext, selectionContext]); const handleMouseUp = useCallback((event: React.MouseEvent) => { if (!dataGridContext?.isGridInFocus()) { diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContext.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContext.ts index 3fdcf359ea..73e81c7f55 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContext.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContext.ts @@ -10,7 +10,7 @@ import { createContext } from 'react'; import type { DataGridHandle } from 'react-data-grid'; import type { IExecutor } from '@cloudbeaver/core-executor'; -import type { IDatabaseDataModel } from '@cloudbeaver/plugin-data-viewer'; +import type { IDatabaseDataModel, IDataTableActions } from '@cloudbeaver/plugin-data-viewer'; export interface IColumnResizeInfo { column: number; @@ -19,6 +19,7 @@ export interface IColumnResizeInfo { export interface IDataGridContext { model: IDatabaseDataModel; + actions: IDataTableActions; resultIndex: number; columnResize: IExecutor; isGridInFocus: () => boolean; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService.ts index 08041291ff..0cec5d8bf5 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService.ts @@ -73,6 +73,7 @@ export class DataGridContextMenuFilterService { context: IMenuContext, value: any | (() => any), icon: string, + isHidden?: (context: IMenuContext) => boolean, ): Array> { const { model, resultIndex, column } = context.data; const data = model.source.getAction(resultIndex, ResultSetDataAction); @@ -88,6 +89,9 @@ export class DataGridContextMenuFilterService { isDisabled(context) { return context.data.model.isLoading(); }, + isHidden(context) { + return isHidden?.(context) ?? false; + }, titleGetter() { const val = typeof value === 'function' ? value() : value; const stringifyValue = format.toDisplayString(val); @@ -115,7 +119,7 @@ export class DataGridContextMenuFilterService { return context.data.model.isDisabled(context.data.resultIndex) || context.data.model.source.results.length > 1; }, - order: 1, + order: 2, title: 'data_grid_table_filter', icon: '/icons/filter.png', isPanel: true, @@ -132,7 +136,7 @@ export class DataGridContextMenuFilterService { const constraints = context.data.model.source.getAction(context.data.resultIndex, ResultSetConstraintAction); return constraints.orderConstraints.length === 0 && constraints.filterConstraints.length === 0; }, - order: 2, + order: 3, title: 'data_grid_table_delete_filters_and_orders', icon: '/icons/erase.png', onClick: async context => { @@ -171,10 +175,19 @@ export class DataGridContextMenuFilterService { return []; } - if (this.clipboardService.state === 'prompt') { - return [{ + const valueGetter = () => this.clipboardService.clipboardValue || ''; + const items = this.getGeneralizedMenuItems( + context, + valueGetter, + '/icons/filter_clipboard.png', + () => this.clipboardService.state === 'prompt' + ); + + return [ + { id: 'permission', isPresent: () => true, + isHidden: () => this.clipboardService.state !== 'prompt', isDisabled(context) { return context.data.model.isLoading(); }, @@ -183,12 +196,9 @@ export class DataGridContextMenuFilterService { onClick: async () => { await this.clipboardService.read(); }, - }]; - } - - const valueGetter = () => this.clipboardService.clipboardValue || ''; - const items = this.getGeneralizedMenuItems(context, valueGetter, '/icons/filter_clipboard.png'); - return items; + }, + ...items, + ]; }, }), } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuOrderService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuOrderService.ts index 48e19e328d..1088282fe6 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuOrderService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuOrderService.ts @@ -45,7 +45,7 @@ export class DataGridContextMenuOrderService { isPresent(context) { return context.contextType === DataGridContextMenuService.cellContext; }, - order: 0, + order: 1, title: 'data_grid_table_order', icon: 'order-arrow-unknown', isPanel: true, diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuService.ts index 4991f94225..c2b19d0b61 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuService.ts @@ -9,10 +9,11 @@ import { injectable } from '@cloudbeaver/core-di'; import { ContextMenuService, IContextMenuItem, IMenuPanel } from '@cloudbeaver/core-dialogs'; import { Executor, IExecutor } from '@cloudbeaver/core-executor'; -import type { IDatabaseDataModel } from '@cloudbeaver/plugin-data-viewer'; +import type { IDatabaseDataModel, IDataTableActions } from '@cloudbeaver/plugin-data-viewer'; export interface IDataGridCellMenuContext { model: IDatabaseDataModel; + actions: IDataTableActions; resultIndex: number; row: number; column: number; @@ -36,6 +37,7 @@ export class DataGridContextMenuService { constructMenuWithContext( model: IDatabaseDataModel, + actions: IDataTableActions, resultIndex: number, row: number, column: number @@ -43,17 +45,18 @@ export class DataGridContextMenuService { return this.contextMenuService.createContextMenu({ menuId: this.getMenuToken(), contextType: DataGridContextMenuService.cellContext, - data: { model, resultIndex, row, column }, + data: { model, actions, resultIndex, row, column }, }, this.getMenuToken()); } openMenu( model: IDatabaseDataModel, + actions: IDataTableActions, resultIndex: number, row: number, column: number ): void { - this.onRootMenuOpen.execute({ model, resultIndex, row, column }); + this.onRootMenuOpen.execute({ model, actions, resultIndex, row, column }); } add(panelId: string, menuItem: IContextMenuItem): void { diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridLoader.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridLoader.tsx index bd96959ac1..8c8fddbdba 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridLoader.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridLoader.tsx @@ -7,29 +7,21 @@ */ import { ComplexLoader, createComplexLoader, Loader } from '@cloudbeaver/core-blocks'; -import type { IDatabaseDataModel } from '@cloudbeaver/plugin-data-viewer'; - -interface Props { - tableModel: IDatabaseDataModel; - resultIndex: number; - className?: string; -} +import type { IDataPresentationProps } from '@cloudbeaver/plugin-data-viewer'; const loader = createComplexLoader(async function loader() { const { DataGridTable } = await import('./DataGridTable'); return { DataGridTable }; }); -export const DataGridLoader: React.FC = function DataGridLoader({ - tableModel, resultIndex, className, -}) { +export const DataGridLoader: React.FC = function DataGridLoader(props) { return ( } > {({ DataGridTable }) => ( - + )} ); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx index e661c70533..53d699e943 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx @@ -14,7 +14,7 @@ import styled from 'reshadow'; import { Executor } from '@cloudbeaver/core-executor'; import { useStyles } from '@cloudbeaver/core-theming'; -import { IDatabaseDataEditorActionsData, IDatabaseDataModel, IDatabaseResultSet, ResultSetSelectAction } from '@cloudbeaver/plugin-data-viewer'; +import { IDatabaseDataEditorActionsData, IDatabaseDataModel, IDatabaseResultSet, IDataPresentationProps, IDataTableActions, ResultSetSelectAction } from '@cloudbeaver/plugin-data-viewer'; import { CellPosition, EditingContext } from '../Editing/EditingContext'; import { useEditing } from '../Editing/useEditing'; @@ -30,18 +30,12 @@ import { useGridDragging } from './useGridDragging'; import { useGridSelectedCellsCopy } from './useGridSelectedCellsCopy'; import { useTableData } from './useTableData'; -interface Props { - model: IDatabaseDataModel; - resultIndex: number; - className?: string; -} - function isAtBottom(event: React.UIEvent): boolean { const target = event.target as HTMLDivElement; return target.clientHeight + target.scrollTop + 100 > target.scrollHeight; } -export const DataGridTable: React.FC = observer(function DataGridTable({ model, resultIndex, className }) { +export const DataGridTable: React.FC> = observer(function DataGridTable({ model, actions, resultIndex, className }) { const gridContainerRef = useRef(null); const dataGridRef = useRef(null); const editorRef = useRef(null); @@ -143,12 +137,13 @@ export const DataGridTable: React.FC = observer(function DataGridTable({ const gridContext = useMemo(() => ({ model, + actions, columnResize, resultIndex, isGridInFocus: () => gridContainerRef.current === document.activeElement, getEditorPortal: () => editorRef.current, getDataGridApi: () => dataGridRef.current, - }), [model, resultIndex, editorRef, dataGridRef]); + }), [model, actions, resultIndex, editorRef, dataGridRef]); return styled(styles)( @@ -157,7 +152,6 @@ export const DataGridTable: React.FC = observer(function DataGridTable({ = observer(function CellFor {(isCellSelected || cellContext?.mouse.state.mouseEnter || menuVisible) && context && ( ; + actions: IDataTableActions; resultIndex: number; row: number; column: number; + onClick?: () => void; onStateSwitch?: (state: boolean) => void; } export const CellMenu: React.FC = observer(function TreeNodeMenu({ model, + actions, resultIndex, row, column, + onClick, onStateSwitch, }) { const dataGridContextMenuService = useService(DataGridContextMenuService); @@ -40,7 +44,7 @@ export const CellMenu: React.FC = observer(function TreeNodeMenu({ const { panel, hidden } = useMemo( () => { - const panel = dataGridContextMenuService.constructMenuWithContext(model, resultIndex, row, column); + const panel = dataGridContextMenuService.constructMenuWithContext(model, actions, resultIndex, row, column); const hidden = computed(() => !panel.menuItems.length || panel.menuItems.every(item => item.isHidden)); @@ -49,6 +53,11 @@ export const CellMenu: React.FC = observer(function TreeNodeMenu({ [column, row] ); + function handleClick() { + dataGridContextMenuService.openMenu(model, actions, resultIndex, row, column); + onClick?.(); + } + if (hidden.get()) { return null; } @@ -59,7 +68,7 @@ export const CellMenu: React.FC = observer(function TreeNodeMenu({ panel={panel} style={[cellMenuStyles]} modal - onClick={() => dataGridContextMenuService.openMenu(model, resultIndex, row, column)} + onClick={handleClick} onVisibleSwitch={onStateSwitch} > diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetBootstrap.ts b/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetBootstrap.ts index 279ad2cda0..e22c682212 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetBootstrap.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetBootstrap.ts @@ -13,6 +13,7 @@ import { DataPresentationService } from '@cloudbeaver/plugin-data-viewer'; import { DataGridContextMenuFilterService } from './DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService'; import { DataGridContextMenuOrderService } from './DataGrid/DataGridContextMenu/DataGridContextMenuOrderService'; +import { DataGridContextMenuService } from './DataGrid/DataGridContextMenu/DataGridContextMenuService'; import { DataGridSettingsService } from './DataGridSettingsService'; import { SpreadsheetGrid } from './SpreadsheetGrid'; @@ -23,6 +24,7 @@ export class SpreadsheetBootstrap extends Bootstrap { private dataGridSettingsService: DataGridSettingsService, private dataGridContextMenuSortingService: DataGridContextMenuOrderService, private dataGridContextMenuFilterService: DataGridContextMenuFilterService, + private dataGridContextMenuService: DataGridContextMenuService, exceptionsCatcherService: ExceptionsCatcherService ) { super(); @@ -40,6 +42,25 @@ export class SpreadsheetBootstrap extends Bootstrap { }); this.dataGridContextMenuSortingService.register(); this.dataGridContextMenuFilterService.register(); + + this.dataGridContextMenuService.add( + this.dataGridContextMenuService.getMenuToken(), + { + id: 'view_value_panel', + isPresent(context) { + return context.contextType === DataGridContextMenuService.cellContext; + }, + isHidden(context) { + return typeof context.data.actions.valuePresentationId === 'string'; + }, + order: 0.5, + title: 'data_grid_table_open_value_panel', + icon: '/icons/text_value_presentation.png', + onClick(context) { + context.data.actions.setValuePresentation(''); + }, + } + ); } load(): void | Promise { } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetGrid.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetGrid.tsx index fb0d5c63ab..7db7d8eeeb 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetGrid.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/SpreadsheetGrid.tsx @@ -10,10 +10,6 @@ import type { IDataPresentationProps } from '@cloudbeaver/plugin-data-viewer'; import { DataGridLoader } from './DataGrid/DataGridLoader'; -export const SpreadsheetGrid: React.FC = function SpreadsheetGrid({ - model, - className, - resultIndex, -}) { - return ; +export const SpreadsheetGrid: React.FC = function SpreadsheetGrid(props) { + return ; }; diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/locales/en.ts b/webapp/packages/plugin-data-spreadsheet-new/src/locales/en.ts index 70c9ea54bf..852be68a18 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/locales/en.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/locales/en.ts @@ -1,5 +1,6 @@ export default [ ['data_grid_table_order', 'Sorting'], + ['data_grid_table_open_value_panel', 'Show in value panel'], ['data_grid_table_filter', 'Filters'], ['data_grid_table_filter_cell_value', 'Cell value'], ['data_grid_table_filter_custom_value', 'Custom'], diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/locales/ru.ts b/webapp/packages/plugin-data-spreadsheet-new/src/locales/ru.ts index a9ab087b63..a5aeb23295 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/locales/ru.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/locales/ru.ts @@ -1,5 +1,6 @@ export default [ ['data_grid_table_order', 'Сортировка'], + ['data_grid_table_open_value_panel', 'Показать в панели значений'], ['data_grid_table_filter', 'Фильтры'], ['data_grid_table_filter_cell_value', 'Значение ячейки'], ['data_grid_table_filter_custom_value', 'Произвольный'], diff --git a/webapp/packages/plugin-data-viewer/src/DataPresentationService.ts b/webapp/packages/plugin-data-viewer/src/DataPresentationService.ts index 7c888c1f50..676eaf9f0a 100644 --- a/webapp/packages/plugin-data-viewer/src/DataPresentationService.ts +++ b/webapp/packages/plugin-data-viewer/src/DataPresentationService.ts @@ -12,6 +12,7 @@ import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; import type { IDatabaseDataModel } from './DatabaseDataModel/IDatabaseDataModel'; import type { IDatabaseDataResult } from './DatabaseDataModel/IDatabaseDataResult'; +import type { IDataTableActions } from './TableViewer/IDataTableActions'; export interface IDataPresentationProps< TOptions = any, @@ -19,6 +20,7 @@ export interface IDataPresentationProps< > { dataFormat: ResultDataFormat; model: IDatabaseDataModel; + actions: IDataTableActions; resultIndex: number; className?: string; } diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/IDataTableActions.ts b/webapp/packages/plugin-data-viewer/src/TableViewer/IDataTableActions.ts new file mode 100644 index 0000000000..5eeb122626 --- /dev/null +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/IDataTableActions.ts @@ -0,0 +1,27 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2021 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 type { ResultDataFormat } from '@cloudbeaver/core-sdk'; + +import type { IDatabaseDataModel } from '../DatabaseDataModel/IDatabaseDataModel'; + +export interface IDataTableActions { + presentationId: string | undefined; + valuePresentationId: string | null | undefined; + dataModel: IDatabaseDataModel | undefined; + + setPresentation: (id: string) => void; + setValuePresentation: (id: string | null) => void; +} + +export interface IDataTableActionsPrivate extends IDataTableActions { + resultIndex: number; + dataFormat: ResultDataFormat; + onPresentationChange: (id: string) => void; + onValuePresentationChange: (id: string | null) => void; +} diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableGrid.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableGrid.tsx index 292af527d3..5a0f147bc1 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableGrid.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableGrid.tsx @@ -15,10 +15,12 @@ import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; import type { IDatabaseDataModel } from '../DatabaseDataModel/IDatabaseDataModel'; import type { IDataPresentationOptions } from '../DataPresentationService'; +import type { IDataTableActions } from './IDataTableActions'; import { TableStatistics } from './TableStatistics'; type TableGridProps = PropsWithChildren<{ model: IDatabaseDataModel; + actions: IDataTableActions; dataFormat: ResultDataFormat; presentation: IDataPresentationOptions; resultIndex: number; @@ -33,6 +35,7 @@ const styles = css` export const TableGrid = observer(function TableGrid({ model, + actions, dataFormat, presentation, resultIndex, @@ -58,6 +61,6 @@ export const TableGrid = observer(function TableGrid({ } return styled(styles)( - + ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableToolsPanel.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableToolsPanel.tsx index 62b073681d..99dfa951bb 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableToolsPanel.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableToolsPanel.tsx @@ -16,9 +16,11 @@ import type { ResultDataFormat } from '@cloudbeaver/core-sdk'; import type { IDatabaseDataModel } from '../DatabaseDataModel/IDatabaseDataModel'; import type { IDataPresentationOptions } from '../DataPresentationService'; +import type { IDataTableActions } from './IDataTableActions'; type TableGridProps = PropsWithChildren<{ model: IDatabaseDataModel; + actions: IDataTableActions; dataFormat: ResultDataFormat; presentation: IDataPresentationOptions | null; resultIndex: number; @@ -33,6 +35,7 @@ const styles = css` export const TableToolsPanel = observer(function TableToolsPanel({ model, + actions, dataFormat, presentation, resultIndex, @@ -57,6 +60,6 @@ export const TableToolsPanel = observer(function TableToolsPanel({ } return styled(styles)( - + ); }); diff --git a/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewer.tsx b/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewer.tsx index 476196342f..0d56f47eb8 100644 --- a/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewer.tsx +++ b/webapp/packages/plugin-data-viewer/src/TableViewer/TableViewer.tsx @@ -6,16 +6,18 @@ * you may not use this file except in compliance with the License. */ +import { observable } from 'mobx'; import { observer } from 'mobx-react-lite'; -import { useCallback, useEffect } from 'react'; +import { useEffect } from 'react'; import styled, { css } from 'reshadow'; -import { Loader, Pane, ResizerControls, Split, splitStyles, TextPlaceholder } from '@cloudbeaver/core-blocks'; +import { Loader, Pane, ResizerControls, Split, splitStyles, TextPlaceholder, useObjectRef } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { ResultDataFormat } from '@cloudbeaver/core-sdk'; import { composes, useStyles } from '@cloudbeaver/core-theming'; import { DataPresentationService, DataPresentationType } from '../DataPresentationService'; +import type { IDataTableActionsPrivate } from './IDataTableActions'; import { TableError } from './TableError'; import { TableFooter } from './TableFooter/TableFooter'; import { TableGrid } from './TableGrid'; @@ -117,30 +119,66 @@ export const TableViewer: React.FC = observer(function TableViewer({ const loading = dataModel?.isLoading() ?? true; const dataFormat = result?.dataFormat || ResultDataFormat.Resultset; - const handlePresentationChange = useCallback((id: string) => { - const presentation = dataPresentationService.get(id); - if (presentation) { - if ( - presentation.dataFormat !== undefined - && presentation.dataFormat !== dataModel?.source.dataFormat - ) { - dataModel?.setDataFormat(presentation.dataFormat) - .reload(); - } - onPresentationChange(id); - } - }, [onPresentationChange, dataModel]); + const dataTableActions = useObjectRef({ + presentationId, + valuePresentationId, + dataModel, + resultIndex, + dataFormat, + onPresentationChange, + onValuePresentationChange, - function handleValuePresentationChange(id: string) { - if (id === valuePresentationId) { - onValuePresentationChange(null); - return; - } - const presentation = dataPresentationService.get(id); - if (presentation) { - onValuePresentationChange(id); - } - } + setPresentation(id: string) { + const presentation = dataPresentationService.get(id); + + if (presentation) { + if ( + presentation.dataFormat !== undefined + && presentation.dataFormat !== this.dataModel?.source.dataFormat + ) { + this.dataModel?.setDataFormat(presentation.dataFormat).reload(); + } + this.onPresentationChange(id); + } + }, + + setValuePresentation(id: string | null) { + if (id === this.valuePresentationId || id === null) { + this.onValuePresentationChange(null); + return; + } + + let presentation = dataPresentationService.get(id); + + if (!presentation && this.dataModel) { + presentation = dataPresentationService.getSupported( + DataPresentationType.toolsPanel, + this.dataFormat, + undefined, + this.dataModel, + this.resultIndex + ) ?? undefined; + } + + if (presentation) { + this.onValuePresentationChange(presentation.id); + } + }, + }, { + presentationId, + valuePresentationId, + dataModel, + resultIndex, + dataFormat, + onPresentationChange, + onValuePresentationChange, + }, { + presentationId: observable, + valuePresentationId: observable, + dataFormat: observable, + resultIndex: observable, + dataModel: observable.ref, + }, ['setPresentation', 'setValuePresentation']); useEffect(() => { if (!presentationId || !dataModel) { @@ -189,9 +227,9 @@ export const TableViewer: React.FC = observer(function TableViewer({ && resultExist; return styled(styles)( - + - + = observer(function TableViewer({ supportedDataFormat={dataModel.supportedDataFormats} model={dataModel} resultIndex={resultIndex} - onPresentationChange={handlePresentationChange} + onPresentationChange={dataTableActions.setPresentation} /> @@ -207,6 +245,7 @@ export const TableViewer: React.FC = observer(function TableViewer({ = observer(function TableViewer({ {resultExist && ( = observer(function TableViewer({ supportedDataFormat={[dataFormat]} model={dataModel} resultIndex={resultIndex} - onPresentationChange={handleValuePresentationChange} + onPresentationChange={dataTableActions.setValuePresentation} /> diff --git a/webapp/packages/plugin-data-viewer/src/index.ts b/webapp/packages/plugin-data-viewer/src/index.ts index 10511895f0..75da1e773b 100644 --- a/webapp/packages/plugin-data-viewer/src/index.ts +++ b/webapp/packages/plugin-data-viewer/src/index.ts @@ -37,6 +37,7 @@ export * from './DatabaseDataModel/Order'; export * from './TableViewer/TableViewerStorageService'; export * from './TableViewer/ValuePanel/DataValuePanelService'; +export * from './TableViewer/IDataTableActions'; export * from './TableViewer/TableViewer'; export * from './TableViewer/TableFooter/TableFooterMenu/TableFooterMenuService'; export * from './TableViewer/DataModelWrapper';