mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
feat: CB-1041 CB-1013 CB-1050 show in value panel button
This commit is contained in:
+3
-2
@@ -26,7 +26,6 @@ export const CellRenderer: React.FC<CellRendererProps<any>> = 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<HTMLDivElement>({});
|
||||
|
||||
const classes: string[] = [];
|
||||
@@ -45,6 +44,8 @@ export const CellRenderer: React.FC<CellRendererProps<any>> = observer(function
|
||||
}
|
||||
|
||||
const handleMouseDown = useCallback((event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||
const dataGridApi = dataGridContext?.getDataGridApi();
|
||||
|
||||
if (dataGridApi) {
|
||||
dataGridApi.selectCell({ idx: column.idx, rowIdx });
|
||||
}
|
||||
@@ -58,7 +59,7 @@ export const CellRenderer: React.FC<CellRendererProps<any>> = observer(function
|
||||
event.shiftKey,
|
||||
true
|
||||
);
|
||||
}, [column, rowIdx, selectionContext]);
|
||||
}, [column, rowIdx, dataGridContext, selectionContext]);
|
||||
|
||||
const handleMouseUp = useCallback((event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||
if (!dataGridContext?.isGridInFocus()) {
|
||||
|
||||
@@ -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<any>;
|
||||
actions: IDataTableActions;
|
||||
resultIndex: number;
|
||||
columnResize: IExecutor<IColumnResizeInfo>;
|
||||
isGridInFocus: () => boolean;
|
||||
|
||||
+20
-10
@@ -73,6 +73,7 @@ export class DataGridContextMenuFilterService {
|
||||
context: IMenuContext<IDataGridCellMenuContext>,
|
||||
value: any | (() => any),
|
||||
icon: string,
|
||||
isHidden?: (context: IMenuContext<IDataGridCellMenuContext>) => boolean,
|
||||
): Array<IContextMenuItem<IDataGridCellMenuContext>> {
|
||||
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,
|
||||
];
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+6
-3
@@ -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<any>;
|
||||
actions: IDataTableActions;
|
||||
resultIndex: number;
|
||||
row: number;
|
||||
column: number;
|
||||
@@ -36,6 +37,7 @@ export class DataGridContextMenuService {
|
||||
|
||||
constructMenuWithContext(
|
||||
model: IDatabaseDataModel<any>,
|
||||
actions: IDataTableActions,
|
||||
resultIndex: number,
|
||||
row: number,
|
||||
column: number
|
||||
@@ -43,17 +45,18 @@ export class DataGridContextMenuService {
|
||||
return this.contextMenuService.createContextMenu<IDataGridCellMenuContext>({
|
||||
menuId: this.getMenuToken(),
|
||||
contextType: DataGridContextMenuService.cellContext,
|
||||
data: { model, resultIndex, row, column },
|
||||
data: { model, actions, resultIndex, row, column },
|
||||
}, this.getMenuToken());
|
||||
}
|
||||
|
||||
openMenu(
|
||||
model: IDatabaseDataModel<any>,
|
||||
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<IDataGridCellMenuContext>): void {
|
||||
|
||||
@@ -7,29 +7,21 @@
|
||||
*/
|
||||
|
||||
import { ComplexLoader, createComplexLoader, Loader } from '@cloudbeaver/core-blocks';
|
||||
import type { IDatabaseDataModel } from '@cloudbeaver/plugin-data-viewer';
|
||||
|
||||
interface Props {
|
||||
tableModel: IDatabaseDataModel<any, any>;
|
||||
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<Props> = function DataGridLoader({
|
||||
tableModel, resultIndex, className,
|
||||
}) {
|
||||
export const DataGridLoader: React.FC<IDataPresentationProps> = function DataGridLoader(props) {
|
||||
return (
|
||||
<ComplexLoader
|
||||
loader={loader}
|
||||
placeholder={<Loader />}
|
||||
>
|
||||
{({ DataGridTable }) => (
|
||||
<DataGridTable model={tableModel} resultIndex={resultIndex} className={className} />
|
||||
<DataGridTable {...props} />
|
||||
)}
|
||||
</ComplexLoader>
|
||||
);
|
||||
|
||||
@@ -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<any, IDatabaseResultSet>;
|
||||
resultIndex: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function isAtBottom(event: React.UIEvent<HTMLDivElement>): boolean {
|
||||
const target = event.target as HTMLDivElement;
|
||||
return target.clientHeight + target.scrollTop + 100 > target.scrollHeight;
|
||||
}
|
||||
|
||||
export const DataGridTable: React.FC<Props> = observer(function DataGridTable({ model, resultIndex, className }) {
|
||||
export const DataGridTable: React.FC<IDataPresentationProps<any, IDatabaseResultSet>> = observer(function DataGridTable({ model, actions, resultIndex, className }) {
|
||||
const gridContainerRef = useRef<HTMLDivElement>(null);
|
||||
const dataGridRef = useRef<DataGridHandle>(null);
|
||||
const editorRef = useRef<HTMLDivElement>(null);
|
||||
@@ -143,12 +137,13 @@ export const DataGridTable: React.FC<Props> = observer(function DataGridTable({
|
||||
|
||||
const gridContext = useMemo<IDataGridContext>(() => ({
|
||||
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)(
|
||||
<DataGridContext.Provider value={gridContext}>
|
||||
@@ -157,7 +152,6 @@ export const DataGridTable: React.FC<Props> = observer(function DataGridTable({
|
||||
<TableDataContext.Provider value={tableData}>
|
||||
<grid-container
|
||||
ref={gridContainerRef}
|
||||
as='div'
|
||||
className="cb-react-grid-container"
|
||||
tabIndex={-1}
|
||||
onKeyDown={onKeydownHandler}
|
||||
|
||||
@@ -72,6 +72,7 @@ export const CellFormatter: React.FC<FormatterProps> = observer(function CellFor
|
||||
{(isCellSelected || cellContext?.mouse.state.mouseEnter || menuVisible) && context && (
|
||||
<CellMenu
|
||||
model={context.model}
|
||||
actions={context.actions}
|
||||
resultIndex={context.resultIndex}
|
||||
row={rowIdx}
|
||||
column={Number(column.key)}
|
||||
|
||||
+12
-3
@@ -15,24 +15,28 @@ import { Icon } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { MenuTrigger } from '@cloudbeaver/core-dialogs';
|
||||
import { useStyles } from '@cloudbeaver/core-theming';
|
||||
import type { IDatabaseDataModel } from '@cloudbeaver/plugin-data-viewer';
|
||||
import type { IDatabaseDataModel, IDataTableActions } from '@cloudbeaver/plugin-data-viewer';
|
||||
|
||||
import { DataGridContextMenuService } from '../../DataGridContextMenu/DataGridContextMenuService';
|
||||
import { cellMenuStyles } from './cellMenuStyles';
|
||||
|
||||
interface Props {
|
||||
model: IDatabaseDataModel<any>;
|
||||
actions: IDataTableActions;
|
||||
resultIndex: number;
|
||||
row: number;
|
||||
column: number;
|
||||
onClick?: () => void;
|
||||
onStateSwitch?: (state: boolean) => void;
|
||||
}
|
||||
|
||||
export const CellMenu: React.FC<Props> = observer(function TreeNodeMenu({
|
||||
model,
|
||||
actions,
|
||||
resultIndex,
|
||||
row,
|
||||
column,
|
||||
onClick,
|
||||
onStateSwitch,
|
||||
}) {
|
||||
const dataGridContextMenuService = useService(DataGridContextMenuService);
|
||||
@@ -40,7 +44,7 @@ export const CellMenu: React.FC<Props> = 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<Props> = 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<Props> = observer(function TreeNodeMenu({
|
||||
panel={panel}
|
||||
style={[cellMenuStyles]}
|
||||
modal
|
||||
onClick={() => dataGridContextMenuService.openMenu(model, resultIndex, row, column)}
|
||||
onClick={handleClick}
|
||||
onVisibleSwitch={onStateSwitch}
|
||||
>
|
||||
<Icon name="snack" viewBox="0 0 16 10" />
|
||||
|
||||
@@ -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<void> { }
|
||||
|
||||
@@ -10,10 +10,6 @@ import type { IDataPresentationProps } from '@cloudbeaver/plugin-data-viewer';
|
||||
|
||||
import { DataGridLoader } from './DataGrid/DataGridLoader';
|
||||
|
||||
export const SpreadsheetGrid: React.FC<IDataPresentationProps> = function SpreadsheetGrid({
|
||||
model,
|
||||
className,
|
||||
resultIndex,
|
||||
}) {
|
||||
return <DataGridLoader tableModel={model} resultIndex={resultIndex} className={className} />;
|
||||
export const SpreadsheetGrid: React.FC<IDataPresentationProps> = function SpreadsheetGrid(props) {
|
||||
return <DataGridLoader {...props} />;
|
||||
};
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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', 'Произвольный'],
|
||||
|
||||
@@ -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<TOptions, TResult>;
|
||||
actions: IDataTableActions;
|
||||
resultIndex: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@@ -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<any, any> | 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;
|
||||
}
|
||||
@@ -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<any>;
|
||||
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)(
|
||||
<Presentation dataFormat={dataFormat} model={model} resultIndex={resultIndex} />
|
||||
<Presentation dataFormat={dataFormat} model={model} actions={actions} resultIndex={resultIndex} />
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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<any, any>;
|
||||
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)(
|
||||
<Presentation dataFormat={dataFormat} model={model} resultIndex={resultIndex} />
|
||||
<Presentation dataFormat={dataFormat} model={model} actions={actions} resultIndex={resultIndex} />
|
||||
);
|
||||
});
|
||||
|
||||
@@ -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<Props> = 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<IDataTableActionsPrivate>({
|
||||
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<Props> = observer(function TableViewer({
|
||||
&& resultExist;
|
||||
|
||||
return styled(styles)(
|
||||
<table-viewer as="div" className={className}>
|
||||
<table-viewer className={className}>
|
||||
<TableHeader model={dataModel} resultIndex={resultIndex} />
|
||||
<table-content as='div'>
|
||||
<table-content>
|
||||
<TablePresentationBar
|
||||
type={DataPresentationType.main}
|
||||
presentationId={presentation.id}
|
||||
@@ -199,7 +237,7 @@ export const TableViewer: React.FC<Props> = observer(function TableViewer({
|
||||
supportedDataFormat={dataModel.supportedDataFormats}
|
||||
model={dataModel}
|
||||
resultIndex={resultIndex}
|
||||
onPresentationChange={handlePresentationChange}
|
||||
onPresentationChange={dataTableActions.setPresentation}
|
||||
/>
|
||||
<table-data>
|
||||
<Split sticky={30} mode={valuePanelDisplayed ? undefined : 'minimize'} keepRatio>
|
||||
@@ -207,6 +245,7 @@ export const TableViewer: React.FC<Props> = observer(function TableViewer({
|
||||
<pane-content>
|
||||
<TableGrid
|
||||
model={dataModel}
|
||||
actions={dataTableActions}
|
||||
dataFormat={dataFormat}
|
||||
presentation={presentation}
|
||||
resultIndex={resultIndex}
|
||||
@@ -219,6 +258,7 @@ export const TableViewer: React.FC<Props> = observer(function TableViewer({
|
||||
{resultExist && (
|
||||
<TableToolsPanel
|
||||
model={dataModel}
|
||||
actions={dataTableActions}
|
||||
dataFormat={dataFormat}
|
||||
presentation={valuePresentation}
|
||||
resultIndex={resultIndex}
|
||||
@@ -242,7 +282,7 @@ export const TableViewer: React.FC<Props> = observer(function TableViewer({
|
||||
supportedDataFormat={[dataFormat]}
|
||||
model={dataModel}
|
||||
resultIndex={resultIndex}
|
||||
onPresentationChange={handleValuePresentationChange}
|
||||
onPresentationChange={dataTableActions.setValuePresentation}
|
||||
/>
|
||||
</table-content>
|
||||
<TableFooter model={dataModel} resultIndex={resultIndex} />
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user