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 89bab8c097..caa9dd9a3b 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 @@ -41,6 +41,10 @@ export const CellRenderer: React.FC> = observer(function }, [column, rowIdx, selectionContext]); const handleDoubleClick = useCallback(() => { + if (!column.editable) { + return; + } + editingContext?.edit({ idx: column.idx, rowIdx }); }, [column, rowIdx]); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/useGridSelectionContext.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/useGridSelectionContext.tsx index 744f35e20b..cb01271f67 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/useGridSelectionContext.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridSelection/useGridSelectionContext.tsx @@ -9,7 +9,7 @@ import { action, observable } from 'mobx'; import { useCallback, useMemo, useState } from 'react'; -import type { ITableData } from '../useTableData'; +import type { ITableData } from '../TableDataContext'; import type { IDataGridSelectionContext } from './DataGridSelectionContext'; export interface IPosition { 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 64d195a282..9fc1c88411 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridTable.tsx @@ -28,6 +28,7 @@ import { DataGridSortingContext } from './DataGridSorting/DataGridSortingContext import { useGridSortingContext } from './DataGridSorting/useGridSortingContext'; import { CellFormatter } from './Formatters/CellFormatter'; import { RowRenderer } from './RowRenderer/RowRenderer'; +import { TableDataContext } from './TableDataContext'; import { useGridDragging } from './useGridDragging'; import { useGridSelectedCellsCopy } from './useGridSelectedCellsCopy'; import { useTableData } from './useTableData'; @@ -56,6 +57,7 @@ export const DataGridTable: React.FC = observer(function DataGridTable({ const gridSortingContext = useGridSortingContext(model); const gridSelectionContext = useGridSelectionContext(tableData); const editingContext = useEditing({ + readonly: model.isReadonly(), onEdit: (position, key) => { const editor = model.source.getEditor(resultIndex); @@ -149,33 +151,35 @@ export const DataGridTable: React.FC = observer(function DataGridTable({ - - columnResize.execute({ column: idx, width })} - onScroll={handleScroll} - /> -
- + + + columnResize.execute({ column: idx, width })} + onScroll={handleScroll} + /> +
+ + diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableColumnHeader.tsx b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableColumnHeader.tsx index 4f8131426c..dd61cca673 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableColumnHeader.tsx +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableColumnHeader/TableColumnHeader.tsx @@ -98,7 +98,7 @@ export const TableColumnHeader: React.FC> = observer(fu const loading = model.isLoading(); // TODO we want to get "sortable" property from SqlResultColumn data - const sortable = true; + const sortable = model.source.results.length === 1; const currentSortMode = gridSortingContext.getSortMode(columnName); const handleSort = (e: React.MouseEvent) => { diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableDataContext.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableDataContext.ts new file mode 100644 index 0000000000..1d59a826ec --- /dev/null +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/TableDataContext.ts @@ -0,0 +1,25 @@ +/* + * 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 { createContext } from 'react'; +import type { Column } from 'react-data-grid'; + +import type { SqlResultColumn } from '@cloudbeaver/core-sdk'; + +export interface ITableData { + columns: Array>; + rows: any[][]; + getColumnInfo: (key: string | number) => SqlResultColumn | undefined; + getColumnsInRange: (startIndex: number, endIndex: number) => Array>; + getColumnIndexFromKey: (columnKey: string | number) => number; + isIndexColumn: (columnKey: string) => boolean; + isIndexColumnInRange: (columnsRange: Array>) => boolean; + getColumnKeyFromColumnIndex: (columnIndex: number) => string; +} + +export const TableDataContext = createContext(null); diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useTableData.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useTableData.ts index b2b4cd33b7..5df20402b3 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useTableData.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/useTableData.ts @@ -11,6 +11,7 @@ import { useState } from 'react'; import type { Column } from 'react-data-grid'; import { useObjectRef } from '@cloudbeaver/core-blocks'; +import type { SqlResultColumn } from '@cloudbeaver/core-sdk'; import { TextTools } from '@cloudbeaver/core-utils'; import type { IDatabaseResultSet } from '@cloudbeaver/plugin-data-viewer'; @@ -18,6 +19,7 @@ import { ResultSetTools } from '../ResultSetTools'; import { IndexFormatter } from './Formatters/IndexFormatter'; import { TableColumnHeader } from './TableColumnHeader/TableColumnHeader'; import { TableIndexColumnHeader } from './TableColumnHeader/TableIndexColumnHeader'; +import type { ITableData } from './TableDataContext'; export const indexColumn: Column = { key: Number.MAX_SAFE_INTEGER + '', @@ -30,16 +32,6 @@ export const indexColumn: Column = { formatter: IndexFormatter, }; -export interface ITableData { - columns: Array>; - rows: any[][]; - getColumnsInRange: (startIndex: number, endIndex: number) => Array>; - getColumnIndexFromKey: (columnKey: string | number) => number; - isIndexColumn: (columnKey: string) => boolean; - isIndexColumnInRange: (columnsRange: Array>) => boolean; - getColumnKeyFromColumnIndex: (columnIndex: number) => string; -} - export function useTableData(modelResultData: IDatabaseResultSet | null): ITableData { const props = useObjectRef({ modelResultData }, undefined, true); const [state] = useState(() => computed(() => { @@ -68,6 +60,7 @@ export function useTableData(modelResultData: IDatabaseResultSet | null): ITable const columns = props.modelResultData.data?.columns!.map>((col, columnIndex) => ({ key: columnIndex + '', name: col.label!, + editable: !col.readOnly, width: Math.min(300, measuredCells[columnIndex]), headerRenderer: TableColumnHeader, })) || []; @@ -81,17 +74,20 @@ export function useTableData(modelResultData: IDatabaseResultSet | null): ITable return useObjectRef({ columns, rows, + getColumnInfo(key: string | number): SqlResultColumn | undefined { + return props.modelResultData?.data?.columns?.[Number(key)]; + }, getColumnIndexFromKey(key: string | number) { - return columns.findIndex((column: any) => column.key === String(key)); + return this.columns.findIndex((column: any) => column.key === String(key)); }, getColumnsInRange(startIndex: number, endIndex: number) { if (startIndex === endIndex) { - return [columns[startIndex]]; + return [this.columns[startIndex]]; } const firstIndex = Math.min(startIndex, endIndex); const lastIndex = Math.max(startIndex, endIndex); - return columns.slice(firstIndex, lastIndex + 1); + return this.columns.slice(firstIndex, lastIndex + 1); }, isIndexColumn(columnKey: string) { return columnKey === indexColumn.key; @@ -100,7 +96,10 @@ export function useTableData(modelResultData: IDatabaseResultSet | null): ITable return columnsRange.some(column => this.isIndexColumn(column.key)); }, getColumnKeyFromColumnIndex(columnIndex: number) { - return columns[columnIndex].key; + return this.columns[columnIndex].key; }, - }); + }, { + columns, + rows, + }, true); } diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/Editing/useEditing.ts b/webapp/packages/plugin-data-spreadsheet-new/src/Editing/useEditing.ts index 0fdf7c3219..0c7231bfe5 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/Editing/useEditing.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/Editing/useEditing.ts @@ -19,6 +19,7 @@ function findPosition(position: Position): (position: Position) => boolean { } interface IEditingOptions { + readonly?: boolean; onEdit: (position: Position, key?: string) => boolean; } @@ -28,6 +29,9 @@ export function useEditing(options: IEditingOptions): IEditingContext { const [context] = useState({ edit(position: Position, key?: string) { + if (optionsRef.readonly) { + return; + } // TODO: not works yet switch (key) { case 'Escape': diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataModel.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataModel.ts index 7aaa766f9c..f54a214107 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataModel.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataModel.ts @@ -43,6 +43,10 @@ implements IDatabaseDataModel { return this.source.isLoading(); } + isReadonly(): boolean { + return this.source.isReadonly(); + } + isDataAvailable(offset: number, count: number): boolean { return this.source.offset <= offset && this.source.count >= count; } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataSource.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataSource.ts index 9a4a753a5f..d07a822b14 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataSource.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/DatabaseDataSource.ts @@ -100,6 +100,10 @@ implements IDatabaseDataSource { return this; } + isReadonly(): boolean { + return this.access === DatabaseDataAccessMode.Readonly || this.results.length > 1; + } + isLoading(): boolean { return !!this.activeRequest || !!this.activeSave; } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataModel.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataModel.ts index 6d38f725d8..9c0c1c5c6b 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataModel.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataModel.ts @@ -18,6 +18,7 @@ export interface IDatabaseDataModel boolean; isLoading: () => boolean; isDataAvailable: (offset: number, count: number) => boolean; diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataSource.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataSource.ts index 0ff0b0d3b0..d7849d0e84 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataSource.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataSource.ts @@ -36,6 +36,7 @@ export interface IDatabaseDataSource boolean; isLoading: () => boolean; hasResult: (resultIndex: number) => boolean;