Skip to content

Commit 44b8929

Browse files
SychevAndreymr-anton-tEvgeniaBzzz
authored
dbeaver/pro#7798 [CB] Fix: menu after migration to new (#4008)
* dbeaver/pro#7798 fix: remove unwanted wrapper and relevant CSS module * dbeaver/pro#7798 feat: add refresh action to user administration tools menu * dbeaver/pro#7798 fix: add loader to context menu rendering The menu was failing to open on first click due to lazy-loaded custom items (ContextMenuSearchItem) suspending the entire top navigation bar on initial load, causing portal recreation and loss of open state. Wrapped menu items in a local Loader to ensure lazy components load within the popover without affecting the parent component. * dbeaver/pro#7798 fix: use suspense for each renderMenuItem * dbeaver/pro#7798 refactor: simplify orderItems method in CreateUserBootstrap * dbeaver/pro#7798 fix: fix menuBarItem styles * dbeaver/pro#7798 refactor: update CreateUserBootstrap to include AdministrationScreenService --------- Co-authored-by: mr-anton-t <[email protected]> Co-authored-by: Evgenia <[email protected]>
1 parent b75d802 commit 44b8929

File tree

7 files changed

+85
-55
lines changed

7 files changed

+85
-55
lines changed

webapp/packages/core-ui/src/ContextMenu/RenderMenuItems.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* you may not use this file except in compliance with the License.
77
*/
88
import { observer } from 'mobx-react-lite';
9+
import { Suspense } from 'react';
910

1011
import { type IMenuData } from '@cloudbeaver/core-view';
1112
import { RenderMenuItem } from './RenderMenuItem.js';
@@ -37,18 +38,19 @@ export const RenderMenuItems = observer<IRenderMenuItemsProps>(function RenderMe
3738
return (
3839
<>
3940
{menu.items.map(item => (
40-
<RenderMenuItem
41-
key={item.id}
42-
item={item}
43-
menuData={menu}
44-
onlyIcons={onlyIcons}
45-
placement={placement}
46-
showSubmenuOnHover={showSubmenuOnHover}
47-
menuComponent={menuComponent}
48-
itemComponent={itemComponent}
49-
groupComponent={groupComponent}
50-
groupArrowComponent={groupArrowComponent}
51-
/>
41+
<Suspense key={item.id} fallback={null}>
42+
<RenderMenuItem
43+
item={item}
44+
menuData={menu}
45+
onlyIcons={onlyIcons}
46+
placement={placement}
47+
showSubmenuOnHover={showSubmenuOnHover}
48+
menuComponent={menuComponent}
49+
itemComponent={itemComponent}
50+
groupComponent={groupComponent}
51+
groupArrowComponent={groupArrowComponent}
52+
/>
53+
</Suspense>
5254
))}
5355
</>
5456
);

webapp/packages/core-ui/src/Tabs/Tab/TabMenu.module.css

Lines changed: 0 additions & 12 deletions
This file was deleted.

webapp/packages/core-ui/src/Tabs/Tab/TabMenu.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
import { observer } from 'mobx-react-lite';
99

10-
import { getComputed, s, useS } from '@cloudbeaver/core-blocks';
10+
import { getComputed } from '@cloudbeaver/core-blocks';
1111
import { type IDataContext, useDataContextLink } from '@cloudbeaver/core-data-context';
1212
import { useMenu } from '@cloudbeaver/core-view';
1313

@@ -16,7 +16,6 @@ import type { ITabsContext } from '../TabsContext.js';
1616
import { DATA_CONTEXT_TAB_ID } from './DATA_CONTEXT_TAB_ID.js';
1717
import { DATA_CONTEXT_TABS_CONTEXT } from './DATA_CONTEXT_TABS_CONTEXT.js';
1818
import { MENU_TAB } from './MENU_TAB.js';
19-
import style from './TabMenu.module.css';
2019

2120
interface TabMenuProps extends React.PropsWithChildren {
2221
tabId: string;
@@ -25,7 +24,6 @@ interface TabMenuProps extends React.PropsWithChildren {
2524
}
2625

2726
export const TabMenu = observer<TabMenuProps>(function TabMenu({ children, tabId, state, menuContext }) {
28-
const styles = useS(style);
2927
const menu = useMenu({
3028
menu: MENU_TAB,
3129
context: menuContext,
@@ -43,10 +41,8 @@ export const TabMenu = observer<TabMenuProps>(function TabMenu({ children, tabId
4341
}
4442

4543
return (
46-
<div className={s(styles, { portal: true })}>
4744
<ContextMenu menu={menu} placement="bottom-start">
4845
{children}
4946
</ContextMenu>
50-
</div>
5147
);
5248
});

webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/CreateUserBootstrap.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,54 @@
55
* Licensed under the Apache License, Version 2.0.
66
* you may not use this file except in compliance with the License.
77
*/
8-
import { DATA_CONTEXT_ADMINISTRATION_ITEM_ROUTE } from '@cloudbeaver/core-administration';
8+
import { AdministrationScreenService } from '@cloudbeaver/core-administration';
99
import { AUTH_PROVIDER_LOCAL_ID, AuthProvidersResource } from '@cloudbeaver/core-authentication';
1010
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
1111
import { CachedMapAllKey, getCachedMapResourceLoaderState } from '@cloudbeaver/core-resource';
12-
import { ACTION_CREATE, ActionService, MenuService } from '@cloudbeaver/core-view';
12+
import { ACTION_CREATE, ACTION_REFRESH, ActionService, menuExtractItems, MenuService } from '@cloudbeaver/core-view';
1313

1414
import { AdministrationUsersManagementService } from '../../../AdministrationUsersManagementService.js';
1515
import { MENU_USERS_ADMINISTRATION } from '../../../Menus/MENU_USERS_ADMINISTRATION.js';
1616
import { ADMINISTRATION_ITEM_USER_CREATE_PARAM } from '../ADMINISTRATION_ITEM_USER_CREATE_PARAM.js';
1717
import { CreateUserService } from './CreateUserService.js';
18+
import { DATA_CONTEXT_USERS_ADMINISTRATION_ACTIONS } from './DATA_CONTEXT_USERS_ADMINISTRATION_ACTIONS.js';
1819

19-
@injectable(() => [AuthProvidersResource, CreateUserService, MenuService, ActionService, AdministrationUsersManagementService])
20+
@injectable(() => [
21+
AuthProvidersResource,
22+
CreateUserService,
23+
MenuService,
24+
ActionService,
25+
AdministrationUsersManagementService,
26+
AdministrationScreenService,
27+
])
2028
export class CreateUserBootstrap extends Bootstrap {
2129
constructor(
2230
private readonly authProvidersResource: AuthProvidersResource,
2331
private readonly createUserService: CreateUserService,
2432
private readonly menuService: MenuService,
2533
private readonly actionService: ActionService,
2634
private readonly administrationUsersManagementService: AdministrationUsersManagementService,
35+
private readonly administrationScreenService: AdministrationScreenService,
2736
) {
2837
super();
2938
}
3039

31-
override register() {
40+
override register(): void {
3241
this.menuService.addCreator({
3342
menus: [MENU_USERS_ADMINISTRATION],
3443
getItems(context, items) {
35-
return [...items, ACTION_CREATE];
44+
return [...items, ACTION_CREATE, ACTION_REFRESH];
45+
},
46+
orderItems(context, items) {
47+
items.push(...menuExtractItems(items, [ACTION_REFRESH]));
48+
return items;
3649
},
3750
});
3851

3952
this.actionService.addHandler({
4053
id: 'users-table-base',
4154
menus: [MENU_USERS_ADMINISTRATION],
42-
actions: [ACTION_CREATE],
55+
actions: [ACTION_CREATE, ACTION_REFRESH],
4356
isHidden: (context, action) => {
4457
if (action === ACTION_CREATE) {
4558
return this.administrationUsersManagementService.externalUserProviderEnabled || !this.authProvidersResource.has(AUTH_PROVIDER_LOCAL_ID);
@@ -49,9 +62,7 @@ export class CreateUserBootstrap extends Bootstrap {
4962
},
5063
isDisabled: (context, action) => {
5164
if (action === ACTION_CREATE) {
52-
const administrationItemRoute = context.get(DATA_CONTEXT_ADMINISTRATION_ITEM_ROUTE);
53-
54-
return administrationItemRoute?.param === ADMINISTRATION_ITEM_USER_CREATE_PARAM && !!this.createUserService.state;
65+
return this.administrationScreenService.activeScreen?.param === ADMINISTRATION_ITEM_USER_CREATE_PARAM && !!this.createUserService.state;
5566
}
5667

5768
return false;
@@ -65,6 +76,9 @@ export class CreateUserBootstrap extends Bootstrap {
6576
case ACTION_CREATE:
6677
this.createUserService.create();
6778
break;
79+
case ACTION_REFRESH:
80+
context.get(DATA_CONTEXT_USERS_ADMINISTRATION_ACTIONS)?.onRefresh();
81+
break;
6882
}
6983
},
7084
getActionInfo: (context, action) => {
@@ -76,6 +90,15 @@ export class CreateUserBootstrap extends Bootstrap {
7690
};
7791
}
7892

93+
if (action === ACTION_REFRESH) {
94+
return {
95+
...action.info,
96+
label: 'ui_refresh',
97+
icon: 'refresh',
98+
tooltip: 'authentication_administration_tools_refresh_tooltip',
99+
};
100+
}
101+
79102
return action.info;
80103
},
81104
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* CloudBeaver - Cloud Database Manager
3+
* Copyright (C) 2020-2025 DBeaver Corp and others
4+
*
5+
* Licensed under the Apache License, Version 2.0.
6+
* you may not use this file except in compliance with the License.
7+
*/
8+
9+
import { createDataContext } from '@cloudbeaver/core-data-context';
10+
11+
export interface IUsersAdministrationActions {
12+
onRefresh: () => void;
13+
}
14+
15+
export const DATA_CONTEXT_USERS_ADMINISTRATION_ACTIONS = createDataContext<IUsersAdministrationActions>('Users Administration Actions');

webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersAdministrationMenuBarItemStyles.module.css

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@
66
* you may not use this file except in compliance with the License.
77
*/
88

9-
.menuBarItemGroup {
10-
& .menuBarItem {
11-
& .menuBarItemBox {
12-
gap: 0;
13-
}
14-
& .menuBarItemLabel {
15-
font-size: 14px;
16-
}
9+
.menuBarItem {
10+
padding: 0 4px;
1711

18-
& .menuBarItemIcon + .menuBarItemLabel {
19-
padding-left: initial;
20-
}
12+
& .menuBarItemBox {
13+
gap: 0;
14+
}
15+
& .menuBarItemLabel {
16+
font-size: 14px;
17+
text-transform: uppercase;
18+
font-weight: 700;
19+
}
20+
21+
& .menuBarItemIcon + .menuBarItemLabel {
22+
padding-left: initial;
2123
}
2224
}

webapp/packages/plugin-authentication-administration/src/Administration/Users/UsersTable/UsersAdministrationToolsPanel.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
*/
88
import { observer } from 'mobx-react-lite';
99

10-
import { s, SContext, type StyleRegistry, ToolsAction, ToolsPanel, useTranslate } from '@cloudbeaver/core-blocks';
10+
import { s, SContext, type StyleRegistry, ToolsPanel } from '@cloudbeaver/core-blocks';
11+
import { useDataContext, useDataContextLink } from '@cloudbeaver/core-data-context';
1112
import { MenuBar, MenuBarItemStyles } from '@cloudbeaver/core-ui';
1213
import { useMenu } from '@cloudbeaver/core-view';
1314

1415
import { MENU_USERS_ADMINISTRATION } from '../../../Menus/MENU_USERS_ADMINISTRATION.js';
16+
import { DATA_CONTEXT_USERS_ADMINISTRATION_ACTIONS } from './DATA_CONTEXT_USERS_ADMINISTRATION_ACTIONS.js';
1517
import UsersAdministrationMenuBarItemStyles from './UsersAdministrationMenuBarItemStyles.module.css';
1618
import styles from './UsersAdministrationToolsPanel.module.css';
1719

@@ -30,17 +32,19 @@ const registry: StyleRegistry = [
3032
];
3133

3234
export const UsersAdministrationToolsPanel = observer<Props>(function UsersAdministrationToolsPanel({ onUpdate }) {
33-
const translate = useTranslate();
34-
const menu = useMenu({ menu: MENU_USERS_ADMINISTRATION });
35+
const context = useDataContext();
36+
37+
useDataContextLink(context, (context, id) => {
38+
context.set(DATA_CONTEXT_USERS_ADMINISTRATION_ACTIONS, { onRefresh: onUpdate }, id);
39+
});
40+
41+
const menu = useMenu({ menu: MENU_USERS_ADMINISTRATION, context });
3542

3643
return (
3744
<ToolsPanel className={s(styles, { toolsPanel: true })} rounded>
3845
<SContext registry={registry}>
3946
<MenuBar menu={menu} className={s(styles, { menuBar: true })} compact={false} />
4047
</SContext>
41-
<ToolsAction title={translate('authentication_administration_tools_refresh_tooltip')} icon="refresh" viewBox="0 0 24 24" onClick={onUpdate}>
42-
{translate('ui_refresh')}
43-
</ToolsAction>
4448
</ToolsPanel>
4549
);
4650
});

0 commit comments

Comments
 (0)