diff --git a/webapp/packages/ag-grid-plugin/src/AgGridTable/AgGridTableController.ts b/webapp/packages/ag-grid-plugin/src/AgGridTable/AgGridTableController.ts index 25a0491534..a7ee9dd47d 100644 --- a/webapp/packages/ag-grid-plugin/src/AgGridTable/AgGridTableController.ts +++ b/webapp/packages/ag-grid-plugin/src/AgGridTable/AgGridTableController.ts @@ -248,6 +248,7 @@ const defaultColumnDef: ColDef = { export const INDEX_COLUMN_DEF: ColDef = { headerName: '#', + colId: `${Number.MAX_SAFE_INTEGER}`, field: `${Number.MAX_SAFE_INTEGER}`, valueGetter: 'node.id', width: 70, diff --git a/webapp/packages/ag-grid-plugin/src/AgGridTable/TableColumnHeader/TableColumnHeader.tsx b/webapp/packages/ag-grid-plugin/src/AgGridTable/TableColumnHeader/TableColumnHeader.tsx index 6c89efe9dc..ef3b1f8a01 100644 --- a/webapp/packages/ag-grid-plugin/src/AgGridTable/TableColumnHeader/TableColumnHeader.tsx +++ b/webapp/packages/ag-grid-plugin/src/AgGridTable/TableColumnHeader/TableColumnHeader.tsx @@ -70,7 +70,7 @@ const headerStyles = css` `; export interface IAgColumnClickEvent extends AgEvent{ - columnIndex: number; + columnId: string; isMultiple: boolean; } @@ -80,7 +80,7 @@ export function TableColumnHeader(props: HeaderProps) { const handleClick = useCallback((e: React.MouseEvent) => { const event: IAgColumnClickEvent = Object.freeze({ type: COLUMN_CLICK_EVENT_TYPE, - columnIndex: parseInt(props.column.getColId()), + columnId: props.column.getColId(), isMultiple: e.ctrlKey, }); diff --git a/webapp/packages/ag-grid-plugin/src/AgGridTable/TableSelection/RowSelection.ts b/webapp/packages/ag-grid-plugin/src/AgGridTable/TableSelection/RowSelection.ts index de08f3a769..7ad0b951f4 100644 --- a/webapp/packages/ag-grid-plugin/src/AgGridTable/TableSelection/RowSelection.ts +++ b/webapp/packages/ag-grid-plugin/src/AgGridTable/TableSelection/RowSelection.ts @@ -7,31 +7,31 @@ */ export class RowSelection { - columns = new Set() + columns = new Set() constructor(readonly rowId: number) {} - add(columnIndexList: number[]) { + add(columnIndexList: string[]) { for (const columnId of columnIndexList) { this.columns.add(columnId); } } - remove(columnIndexList: number[]) { + remove(columnIndexList: string[]) { for (const columnId of columnIndexList) { this.columns.delete(columnId); } } - replace(columnIndexList: number[]) { + replace(columnIndexList: string[]) { this.columns.clear(); this.add(columnIndexList); } - isSelected(columnIndex: number) { + isSelected(columnIndex: string) { return this.columns.has(columnIndex); } - isRangeSelected(columnIndexList: number[]) { + isRangeSelected(columnIndexList: string[]) { return columnIndexList.every(column => this.columns.has(column)); } } diff --git a/webapp/packages/ag-grid-plugin/src/AgGridTable/TableSelection/TableSelection.ts b/webapp/packages/ag-grid-plugin/src/AgGridTable/TableSelection/TableSelection.ts index 892797088d..9d4aa28f02 100644 --- a/webapp/packages/ag-grid-plugin/src/AgGridTable/TableSelection/TableSelection.ts +++ b/webapp/packages/ag-grid-plugin/src/AgGridTable/TableSelection/TableSelection.ts @@ -22,28 +22,28 @@ export class TableSelection { this.selectedMap.clear(); } - selectCell(rowId: number, columnIndex: number, isMultiple: boolean, ignoreSelected = false) { + selectCell(rowId: number, columnId: string, isMultiple: boolean, ignoreSelected = false) { if (!isMultiple) { this.clear(); } const rowSelection = this.selectedMap.get(rowId); - if (!ignoreSelected && rowSelection?.isSelected(columnIndex)) { + if (!ignoreSelected && rowSelection?.isSelected(columnId)) { this.unselectColumn( this.selectedMap, rowSelection, - [columnIndex] + [columnId] ); } else { - this.selectColumn(rowId, rowSelection, [columnIndex]); + this.selectColumn(rowId, rowSelection, [columnId]); } } selectRange( startPosition: number, endPosition: number, - columns: number[], + columns: string[], isMultiple: boolean ) { const firstRow = Math.min(startPosition, endPosition); @@ -70,13 +70,13 @@ export class TableSelection { } } - isCellSelected(rowId: number, columnIndex: number): boolean { + isCellSelected(rowId: number, columnId: string): boolean { const current = this.selectedMap.get(rowId); - return current?.isSelected(columnIndex) || false; + return current?.isSelected(columnId) || false; } - isRangeSelected(startPosition: number, endPosition: number, columns: number[]): boolean { + isRangeSelected(startPosition: number, endPosition: number, columns: string[]): boolean { const start = Math.min(startPosition, endPosition); const end = Math.max(startPosition, endPosition); @@ -89,19 +89,19 @@ export class TableSelection { return true; } - private unselectColumn(source: Map, rowSelection: RowSelection, columnIndexList: number[]) { - rowSelection.remove(columnIndexList); + private unselectColumn(source: Map, rowSelection: RowSelection, columns: string[]) { + rowSelection.remove(columns); if (rowSelection.columns.size === 0) { source.delete(rowSelection.rowId); } } - private selectColumn(rowId: number, rowSelection: RowSelection | undefined = undefined, columnIndexList: number[]) { + private selectColumn(rowId: number, rowSelection: RowSelection | undefined = undefined, columns: string[]) { if (!rowSelection) { rowSelection = new RowSelection(rowId); this.selectedMap.set(rowId, rowSelection); } - rowSelection.add(columnIndexList); + rowSelection.add(columns); } } diff --git a/webapp/packages/ag-grid-plugin/src/modules/RangeSelection/rangeController.ts b/webapp/packages/ag-grid-plugin/src/modules/RangeSelection/rangeController.ts index 3d792fdd2b..bc87638da8 100644 --- a/webapp/packages/ag-grid-plugin/src/modules/RangeSelection/rangeController.ts +++ b/webapp/packages/ag-grid-plugin/src/modules/RangeSelection/rangeController.ts @@ -51,7 +51,7 @@ const EVENT_KEY_CODE = { interface TemporarySelectionRange { firstRow: number; lastRow: number; - columns: number[]; + columns: string[]; isMultiple: boolean; } @@ -110,7 +110,7 @@ export class RangeController implements IRangeController { private copySelectedData() { const selectedRows = this.selection!.getSelectedRows(); - const selectedColumns = new Set(); + const selectedColumns = new Set(); for (const selectedRow of selectedRows) { for (const columnId of selectedRow.columns) { @@ -120,7 +120,7 @@ export class RangeController implements IRangeController { const columns = this.columnController .getAllDisplayedColumns() - .filter(column => selectedColumns.has(parseInt(column.getColId()))); + .filter(column => selectedColumns.has(column.getColId())); let data = ''; for (const selectedRow of selectedRows) { @@ -128,7 +128,7 @@ export class RangeController implements IRangeController { if (column !== columns[0]) { data += '\t'; } - if (selectedRow.isSelected(parseInt(column.getColId()))) { + if (selectedRow.isSelected(column.getColId())) { const rowNode = this.rowPositionUtils.getRowNode({ rowIndex: selectedRow.rowId, rowPinned: undefined, @@ -164,7 +164,7 @@ export class RangeController implements IRangeController { return; } const lastRowId = this.gridApi.getInfiniteRowCount() - 1 - (this.rowModel.isLastRowFound() ? 0 : 1); - if (event.columnIndex === parseInt(INDEX_COLUMN_DEF.field!)) { + if (event.columnId === INDEX_COLUMN_DEF.colId!) { this.selection.selectRange( 0, lastRowId, @@ -172,7 +172,7 @@ export class RangeController implements IRangeController { event.isMultiple ); } else { - this.selection.selectRange(0, lastRowId, [event.columnIndex], event.isMultiple); + this.selection.selectRange(0, lastRowId, [event.columnId], event.isMultiple); } this.restoreFocus(); this.dispatchChangedEvent(false, true); @@ -183,7 +183,7 @@ export class RangeController implements IRangeController { return; } - if (event.column.getColId() === INDEX_COLUMN_DEF.field) { + if (event.column.getColId() === INDEX_COLUMN_DEF.colId) { this.selection.selectRange( event.rowIndex, event.rowIndex, @@ -201,16 +201,16 @@ export class RangeController implements IRangeController { this.lastSelectedCell = cell; this.lastFocus = cell; if (!this.gridOptionsWrapper.isEnableRangeSelection() - || cell.column.getColDef().field === INDEX_COLUMN_DEF.field) { + || cell.column.getColId() === INDEX_COLUMN_DEF.colId) { return; } - this.selection.selectCell(cell.rowIndex, parseInt(cell.column.getColId()), appendRange); + this.selection.selectCell(cell.rowIndex, cell.column.getColId(), appendRange); this.dispatchChangedEvent(false, true); } getCellRangeCount(cell: CellPosition): number { - const columnIndex = parseInt(cell.column.getColId()); - if (this.isCellInTemporaryRange(cell.rowIndex, columnIndex)) { + const columnId = cell.column.getColId(); + if (this.isCellInTemporaryRange(cell.rowIndex, columnId)) { const isRangeSelected = this.selection?.isRangeSelected( this.temporaryRange!.firstRow, this.temporaryRange!.lastRow, @@ -218,7 +218,7 @@ export class RangeController implements IRangeController { ); return isRangeSelected ? 0 : 1; } - if (this.selection?.isCellSelected(cell.rowIndex, parseInt(cell.column.getColId()))) { + if (this.selection?.isCellSelected(cell.rowIndex, cell.column.getColId())) { return 1; } @@ -232,7 +232,7 @@ export class RangeController implements IRangeController { const startRow = this.lastSelectedCell !== undefined ? this.lastSelectedCell.rowIndex : position.rowIndex; const endRow = position.rowIndex; let columns = this.getColumnsBetween((this.lastSelectedCell || position).column, position.column); - const isRowsSelection = columns.includes(parseInt(INDEX_COLUMN_DEF.field!)); + const isRowsSelection = columns.includes(INDEX_COLUMN_DEF.colId!); if (isRowsSelection) { columns = this.getColumnsWithoutIndex(); @@ -293,9 +293,9 @@ export class RangeController implements IRangeController { this.eventService.dispatchEvent(event); } - private getColumnsBetween(firstColumn: Column, secondColumn: Column): number[] { + private getColumnsBetween(firstColumn: Column, secondColumn: Column): string[] { if (firstColumn === secondColumn) { - return [parseInt(firstColumn.getColId())]; + return [firstColumn.getColId()]; } const columns = this.columnController.getAllDisplayedColumns(); @@ -309,14 +309,14 @@ export class RangeController implements IRangeController { const firstIndex = Math.min(firstOffset, secondOffset); const lastIndex = Math.max(firstOffset, secondOffset); - return columns.slice(firstIndex, lastIndex + 1).map(column => parseInt(column.getColId())); + return columns.slice(firstIndex, lastIndex + 1).map(column => column.getColId()); } private getColumnsWithoutIndex() { return this.columnController .getAllDisplayedColumns() - .map(column => parseInt(column.getColId())) - .filter(column => column !== parseInt(INDEX_COLUMN_DEF.field!)); + .map(column => column.getColId()) + .filter(column => column !== INDEX_COLUMN_DEF.colId!); } getRangeStartRow(cellRange: CellRange): RowPosition { @@ -338,10 +338,10 @@ export class RangeController implements IRangeController { return; } - if (startDraggingCell.column.getColId() !== INDEX_COLUMN_DEF.field) { + if (startDraggingCell.column.getColId() !== INDEX_COLUMN_DEF.colId) { this.selection.selectCell( startDraggingCell.rowIndex, - parseInt(startDraggingCell.column.getColId()), + startDraggingCell.column.getColId(), true, true ); @@ -404,7 +404,7 @@ export class RangeController implements IRangeController { } let columns = this.getColumnsBetween(this.startDraggingCell.column, this.endDraggingCell.column); - const isRowsSelection = columns.includes(parseInt(INDEX_COLUMN_DEF.field!)); + const isRowsSelection = columns.includes(INDEX_COLUMN_DEF.colId!); const startRow = this.startDraggingCell.rowIndex; const endRow = this.endDraggingCell.rowIndex; @@ -438,7 +438,7 @@ export class RangeController implements IRangeController { this.temporaryRange = null; } - private isCellInTemporaryRange(rowId: number, column: number) { + private isCellInTemporaryRange(rowId: number, column: string) { if (!this.temporaryRange || this.temporaryRange.firstRow > rowId || this.temporaryRange.lastRow < rowId || !this.temporaryRange.columns.includes(column) diff --git a/webapp/packages/core/src/app/TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService.ts b/webapp/packages/core/src/app/TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService.ts index 4053d4fc02..fb8ee84671 100644 --- a/webapp/packages/core/src/app/TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService.ts +++ b/webapp/packages/core/src/app/TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService.ts @@ -180,7 +180,7 @@ export class ConnectionSchemaManagerService { try { await this.connectionsManagerService.loadConnectionInfoAsync(connectionId); } catch (exception) { - this.notificationService.logException(exception, 'Can\'t load connection info'); + this.notificationService.logException(exception, 'Can\'t load connection info', true); } try { diff --git a/webapp/packages/core/src/app/TopNavBar/ConnectionSchemaManager/ConnectionSelector/ConnectionSelectorController.ts b/webapp/packages/core/src/app/TopNavBar/ConnectionSchemaManager/ConnectionSelector/ConnectionSelectorController.ts index 109951fe86..5b47cff2ec 100644 --- a/webapp/packages/core/src/app/TopNavBar/ConnectionSchemaManager/ConnectionSelector/ConnectionSelectorController.ts +++ b/webapp/packages/core/src/app/TopNavBar/ConnectionSchemaManager/ConnectionSelector/ConnectionSelectorController.ts @@ -41,7 +41,7 @@ export class ConnectionSelectorController { } get isConnectionSelectorVisible() { - return !!this.connectionSelectorService.currentConnectionId; + return !!this.currentConnection; } get isObjectContainerSelectorVisible() { return !!this.connectionSelectorService.currentObjectCatalogId diff --git a/webapp/packages/core/src/app/shared/ConnectionsManager/ConnectionsManagerService.ts b/webapp/packages/core/src/app/shared/ConnectionsManager/ConnectionsManagerService.ts index c7655e4cc4..6ccb99dd79 100644 --- a/webapp/packages/core/src/app/shared/ConnectionsManager/ConnectionsManagerService.ts +++ b/webapp/packages/core/src/app/shared/ConnectionsManager/ConnectionsManagerService.ts @@ -173,22 +173,27 @@ export class ConnectionsManagerService { } async closeNavNodeConnectionAsync(navNodeId: string): Promise { - const node = this.navNodeManagerService.getNode(navNodeId); - if (!node) { + const connectionId = NodeManagerUtils.connectionNodeIdToConnectionId(navNodeId); + const connection = this.getConnectionById(connectionId); + if (!connection) { return; } try { - const connectionId = NodeManagerUtils.connectionNodeIdToConnectionId(navNodeId); await this.graphQLService.gql.closeConnection({ id: connectionId }); await this.afterConnectionClose(connectionId); await this.connectionInfo.refresh(true, { connectionId, close: true }); - if (node.objectFeatures.includes('dataSourceTemporary')) { + if (connection.features.includes(EConnectionFeature.temporary)) { + const node = this.navNodeManagerService.getNode(navNodeId); + if (!node) { + return; + } + await this.navNodeManagerService.refreshTree(node.parentId); } else { await this.navNodeManagerService.refreshNode(navNodeId); + await this.navNodeManagerService.removeTree(navNodeId); } - await this.navNodeManagerService.removeTree(navNodeId); } catch (exception) { this.notificationService.logException(exception, `Can't close connection: ${navNodeId}`); } diff --git a/webapp/packages/core/src/app/shared/InlineEditor/InlineEditor.tsx b/webapp/packages/core/src/app/shared/InlineEditor/InlineEditor.tsx index 2367aa25ef..7580a700dc 100644 --- a/webapp/packages/core/src/app/shared/InlineEditor/InlineEditor.tsx +++ b/webapp/packages/core/src/app/shared/InlineEditor/InlineEditor.tsx @@ -20,22 +20,28 @@ import { useStyles } from '@dbeaver/core/theming'; import { EditorDialog } from './EditorDialog'; import { InlineEditorStyles } from './styles'; -export type InlineEditorControls = 'right' | 'top' | 'bottom' +export type InlineEditorControls = 'right' | 'top' | 'bottom' | 'inside' export type InlineEditorProps = { value: string; + placeholder?: string; controlsPosition?: InlineEditorControls; + simple?: boolean; onChange(value: string): void; onSave(): void; onReject(): void; + className?: string; } export const InlineEditor = observer(function InlineEditor({ value, + placeholder, controlsPosition = 'right', + simple, onChange, onSave, onReject, + className, }: InlineEditorProps) { const commonDialogService = useService(CommonDialogService); @@ -66,14 +72,21 @@ export const InlineEditor = observer(function InlineEditor({ }, []); return styled(useStyles(InlineEditorStyles))( - + - + - + {!simple && } ); diff --git a/webapp/packages/core/src/app/shared/InlineEditor/styles.ts b/webapp/packages/core/src/app/shared/InlineEditor/styles.ts index 713762e09e..0f587ba63f 100644 --- a/webapp/packages/core/src/app/shared/InlineEditor/styles.ts +++ b/webapp/packages/core/src/app/shared/InlineEditor/styles.ts @@ -28,6 +28,7 @@ export const InlineEditorStyles = composes( editor { position: relative; box-sizing: border-box; + display: flex; width: 100%; height: 100%; border: solid 1px #01cca3; @@ -36,6 +37,7 @@ export const InlineEditorStyles = composes( editor-container { position: relative; height: 100%; + flex: 1; & input { color: inherit; @@ -66,6 +68,14 @@ export const InlineEditorStyles = composes( border-bottom-color: #01cca3 !important; } + editor-actions[|position=inside] { + position: relative; + flex: 0 0 auto; + bottom: auto; + left: auto; + border-right: none !important; + } + editor-actions[|position=bottom], editor-actions[|position=top] { right: -1px; diff --git a/webapp/packages/data-viewer-plugin/src/TableViewer/TableHeader/TableWhereFilter.tsx b/webapp/packages/data-viewer-plugin/src/TableViewer/TableHeader/TableWhereFilter.tsx index efd9195428..51cb9eed34 100644 --- a/webapp/packages/data-viewer-plugin/src/TableViewer/TableHeader/TableWhereFilter.tsx +++ b/webapp/packages/data-viewer-plugin/src/TableViewer/TableHeader/TableWhereFilter.tsx @@ -10,6 +10,7 @@ import { observer } from 'mobx-react'; import { useCallback } from 'react'; import styled, { css } from 'reshadow'; +import { InlineEditor } from '@dbeaver/core/app'; import { InputField, IconButton, SubmittingForm } from '@dbeaver/core/blocks'; import { useTranslate } from '@dbeaver/core/localization'; import { composes, useStyles } from '@dbeaver/core/theming'; @@ -18,8 +19,8 @@ import { TableViewerModel } from '../TableViewerModel'; const styles = composes( css` - IconButton { - composes: theme-text-primary theme-ripple from global; + InlineEditor { + composes: theme-background-surface theme-text-on-surface from global; } `, css` @@ -29,15 +30,10 @@ const styles = composes( display: flex; align-items: center; } - InputField { + InlineEditor { flex: 1; - } - IconButton { - margin-right: 18px; - position: relative; height: 24px; - width: 24px; - display: block; + margin: 0 12px; } ` ); @@ -54,18 +50,25 @@ export const TableWhereFilter = observer(function TableWhereFilter({ (value: string) => context.setQueryWhereFilter(value), [context] ); + const resetFilter = useCallback( + () => { + context.setQueryWhereFilter(''); + context.applyQueryFilters(); + }, + [context] + ); return styled(useStyles(styles))( context.applyQueryFilters()}> - context.applyQueryFilters()} + onReject={resetFilter} onChange={handleChange} - mod='surface' + placeholder={translate('table_header_sql_expression')} + controlsPosition='inside' + simple /> - context.applyQueryFilters()}/> ); }); diff --git a/webapp/packages/object-viewer-plugin/src/ObjectViewerTabService.ts b/webapp/packages/object-viewer-plugin/src/ObjectViewerTabService.ts index e7597f2f66..dc59bf0960 100644 --- a/webapp/packages/object-viewer-plugin/src/ObjectViewerTabService.ts +++ b/webapp/packages/object-viewer-plugin/src/ObjectViewerTabService.ts @@ -165,7 +165,7 @@ export class ObjectViewerTabService { const nodeInfo = this.navNodeManagerService .getNodeContainerInfo(context.handlerState.objectId); - if (nodeInfo.catalogId) { + if (!nodeInfo.catalogId) { return; } return nodeInfo.catalogId;