Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
93a598b
dbeaver/pro#7772 adds truncated tooltips for context menus
sergeyteleshev Jan 6, 2026
285b6b7
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
sergeyteleshev Jan 6, 2026
e64ad4f
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
sergeyteleshev Jan 8, 2026
a7365de
dbeaver/pro#7772 adds " ... " for long labels
sergeyteleshev Jan 8, 2026
178dfe8
adds unit tests
sergeyteleshev Jan 8, 2026
8fa917c
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
sergeyteleshev Jan 8, 2026
e0e4162
Update webapp/packages/core-blocks/src/Menu/MenuItemElement.tsx
sergeyteleshev Jan 8, 2026
6f02892
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
sergeyteleshev Jan 8, 2026
9732955
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
dariamarutkina Jan 9, 2026
67ad19b
adds binding for delete row
sergeyteleshev Jan 9, 2026
c8455bd
removes tooltips
sergeyteleshev Jan 9, 2026
f423efe
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
sergeyteleshev Jan 9, 2026
b2eb320
fixes tree filters clipping
sergeyteleshev Jan 9, 2026
459dfab
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
sergeyteleshev Jan 12, 2026
cd3ee3d
clips only names, not whole labels
sergeyteleshev Jan 12, 2026
1e01d04
clips only names, not whole labels [2]
sergeyteleshev Jan 12, 2026
f3c996d
reverts getBindingLabels + fixes the os specific keys to show it first
sergeyteleshev Jan 12, 2026
34d1696
clips only names, not whole labels [3]
sergeyteleshev Jan 12, 2026
8743624
dbeaver/pro#7772 simplifies keys helpers logic
sergeyteleshev Jan 12, 2026
637f675
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
dariamarutkina Jan 13, 2026
a3c72c3
Merge branch 'devel' into 7772-cb-remove-tooltips-from-context-menu
dariamarutkina Jan 13, 2026
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
15 changes: 8 additions & 7 deletions webapp/packages/core-blocks/src/Menu/MenuItemElement.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 { observer } from 'mobx-react-lite';
import { type HTMLAttributes, useRef } from 'react';

import { Icon } from '../Icon.js';
import { IconOrImage } from '../IconOrImage.js';
Expand All @@ -14,8 +15,8 @@ import { useTranslate } from '../localization/useTranslate.js';
import { s } from '../s.js';
import { useS } from '../useS.js';
import { useStateDelay } from '../useStateDelay.js';
import { useTruncatedTooltip } from '../useTruncatedTooltip.js';
import style from './MenuItemElement.module.css';
import type { HTMLAttributes } from 'react';

export interface IMenuItemGroupArrowElementProps extends HTMLAttributes<HTMLButtonElement> {}

Expand Down Expand Up @@ -43,21 +44,21 @@ export const MenuItemElement = observer<IMenuItemElementProps>(function MenuItem
}) {
const styles = useS(style);
const translate = useTranslate();

const title = translate(label);
const textRef = useRef<HTMLDivElement | null>(null);
const truncatedLabel = useTruncatedTooltip(textRef, label);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we dont need this, tooltips are just fine

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think so, we don't expect to have long tooltips or labels in the menu items, where we expect them, we should truncate them at the declaration point

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for example like here:

if (this.clipboardService.state === 'granted') {
const filters = supportedOperations
.filter(operation => !nullOperationsFilter(operation))
.map(operation => {
const val = this.clipboardService.clipboardValue || '';
const wrappedValue = wrapOperationArgument(operation.id, val);
const clippedValue = replaceMiddle(wrappedValue, ' ... ', 8, 30);
const label = `${columnLabel} ${operation.expression} ${clippedValue}`;
return new MenuBaseItem(
{ id: operation.id, icon: 'filter-clipboard', label },
{
onSelect: async () => {
const wrappedValue = wrapOperationArgument(operation.id, val);
await this.applyFilter(
model as unknown as IDatabaseDataModel<ResultSetDataSource>,
resultIndex,
key.column,
operation.id,
wrappedValue,
);
},
},
{ isDisabled: () => model.isLoading() },
);
});
result.push(...filters);
}

loading = useStateDelay(loading, 300);

return (
<button {...rest} className={s(styles, { menuPanelItem: true }, rest.className)} title={tooltip ? translate(tooltip) : title}>
<button {...rest} className={s(styles, { menuPanelItem: true }, rest.className)} title={tooltip || truncatedLabel}>
<div className={s(styles, { menuItemMain: true })}>
<div className={s(styles, { menuItemIcon: true })}>
<Loader className={s(styles, { loader: true })} suspense small fullSize>
{typeof icon === 'string' ? <IconOrImage className={s(styles, { iconOrImage: true })} icon={icon} /> : icon}
</Loader>
</div>
{!onlyIcons ? (
<div className={s(styles, { menuItemText: true })} title={title}>
{title}
<div ref={textRef} className={s(styles, { menuItemText: true })}>
{translate(label)}
</div>
) : (
<div />
Expand Down
3 changes: 2 additions & 1 deletion webapp/packages/core-blocks/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2025 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 @@ -10,22 +10,22 @@

export * from './AuthenticationProviderLoader.js';
export * from './useAuthenticationAction.js';
export * from './CommonDialog/CommonDialog/CommonDialogBody.js';

Check failure on line 13 in webapp/packages/core-blocks/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()

Check failure on line 13 in webapp/packages/core-blocks/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 './CommonDialog/CommonDialog/CommonDialogFooter.js';

Check failure on line 14 in webapp/packages/core-blocks/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()

Check failure on line 14 in webapp/packages/core-blocks/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 './CommonDialog/CommonDialog/CommonDialogHeader.js';

Check failure on line 15 in webapp/packages/core-blocks/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()

Check failure on line 15 in webapp/packages/core-blocks/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 './CommonDialog/CommonDialog/CommonDialogWrapper.js';

Check failure on line 16 in webapp/packages/core-blocks/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()

Check failure on line 16 in webapp/packages/core-blocks/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 './CommonDialog/ConfirmationDialog.js';

Check failure on line 17 in webapp/packages/core-blocks/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()

Check failure on line 17 in webapp/packages/core-blocks/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 { default as ConfirmationDialogStyles } from './CommonDialog/ConfirmationDialog.module.css';
export * from './CommonDialog/ConfirmationDialogDelete.js';

Check failure on line 19 in webapp/packages/core-blocks/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()

Check failure on line 19 in webapp/packages/core-blocks/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 './CommonDialog/RenameDialog.js';

Check failure on line 20 in webapp/packages/core-blocks/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()

Check failure on line 20 in webapp/packages/core-blocks/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 './CommonDialog/DialogsPortal.js';

Check failure on line 21 in webapp/packages/core-blocks/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()

Check failure on line 21 in webapp/packages/core-blocks/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 './ExportImageDialog/ExportImageDialogLazy.js';
export * from './ExportImageDialog/ExportImageFormats.js';

export * from './ErrorDetailsDialog/ErrorDetailsDialog.js';

Check failure on line 25 in webapp/packages/core-blocks/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()

Check failure on line 25 in webapp/packages/core-blocks/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 './ComponentsRegistry/CRegistryLoader.js';
export * from './ComponentsRegistry/registry.js';

Check failure on line 28 in webapp/packages/core-blocks/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()

Check failure on line 28 in webapp/packages/core-blocks/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 './ComponentsRegistry/CRegistryList.js';
export * from './ComponentsRegistry/IComponentsTreeNodeValidator.js';
export * from './ComponentsRegistry/useParentProps.js';
Expand Down Expand Up @@ -231,6 +231,7 @@
export * from './usePromiseState.js';
export * from './useS.js';
export * from './useStateDelay.js';
export * from './useTruncatedTooltip.js';
export * from './useErrorDetails.js';
export * from './useActivationDelay.js';
export * from './useAdministrationSettings.js';
Expand Down
60 changes: 60 additions & 0 deletions webapp/packages/core-blocks/src/useTruncatedTooltip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* CloudBeaver - Cloud Database Manager
* 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 { useEffect, useRef, useState } from 'react';

import { useTranslate } from './localization/useTranslate.js';

export function useTruncatedTooltip(ref: React.RefObject<HTMLDivElement | null>, tooltip: string | undefined): string | undefined {
const [isTextTruncated, setIsTextTruncated] = useState(false);
const translate = useTranslate();
const observerRef = useRef<ResizeObserver | null>(null);
const elementRef = useRef<HTMLDivElement | null>(null);

function checkTruncation() {
if (elementRef.current) {
setIsTextTruncated(elementRef.current.scrollWidth > elementRef.current.clientWidth);
}
}

useEffect(() => {
const element = ref.current;

if (elementRef.current === element) {
return;
}

if (observerRef.current) {
observerRef.current.disconnect();
observerRef.current = null;
}

elementRef.current = element;

if (!element) {
return;
}

checkTruncation();

const resizeObserver = new ResizeObserver(checkTruncation);
resizeObserver.observe(element);
observerRef.current = resizeObserver;

return () => {
resizeObserver.disconnect();
};
});

const translatedTooltip = tooltip ? translate(tooltip) : undefined;

if (isTextTruncated && translatedTooltip) {
return translatedTooltip;
}

return;
}
Loading