Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion webapp/common-react/@dbeaver/ui-kit/src/Composite/Composite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
Composite as AriakitComposite,
CompositeItem as AriakitCompositeItem,
CompositeProvider as AriakitCompositeProvider,
useCompositeContext,
useCompositeStore,
type CompositeProps,
type CompositeItemProps,
Expand All @@ -17,16 +18,23 @@
type CompositeStore,
} from '@ariakit/react';

export function CompositeProvider({ children, ...props }: CompositeProviderProps) {

Check warning on line 21 in webapp/common-react/@dbeaver/ui-kit/src/Composite/Composite.tsx

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
return <AriakitCompositeProvider {...props}>{children}</AriakitCompositeProvider>;
}

export function Composite({ children, ...props }: CompositeProps) {

Check warning on line 25 in webapp/common-react/@dbeaver/ui-kit/src/Composite/Composite.tsx

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
return <AriakitComposite {...props}>{children}</AriakitComposite>;
}

export function CompositeItem({ children, ...props }: CompositeItemProps) {

Check warning on line 29 in webapp/common-react/@dbeaver/ui-kit/src/Composite/Composite.tsx

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Missing return type on function
return <AriakitCompositeItem {...props}>{children}</AriakitCompositeItem>;
}

export { useCompositeStore, type CompositeProps, type CompositeItemProps, type CompositeProviderProps, type CompositeStore };
export {
useCompositeContext,
useCompositeStore,
type CompositeProps,
type CompositeItemProps,
type CompositeProviderProps,
type CompositeStore,
};
1 change: 1 addition & 0 deletions webapp/common-react/@dbeaver/ui-kit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,22 @@
type FocusTrapRegionProps,
} from '@ariakit/react';

export { Button, ButtonBase, type ButtonProps, ButtonIcon, type ButtonIconProps, UnstyledButton, type UnstyledButtonProps } from './Button/Button.js';

Check failure on line 24 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export { IconButton, IconButtonBase, type IconButtonProps } from './IconButton/IconButton.js';

Check failure on line 25 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export { Checkbox, CheckboxBase, type CheckboxProps } from './Checkbox/Checkbox.js';

Check failure on line 26 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export { CheckboxIndicator, type ICheckboxIndicatorProps } from './Checkbox/CheckboxIndicator.js';

Check failure on line 27 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export { ColorPicker } from './ColorPicker/ColorPicker.js';

Check failure on line 28 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export { ColorIndicator } from './ColorPicker/ColorIndicator.js';

Check failure on line 29 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export { ColorPickerBase, type ColorPickerProps } from './ColorPicker/ColorPickerBase.js';

Check failure on line 30 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export { normalizeColorToRgb } from './ColorPicker/colorUtils.js';
export { Input, InputBase, type InputProps } from './Input/Input.js';

Check failure on line 32 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export {
SearchPanel,
type SearchPanelProps,
type SearchPanelRef,
type SearchPanelQuery,
type SearchPanelStrings,
} from './SearchPanel/SearchPanel.js';

Check failure on line 39 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export {
Select,
useSelectContext,
Expand All @@ -46,7 +46,7 @@
type SelectLabelProps,
type SelectPopoverProps,
type SelectItemProps,
} from './Select/Select.js';

Check failure on line 49 in webapp/common-react/@dbeaver/ui-kit/src/index.ts

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Don't import/export .tsx files from .ts files directly, use React.lazy()
export * from './Combobox/Combobox.js';
export * from './Command/Command.js';
export { Popover, usePopoverStore, type PopoverStore } from './Popover/Popover.js';
Expand All @@ -71,6 +71,7 @@
Composite,
CompositeItem,
CompositeProvider,
useCompositeContext,
useCompositeStore,
type CompositeProps,
type CompositeItemProps,
Expand Down
10 changes: 2 additions & 8 deletions webapp/packages/core-blocks/src/Split/SplitControls.module.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
/*
* 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.
*/
.container {
position: absolute;
display: flex;
Expand All @@ -20,7 +13,8 @@
}
}

.container:hover .resizeButton {
.container:hover .resizeButton,
.container:focus-within .resizeButton {
opacity: 1;
}

Expand Down
10 changes: 3 additions & 7 deletions webapp/packages/core-blocks/src/Table/TableBody.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/

interface Props {
className?: string;
}

export const TableBody: React.FC<React.PropsWithChildren<Props>> = function TableBody({ children, className }) {
return <tbody className={className}>{children}</tbody>;
export const TableBody: React.FC<React.ComponentProps<'tbody'>> = function TableBody(props) {
return <tbody {...props} />;
};
6 changes: 4 additions & 2 deletions webapp/packages/core-blocks/src/Table/TableItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2026 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
Expand All @@ -26,7 +26,7 @@
onClose: () => void;
}

interface Props<T> extends React.PropsWithChildren {
interface Props<T> extends Omit<React.ComponentProps<'tr'>, 'onClick' | 'onDoubleClick'> {
item: T;
expandElement?: React.FunctionComponent<TableItemExpandProps<T>>;
selectOnItem?: boolean;
Expand All @@ -39,7 +39,7 @@
}

interface ITableItemComponent {
<T>(props: Props<T>): React.ReactElement<any, any> | null;

Check warning on line 42 in webapp/packages/core-blocks/src/Table/TableItem.tsx

View workflow job for this annotation

GitHub Actions / Frontend / Lint

Interface only has a call signature, you should use a function type instead
}

export const TableItem: ITableItemComponent = observer(function TableItem({
Expand All @@ -53,6 +53,7 @@
className,
onClick,
onDoubleClick,
...rest
}) {
const context = useContext(TableContext);
const props = useObjectRef({ selectOnItem });
Expand All @@ -77,7 +78,7 @@
isSelected: () => !!context.selectedItems.get(item),
isExpanded: () => !!context.expandedItems.get(item),
}),
[item, selectionDisabled],

Check warning on line 81 in webapp/packages/core-blocks/src/Table/TableItem.tsx

View workflow job for this annotation

GitHub Actions / Frontend / Lint

React Hook useMemo has missing dependencies: 'context.expandedItems' and 'context.selectedItems'. Either include them or remove the dependency array
);

const isSelected = itemContext.isSelected();
Expand All @@ -95,10 +96,10 @@
if (onClick) {
onClick();
}
}, []);

Check warning on line 99 in webapp/packages/core-blocks/src/Table/TableItem.tsx

View workflow job for this annotation

GitHub Actions / Frontend / Lint

React Hook useCallback has missing dependencies: 'props.selectOnItem' and 'ref'. Either include them or remove the dependency array

const handleDoubleClick = useCallback(
(e: React.MouseEvent<HTMLTableRowElement>) => {

Check warning on line 102 in webapp/packages/core-blocks/src/Table/TableItem.tsx

View workflow job for this annotation

GitHub Actions / Frontend / Lint

'e' is defined but never used
if (onDoubleClick) {
onDoubleClick();
}
Expand All @@ -117,6 +118,7 @@
<tr
title={title}
className={s(styles, { selected: isSelected, expanded: isExpanded, disabled, row: true }, className)}
{...rest}
onClick={handleClick}
onDoubleClick={handleDoubleClick}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@cloudbeaver/core-utils": "workspace:*",
"@cloudbeaver/core-view": "workspace:*",
"@cloudbeaver/plugin-sql-editor": "workspace:*",
"@dbeaver/ui-kit": "workspace:*",
"mobx": "^6",
"mobx-react-lite": "^4",
"react": "^19",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
useTranslate,
} from '@cloudbeaver/core-blocks';
import type { SqlExecutionPlanNode } from '@cloudbeaver/core-sdk';
import { Composite, CompositeProvider } from '@dbeaver/ui-kit';

import style from './ExecutionPlanTreeBlock.module.css';
import { NestedNode } from './NestedNode.js';
Expand Down Expand Up @@ -57,11 +58,13 @@ export const ExecutionPlanTreeBlock = observer<Props>(function ExecutionPlanTree
);
})}
</TableHeader>
<TableBody>
{state.nodes.map(node => (
<NestedNode key={node.id} columns={state.columns} node={node} depth={0} />
))}
</TableBody>
<CompositeProvider orientation="vertical">
<Composite render={<TableBody />}>
{state.nodes.map(node => (
<NestedNode key={node.id} columns={state.columns} node={node} depth={0} />
))}
</Composite>
</CompositeProvider>
</Table>
) : (
<TextPlaceholder>{translate('plugin_sql_execution_plan_placeholder')}</TextPlaceholder>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import classes from './Expand.module.css';
interface Props {
expanded: boolean;
className?: string;
onClick: (event: React.MouseEvent<any>) => void;
onClick?: (event: React.MouseEvent<any>) => void;
}

export const Expand: React.FC<Props> = function Expand({ expanded, className, onClick }) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
* you may not use this file except in compliance with the License.
*/

.row:focus-visible {
outline: 1px solid var(--theme-primary);
outline-offset: -1px;
}

.tableColumnValue {
white-space: pre;
cursor: pointer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2026 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 { useCallback, useState } from 'react';

import { EventTableItemSelectionFlag, TableColumnValue, TableItem } from '@cloudbeaver/core-blocks';
import { EventTableItemSelectionFlag, s, TableColumnValue, TableItem } from '@cloudbeaver/core-blocks';
import { EventContext } from '@cloudbeaver/core-events';
import type { IObjectPropertyInfo } from '@cloudbeaver/core-sdk';
import { CompositeItem } from '@dbeaver/ui-kit';

import type { IExecutionPlanNode } from './ExecutionPlanTreeContext.js';
import { Expand } from './Expand.js';
import { getPropertyValue } from './getPropertyValue.js';
import classes from './NestedNode.module.css';
import { useTreeGridKeyDown } from './useTreeGridKeyDown.js';

interface Props {
columns: IObjectPropertyInfo[];
Expand All @@ -23,6 +25,10 @@ interface Props {
className?: string;
}

function getNodeItemId(nodeId: string): string {
return `execution-plan-node-${nodeId}`;
}

export const NestedNode: React.FC<Props> = function NestedNode({ columns, node, depth, className }) {
const [expanded, setExpanded] = useState(true);

Expand All @@ -32,10 +38,21 @@ export const NestedNode: React.FC<Props> = function NestedNode({ columns, node,
}, []);

const hasChildren = node.children.length > 0;
const handleKeyDown = useTreeGridKeyDown({
expanded: hasChildren ? expanded : undefined,
parentItemId: node.parentId ? getNodeItemId(node.parentId) : undefined,
setExpanded,
});

return (
<>
<TableItem key={`${node.id}_${depth}`} className={className} item={node.id} selectOnItem>
<CompositeItem
id={getNodeItemId(node.id)}
aria-expanded={hasChildren ? expanded : undefined}
aria-level={depth + 1}
render={<TableItem item={node.id} className={s(classes, { row: true }, className)} selectOnItem />}
onKeyDown={handleKeyDown}
>
{columns.map((column, idx) => {
const property = node.properties.find(property => property.id === column.id);
const value = property ? getPropertyValue(property) : '';
Expand All @@ -53,7 +70,7 @@ export const NestedNode: React.FC<Props> = function NestedNode({ columns, node,
</TableColumnValue>
);
})}
</TableItem>
</CompositeItem>
{expanded && node.children.map(child => <NestedNode key={child.id} columns={columns} node={child} depth={depth + 1} />)}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useMemo } from 'react';

import { Table, TableBody, TableColumnHeader, TableHeader, TextPlaceholder, useTranslate } from '@cloudbeaver/core-blocks';
import type { ObjectPropertyInfo, SqlExecutionPlanNode } from '@cloudbeaver/core-sdk';
import { Composite, CompositeProvider } from '@dbeaver/ui-kit';

import { isVisibleProperty } from '../useExecutionPlanTreeState.js';
import { PropertiesPanelItemsGroup } from './PropertiesPanelItemsGroup.js';
Expand Down Expand Up @@ -62,14 +63,16 @@ export const PropertiesPanel = observer<Props>(function PropertiesPanel({ select
<TableColumnHeader title={nameColumnTitle}>{nameColumnTitle}</TableColumnHeader>
<TableColumnHeader title={valueColumnTitle}>{valueColumnTitle}</TableColumnHeader>
</TableHeader>
<TableBody>
{!!general.length && (
<PropertiesPanelItemsGroup properties={general} name={translate('plugin_sql_execution_plan_properties_panel_general')} />
)}
{!!details.length && (
<PropertiesPanelItemsGroup properties={details} name={translate('plugin_sql_execution_plan_properties_panel_details')} />
)}
</TableBody>
<CompositeProvider orientation="vertical">
<Composite render={<TableBody />}>
{!!general.length && (
<PropertiesPanelItemsGroup properties={general} name={translate('plugin_sql_execution_plan_properties_panel_general')} />
)}
{!!details.length && (
<PropertiesPanelItemsGroup properties={details} name={translate('plugin_sql_execution_plan_properties_panel_details')} />
)}
</Composite>
</CompositeProvider>
</Table>
);
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/*
* 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.
*/
.row:focus-visible {
outline: 1px solid var(--theme-primary);
outline-offset: -1px;
}

.tableColumnValue {
white-space: pre;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 DBeaver Corp and others
* Copyright (C) 2020-2026 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 { useState } from 'react';
import { useId, useState } from 'react';

import { TableColumnValue, TableItem } from '@cloudbeaver/core-blocks';
import { s, TableColumnValue, TableItem } from '@cloudbeaver/core-blocks';
import type { IObjectPropertyInfo } from '@cloudbeaver/core-sdk';
import { CompositeItem } from '@dbeaver/ui-kit';

import { Expand } from '../Expand.js';
import { getPropertyValue } from '../getPropertyValue.js';
import { useTreeGridKeyDown } from '../useTreeGridKeyDown.js';
import classes from './PropertiesPanelItemsGroup.module.css';

interface Props {
Expand All @@ -20,35 +22,52 @@ interface Props {
}

export const PropertiesPanelItemsGroup: React.FC<Props> = function PropertiesPanelItemsGroup({ properties, name }) {
const groupItemId = useId();
const [expanded, setExpanded] = useState(true);

const handleGroupKeyDown = useTreeGridKeyDown({ expanded, setExpanded });
const handlePropertyKeyDown = useTreeGridKeyDown({ expanded: undefined, parentItemId: groupItemId });

return (
<>
<TableItem item={`${name}_root`} selectDisabled>
<CompositeItem
id={groupItemId}
aria-expanded={expanded}
aria-level={1}
render={
<TableItem item={`${name}_root`} className={s(classes, { row: true })} title={name} selectDisabled onClick={() => setExpanded(!expanded)} />
}
onKeyDown={handleGroupKeyDown}
>
<TableColumnValue className={classes['tableColumnValue']} title={name}>
<div className={classes['control']}>
<div className={classes['expandContainer']}>
<Expand expanded={expanded} onClick={() => setExpanded(!expanded)} />
<Expand expanded={expanded} />
</div>
{name}
</div>
</TableColumnValue>
<TableColumnValue className={classes['tableColumnValue']} />
</TableItem>
</CompositeItem>
{expanded &&
properties.map(property => {
const name = property.displayName;
const tooltip = `${name} ${property.description ? '(' + property.description + ')' : ''}`;
const value = getPropertyValue(property);
return (
<TableItem key={property.id} item={property.id} selectDisabled>
<CompositeItem
key={property.id}
aria-level={2}
render={<TableItem item={property.id} className={s(classes, { row: true })} selectDisabled />}
onKeyDown={handlePropertyKeyDown}
>
<TableColumnValue className={classes['tableColumnValue']} title={tooltip}>
{'\t\t' + name}
</TableColumnValue>
<TableColumnValue className={classes['tableColumnValue']} title={value}>
{value}
</TableColumnValue>
</TableItem>
</CompositeItem>
);
})}
</>
Expand Down
Loading
Loading