mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-12 23:37:00 +08:00
Merge remote-tracking branch 'origin/devel' into devel
This commit is contained in:
@@ -10,7 +10,6 @@ import { AdministrationTopAppBarService, WizardTopAppBarService } from '@cloudbe
|
||||
import { injectable, Bootstrap } from '@cloudbeaver/core-di';
|
||||
|
||||
import { Logo } from './Logo';
|
||||
import { SettingsMenu } from './SettingsMenu/SettingsMenu';
|
||||
|
||||
@injectable()
|
||||
export class AdministrationTopAppBarBootstrapService extends Bootstrap {
|
||||
@@ -23,9 +22,8 @@ export class AdministrationTopAppBarBootstrapService extends Bootstrap {
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.administrationTopAppBarService.placeholder.add(Logo, 0);
|
||||
this.administrationTopAppBarService.placeholder.add(SettingsMenu, 4);
|
||||
this.wizardTopAppBarService.placeholder.add(Logo, 0);
|
||||
}
|
||||
|
||||
load(): void | Promise<void> {}
|
||||
}
|
||||
load(): void | Promise<void> { }
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { IComputedMenuItemOptions, IMenuPanel, StaticMenu } from '@cloudbeaver/core-dialogs';
|
||||
import { LocalizationService } from '@cloudbeaver/core-localization';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { ThemeService } from '@cloudbeaver/core-theming';
|
||||
|
||||
@injectable()
|
||||
export class SettingsMenuService extends Bootstrap {
|
||||
static settingsMenuToken = 'settingsMenu';
|
||||
|
||||
private menu = new StaticMenu();
|
||||
private langMenuToken = 'langMenu';
|
||||
private themeMenuToken = 'themeMenu';
|
||||
|
||||
constructor(
|
||||
private localizationService: LocalizationService,
|
||||
private themeService: ThemeService,
|
||||
private serverConfigResource: ServerConfigResource,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.menu.addRootPanel(SettingsMenuService.settingsMenuToken);
|
||||
}
|
||||
|
||||
async load(): Promise<void> {
|
||||
this.addThemes();
|
||||
await this.addLocales();
|
||||
}
|
||||
|
||||
getMenu(): IMenuPanel {
|
||||
return this.menu.getMenu(SettingsMenuService.settingsMenuToken);
|
||||
}
|
||||
|
||||
addMenuItem(panelId: string, options: IComputedMenuItemOptions): void {
|
||||
this.menu.addMenuItem(panelId, options);
|
||||
}
|
||||
|
||||
private addThemes() {
|
||||
this.addMenuItem(
|
||||
SettingsMenuService.settingsMenuToken,
|
||||
{
|
||||
id: this.themeMenuToken,
|
||||
order: 1,
|
||||
title: 'app_shared_settingsMenu_theme',
|
||||
isPanel: true,
|
||||
}
|
||||
);
|
||||
|
||||
this.themeService.themes.forEach(theme => {
|
||||
this.addMenuItem(
|
||||
this.themeMenuToken,
|
||||
{
|
||||
id: theme.id,
|
||||
title: theme.name,
|
||||
isDisabled: () => theme.id === this.themeService.currentThemeId,
|
||||
onClick: () => this.themeService.changeThemeAsync(theme.id),
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private async addLocales() {
|
||||
const config = await this.serverConfigResource.load();
|
||||
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.addMenuItem(
|
||||
SettingsMenuService.settingsMenuToken,
|
||||
{
|
||||
id: this.langMenuToken,
|
||||
order: 2,
|
||||
title: 'app_shared_settingsMenu_lang',
|
||||
isPanel: true,
|
||||
}
|
||||
);
|
||||
|
||||
config.supportedLanguages.forEach(lang => {
|
||||
this.addMenuItem(
|
||||
this.langMenuToken,
|
||||
{
|
||||
id: lang.isoCode,
|
||||
title: lang.nativeName,
|
||||
isDisabled: () => lang.isoCode === this.localizationService.getCurrentLanguage(),
|
||||
onClick: () => this.localizationService.changeLocaleAsync(lang.isoCode),
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { useService } from '@cloudbeaver/core-di';
|
||||
|
||||
import { TopNavService } from './TopNavBarService';
|
||||
|
||||
export function TopNavBar() {
|
||||
export const TopNavBar = function TopNavBar() {
|
||||
const topNavBarService = useService(TopNavService);
|
||||
|
||||
return (
|
||||
@@ -19,4 +19,4 @@ export function TopNavBar() {
|
||||
<Placeholder container={topNavBarService.placeholder} />
|
||||
</TopAppBar>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -13,7 +13,6 @@ import { ConnectionSelector } from './ConnectionSchemaManager/ConnectionSelector
|
||||
import { Fill } from './Fill';
|
||||
import { Logo } from './Logo';
|
||||
import { MainMenu } from './MainMenu/MainMenu';
|
||||
import { SettingsMenu } from './SettingsMenu/SettingsMenu';
|
||||
|
||||
@injectable()
|
||||
export class TopNavService {
|
||||
@@ -24,6 +23,5 @@ export class TopNavService {
|
||||
this.placeholder.add(MainMenu, 1);
|
||||
this.placeholder.add(ConnectionSelector, 2);
|
||||
this.placeholder.add(Fill, 3);
|
||||
this.placeholder.add(SettingsMenu, 4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
export * from './CoreSettingsService';
|
||||
export * from './AppScreen/AppScreenService';
|
||||
export * from './TopNavBar/MainMenu/MainMenuService';
|
||||
export * from './TopNavBar/SettingsMenu/SettingsMenuService';
|
||||
export * from './TopNavBar/ConnectionSchemaManager/ConnectionSchemaManagerService';
|
||||
export * from './TopNavBar/TopNavBarService';
|
||||
export * from './TopNavBar/AdministrationTopAppBarBootstrapService';
|
||||
@@ -59,7 +58,6 @@ export * from './useAppVersion';
|
||||
|
||||
// components
|
||||
export * from './Body';
|
||||
export * from './TopNavBar/SettingsMenu/SettingsMenu';
|
||||
export * from './TopNavBar/Logo';
|
||||
|
||||
// Interfaces
|
||||
|
||||
@@ -31,7 +31,6 @@ import {
|
||||
ConnectionSchemaManagerService,
|
||||
NavigationTabsService,
|
||||
NavNodeContextMenuService,
|
||||
SettingsMenuService,
|
||||
LogViewerService,
|
||||
LogViewerBootstrap,
|
||||
TopNavService,
|
||||
@@ -156,7 +155,6 @@ export const coreManifests: PluginManifest[] = [
|
||||
DBObjectResource,
|
||||
NotificationService,
|
||||
SessionService,
|
||||
SettingsMenuService,
|
||||
SettingsService,
|
||||
ThemeSettingsService,
|
||||
ThemeService,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { action, observable, makeObservable } from 'mobx';
|
||||
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ServerService, SessionResource } from '@cloudbeaver/core-root';
|
||||
import { ServerConfigResource, SessionResource } from '@cloudbeaver/core-root';
|
||||
import type { ServerLanguage } from '@cloudbeaver/core-sdk';
|
||||
import { SettingsService } from '@cloudbeaver/core-settings';
|
||||
|
||||
@@ -38,10 +38,10 @@ export class LocalizationService extends Bootstrap {
|
||||
private localeProviders: ILocaleProvider[] = [];
|
||||
|
||||
constructor(
|
||||
private notificationService: NotificationService,
|
||||
private sessionResource: SessionResource,
|
||||
private serverService: ServerService,
|
||||
private settingsService: SettingsService
|
||||
private readonly notificationService: NotificationService,
|
||||
private readonly sessionResource: SessionResource,
|
||||
private readonly serverConfigResource: ServerConfigResource,
|
||||
private readonly settingsService: SettingsService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -133,7 +133,7 @@ export class LocalizationService extends Bootstrap {
|
||||
}
|
||||
|
||||
private async setLocale(key: string) {
|
||||
const config = await this.serverService.config.load();
|
||||
const config = await this.serverConfigResource.load();
|
||||
|
||||
if (!config) {
|
||||
throw new Error('Can\'t get server settings');
|
||||
|
||||
@@ -59,6 +59,7 @@ export const defaultENLocale = [
|
||||
['ui_changes_will_be_lost', 'Your changes will be lost'],
|
||||
['ui_continue', 'Continue'],
|
||||
['ui_authentication', 'Authentication'],
|
||||
['ui_settings', 'Settings'],
|
||||
|
||||
['root_permission_denied', "You don't have permissions"],
|
||||
['root_permission_no_permission', "You don't have permission for this action"],
|
||||
|
||||
@@ -38,6 +38,7 @@ export const defaultITLocale = [
|
||||
['ui_no_items_placeholder', 'Non ci sono ancora elementi.'],
|
||||
['ui_search_no_result_placeholder', 'Nessun risultato trovato.'],
|
||||
['ui_save_reminder', 'Ci sono modifiche non salvate.'],
|
||||
['ui_settings', 'Settings'],
|
||||
|
||||
['root_permission_denied', 'Non hai i permessi'],
|
||||
['app_root_session_expire_warning_title', 'La sessione sta per scadere'],
|
||||
|
||||
@@ -57,6 +57,7 @@ export const defaultRULocale = [
|
||||
['ui_changes_will_be_lost', 'Ваши изменения будут потеряны'],
|
||||
['ui_continue', 'Продолжить'],
|
||||
['ui_authentication', 'Аутентификация'],
|
||||
['ui_settings', 'Настройки'],
|
||||
|
||||
['root_permission_denied', 'Отказано в доступе'],
|
||||
['root_permission_no_permission', 'У вас нет разрешения на это действие'],
|
||||
|
||||
@@ -1,73 +1,74 @@
|
||||
export const defaultZHLocale = [
|
||||
['name', 'zh'],
|
||||
['ui_tag_new', '新建'],
|
||||
['ui_light_theme', '明亮'],
|
||||
['ui_dark_theme', '黑暗'],
|
||||
['ui_stepper_back', '返回'],
|
||||
['ui_stepper_next', '下一步'],
|
||||
['ui_stepper_finish', '完成'],
|
||||
['ui_processing_loading', '加载中...'],
|
||||
['ui_processing_cancel', '取消'],
|
||||
['ui_processing_canceling', '取消中...'],
|
||||
['ui_processing_retry', '重试'],
|
||||
['ui_processing_ok', '好'],
|
||||
['ui_processing_create', '创建'],
|
||||
['ui_processing_save', '保存'],
|
||||
['ui_configure', '配置'],
|
||||
['ui_apply', '应用'],
|
||||
['ui_error_message', '错误:'],
|
||||
['ui_error_close', '关闭'],
|
||||
['ui_close', '关闭'],
|
||||
['ui_errors_details', '详情'],
|
||||
['ui_search', '搜索...'],
|
||||
['ui_delete', '删除'],
|
||||
['ui_add', '添加'],
|
||||
['ui_refresh', '刷新'],
|
||||
['ui_data_saving_error', '保存出错'],
|
||||
['ui_data_delete_confirmation', '删除确认'],
|
||||
['ui_no_matches_placeholder', '您的搜索没有返回匹配项。'],
|
||||
['ui_information', '信息'],
|
||||
['ui_clipboard', '剪贴板'],
|
||||
['ui_copy_to_clipboard', '复制'],
|
||||
['ui_copy_to_clipboard_copied', '已复制'],
|
||||
['ui_copy_to_clipboard_failed_to_copy', '复制失败'],
|
||||
['ui_clipboard_access_denied_title', '剪贴板访问被拒绝'],
|
||||
['ui_clipboard_access_denied_message', '您需要授予对剪贴板的访问权限才能使用某些应用功能'],
|
||||
['ui_reveal_password', '展示或隐藏密码'],
|
||||
['ui_page_not_found', '找不到页面'],
|
||||
['ui_revoke', '撤销'],
|
||||
['ui_grant', '授予'],
|
||||
['ui_edit', '编辑'],
|
||||
['ui_open_in_tab', '在选项卡中打开'],
|
||||
['ui_rename', '重命名'],
|
||||
['ui_rename_processing', '重命名中...'],
|
||||
['ui_name', '名称'],
|
||||
['ui_cant_delete_item', "此项目不能删除"],
|
||||
['ui_no_items_placeholder', '还没有项目'],
|
||||
['ui_search_no_result_placeholder', '没有找到结果'],
|
||||
['ui_save_reminder', '您有未保存的更改'],
|
||||
['ui_yes', '是'],
|
||||
['ui_no', '否'],
|
||||
['ui_select_all', '选择所有'],
|
||||
['ui_reconnect', '重新连接'],
|
||||
['ui_forget', '忘记'],
|
||||
['ui_set', '设置'],
|
||||
['ui_are_you_sure', '您确定吗?'],
|
||||
['ui_options', '选项'],
|
||||
['ui_changes_might_be_lost', '您的更改可能会丢失'],
|
||||
['ui_file', '文件'],
|
||||
['ui_changes_will_be_lost', '您的更改将丢失'],
|
||||
['ui_continue', '继续'],
|
||||
['ui_authentication', '认证'],
|
||||
['name', 'zh'],
|
||||
['ui_tag_new', '新建'],
|
||||
['ui_light_theme', '明亮'],
|
||||
['ui_dark_theme', '黑暗'],
|
||||
['ui_stepper_back', '返回'],
|
||||
['ui_stepper_next', '下一步'],
|
||||
['ui_stepper_finish', '完成'],
|
||||
['ui_processing_loading', '加载中...'],
|
||||
['ui_processing_cancel', '取消'],
|
||||
['ui_processing_canceling', '取消中...'],
|
||||
['ui_processing_retry', '重试'],
|
||||
['ui_processing_ok', '好'],
|
||||
['ui_processing_create', '创建'],
|
||||
['ui_processing_save', '保存'],
|
||||
['ui_configure', '配置'],
|
||||
['ui_apply', '应用'],
|
||||
['ui_error_message', '错误:'],
|
||||
['ui_error_close', '关闭'],
|
||||
['ui_close', '关闭'],
|
||||
['ui_errors_details', '详情'],
|
||||
['ui_search', '搜索...'],
|
||||
['ui_delete', '删除'],
|
||||
['ui_add', '添加'],
|
||||
['ui_refresh', '刷新'],
|
||||
['ui_data_saving_error', '保存出错'],
|
||||
['ui_data_delete_confirmation', '删除确认'],
|
||||
['ui_no_matches_placeholder', '您的搜索没有返回匹配项。'],
|
||||
['ui_information', '信息'],
|
||||
['ui_clipboard', '剪贴板'],
|
||||
['ui_copy_to_clipboard', '复制'],
|
||||
['ui_copy_to_clipboard_copied', '已复制'],
|
||||
['ui_copy_to_clipboard_failed_to_copy', '复制失败'],
|
||||
['ui_clipboard_access_denied_title', '剪贴板访问被拒绝'],
|
||||
['ui_clipboard_access_denied_message', '您需要授予对剪贴板的访问权限才能使用某些应用功能'],
|
||||
['ui_reveal_password', '展示或隐藏密码'],
|
||||
['ui_page_not_found', '找不到页面'],
|
||||
['ui_revoke', '撤销'],
|
||||
['ui_grant', '授予'],
|
||||
['ui_edit', '编辑'],
|
||||
['ui_open_in_tab', '在选项卡中打开'],
|
||||
['ui_rename', '重命名'],
|
||||
['ui_rename_processing', '重命名中...'],
|
||||
['ui_name', '名称'],
|
||||
['ui_cant_delete_item', "此项目不能删除"],
|
||||
['ui_no_items_placeholder', '还没有项目'],
|
||||
['ui_search_no_result_placeholder', '没有找到结果'],
|
||||
['ui_save_reminder', '您有未保存的更改'],
|
||||
['ui_yes', '是'],
|
||||
['ui_no', '否'],
|
||||
['ui_select_all', '选择所有'],
|
||||
['ui_reconnect', '重新连接'],
|
||||
['ui_forget', '忘记'],
|
||||
['ui_set', '设置'],
|
||||
['ui_are_you_sure', '您确定吗?'],
|
||||
['ui_options', '选项'],
|
||||
['ui_changes_might_be_lost', '您的更改可能会丢失'],
|
||||
['ui_file', '文件'],
|
||||
['ui_changes_will_be_lost', '您的更改将丢失'],
|
||||
['ui_continue', '继续'],
|
||||
['ui_authentication', '认证'],
|
||||
['ui_settings', 'Settings'],
|
||||
|
||||
['root_permission_denied', "您没有权限"],
|
||||
['root_permission_no_permission', "您没有权限执行此操作"],
|
||||
['app_root_session_expire_warning_title', '会话即将过期'],
|
||||
['app_root_session_expire_warning_message', '您的会话将在5分钟内到期。要继续工作,请关闭此弹出窗口。'],
|
||||
['app_root_session_expire_warning_button', '我在'],
|
||||
['app_root_session_expired_title', '会话已过期'],
|
||||
['app_root_session_expired_message', '会话已过期。您想重新加载吗?'],
|
||||
['app_root_session_expired_reload', '重新加载'],
|
||||
['app_root_quota_exceeded', '超出配额'],
|
||||
['core_eventsLog_dbeaverErrorDetails', '错误详情'],
|
||||
];
|
||||
['root_permission_denied', "您没有权限"],
|
||||
['root_permission_no_permission', "您没有权限执行此操作"],
|
||||
['app_root_session_expire_warning_title', '会话即将过期'],
|
||||
['app_root_session_expire_warning_message', '您的会话将在5分钟内到期。要继续工作,请关闭此弹出窗口。'],
|
||||
['app_root_session_expire_warning_button', '我在'],
|
||||
['app_root_session_expired_title', '会话已过期'],
|
||||
['app_root_session_expired_message', '会话已过期。您想重新加载吗?'],
|
||||
['app_root_session_expired_reload', '重新加载'],
|
||||
['app_root_quota_exceeded', '超出配额'],
|
||||
['core_eventsLog_dbeaverErrorDetails', '错误详情'],
|
||||
];
|
||||
|
||||
@@ -18,8 +18,7 @@ import { DbeaverError, NotificationService } from '@cloudbeaver/core-events';
|
||||
import { SettingsService } from '@cloudbeaver/core-settings';
|
||||
|
||||
import { themes } from './themes';
|
||||
import { defaultThemeSettings } from './ThemeSettingsService';
|
||||
import { ThemeSettingsService } from './ThemeSettingsService';
|
||||
import { defaultThemeSettings, ThemeSettingsService } from './ThemeSettingsService';
|
||||
import type { ClassCollection } from './themeUtils';
|
||||
|
||||
const COMMON_STYLES: any[] = [];
|
||||
@@ -82,11 +81,10 @@ export class ThemeService extends Bootstrap {
|
||||
});
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.loadAllThemes();
|
||||
}
|
||||
register(): void { }
|
||||
|
||||
async load(): Promise<void> {
|
||||
this.loadAllThemes();
|
||||
this.setCurrentThemeId(this.defaultThemeId);
|
||||
this.settingsService.registerSettings(this.settings, THEME_SETTINGS_KEY);
|
||||
await this.changeThemeAsync(this.currentThemeId);
|
||||
|
||||
@@ -8,21 +8,29 @@
|
||||
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useCallback } from 'react';
|
||||
import { MenuSeparator } from 'reakit';
|
||||
import { MenuInitialState, MenuSeparator } from 'reakit';
|
||||
import styled, { use } from 'reshadow';
|
||||
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { useStyles, ComponentStyle } from '@cloudbeaver/core-theming';
|
||||
import { IMenuActionItem, IMenuData, IMenuItem, MenuActionItem, MenuBaseItem, MenuSeparatorItem } from '@cloudbeaver/core-view';
|
||||
import { DATA_CONTEXT_MENU_NESTED, IMenuActionItem, IMenuData, IMenuItem, MenuActionItem, MenuBaseItem, MenuSeparatorItem, MenuService, MenuSubMenuItem, useMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
import { ContextMenu } from '../MenuTrigger';
|
||||
import { MenuBarItem } from './MenuBarItem';
|
||||
|
||||
interface INestedMenuSettings extends MenuInitialState {
|
||||
onVisibleSwitch?: (visible: boolean) => void;
|
||||
}
|
||||
|
||||
interface IMenuBarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'style'> {
|
||||
menu: IMenuData;
|
||||
nestedMenuSettings?: INestedMenuSettings;
|
||||
style?: ComponentStyle;
|
||||
}
|
||||
|
||||
export const MenuBar = observer<IMenuBarProps, HTMLDivElement>(function MenuBar({
|
||||
menu,
|
||||
nestedMenuSettings,
|
||||
style,
|
||||
...props
|
||||
}, ref) {
|
||||
@@ -40,6 +48,7 @@ export const MenuBar = observer<IMenuBarProps, HTMLDivElement>(function MenuBar(
|
||||
key={item.id}
|
||||
item={item}
|
||||
menuData={menu}
|
||||
nestedMenuSettings={nestedMenuSettings}
|
||||
style={style}
|
||||
/>
|
||||
))}
|
||||
@@ -50,16 +59,33 @@ export const MenuBar = observer<IMenuBarProps, HTMLDivElement>(function MenuBar(
|
||||
interface IMenuBarElementProps {
|
||||
item: IMenuItem;
|
||||
menuData: IMenuData;
|
||||
nestedMenuSettings?: INestedMenuSettings;
|
||||
style?: ComponentStyle;
|
||||
}
|
||||
|
||||
const MenuBarElement = observer<IMenuBarElementProps>(function MenuBarElement({ item, style }) {
|
||||
const MenuBarElement = observer<IMenuBarElementProps>(function MenuBarElement({
|
||||
item,
|
||||
menuData,
|
||||
nestedMenuSettings,
|
||||
style
|
||||
}) {
|
||||
const styles = useStyles(style);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
item.events?.onSelect?.();
|
||||
}, [item]);
|
||||
|
||||
if (item instanceof MenuSubMenuItem) {
|
||||
return styled(styles)(
|
||||
<SubMenuItem
|
||||
item={item}
|
||||
menuData={menuData}
|
||||
style={style}
|
||||
nestedMenuSettings={nestedMenuSettings}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (item instanceof MenuSeparatorItem) {
|
||||
return styled(styles)(
|
||||
<MenuSeparator />
|
||||
@@ -127,3 +153,48 @@ const MenuBarAction = observer<IMenuBarActionProps>(function MenuBarAction({ ite
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
interface ISubMenuItemProps {
|
||||
item: MenuSubMenuItem;
|
||||
menuData: IMenuData;
|
||||
nestedMenuSettings?: INestedMenuSettings;
|
||||
style?: ComponentStyle;
|
||||
}
|
||||
|
||||
const SubMenuItem = observer<ISubMenuItemProps>(function SubmenuItem({
|
||||
item,
|
||||
menuData,
|
||||
nestedMenuSettings,
|
||||
style
|
||||
}) {
|
||||
const styles = useStyles(style);
|
||||
const menuService = useService(MenuService);
|
||||
const subMenuData = useMenu(item.menu, menuData.context);
|
||||
|
||||
const handler = menuService.getHandler(menuData.context);
|
||||
const loading = handler?.isLoading?.(menuData.context);
|
||||
const disabled = handler?.isDisabled?.(menuData.context);
|
||||
|
||||
subMenuData.context.set(DATA_CONTEXT_MENU_NESTED, true);
|
||||
|
||||
return styled(styles)(
|
||||
<ContextMenu
|
||||
menu={subMenuData}
|
||||
style={style}
|
||||
disclosure
|
||||
{...nestedMenuSettings}
|
||||
>
|
||||
<MenuBarItem
|
||||
id={item.id}
|
||||
aria-label={item.menu.label}
|
||||
label={item.menu.label}
|
||||
icon={item.menu.icon}
|
||||
title={item.menu.tooltip || item.menu.label}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
style={style}
|
||||
{...use({ hidden: item.hidden })}
|
||||
/>
|
||||
</ContextMenu>
|
||||
);
|
||||
});
|
||||
@@ -22,22 +22,23 @@ interface Props extends Omit<React.DetailedHTMLProps<ButtonHTMLAttributes<HTMLBu
|
||||
style?: ComponentStyle;
|
||||
}
|
||||
|
||||
export const MenuBarItem = observer<Props>(function MenuBarItem({
|
||||
export const MenuBarItem = observer<Props, HTMLButtonElement>(function MenuBarItem({
|
||||
label,
|
||||
loading = false,
|
||||
icon,
|
||||
viewBox = '0 0 24 24',
|
||||
style = [],
|
||||
...rest
|
||||
}) {
|
||||
}, ref) {
|
||||
const translate = useTranslate();
|
||||
loading = useStateDelay(loading, 100);
|
||||
|
||||
const title = translate(rest.title);
|
||||
return styled(useStyles(style))(
|
||||
<menu-bar-item as='button' {...rest} title={translate(rest.title)}>
|
||||
<menu-bar-item as='button' ref={ref} {...rest} title={title} aria-label={title}>
|
||||
{loading && <Loader small fullSize />}
|
||||
{!loading && icon && <IconOrImage icon={icon} viewBox={viewBox} />}
|
||||
{label && <item-label><Translate token={label} /></item-label>}
|
||||
</menu-bar-item>
|
||||
);
|
||||
});
|
||||
}, { forwardRef: true });
|
||||
|
||||
@@ -40,7 +40,7 @@ export const MenuPanelItem = observer<MenuPanelItemProps>(function MenuPanelItem
|
||||
loading = useStateDelay(loading, 100);
|
||||
|
||||
return styled(useStyles(menuPanelStyles, style))(
|
||||
<menu-panel-item title={tooltip}>
|
||||
<menu-panel-item title={tooltip ? translate(tooltip) : title}>
|
||||
<menu-item-content>
|
||||
{typeof icon === 'string' ? <IconOrImage icon={icon} /> : icon}
|
||||
</menu-item-content>
|
||||
|
||||
@@ -11,20 +11,27 @@ import type { IMenuItemEvents } from './IMenuItem';
|
||||
import { MenuItem } from './MenuItem';
|
||||
|
||||
export class MenuBaseItem extends MenuItem implements IMenuBaseItem {
|
||||
private readonly isDisabled?: () => boolean;
|
||||
|
||||
readonly label: string;
|
||||
readonly icon?: string;
|
||||
readonly tooltip?: string;
|
||||
readonly hidden?: boolean;
|
||||
readonly disabled?: boolean;
|
||||
|
||||
get disabled(): boolean {
|
||||
return this.isDisabled?.() ?? false;
|
||||
}
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
tooltip?: string,
|
||||
events?: IMenuItemEvents
|
||||
events?: IMenuItemEvents,
|
||||
isDisabled?: () => boolean
|
||||
) {
|
||||
super(id, events);
|
||||
this.label = label;
|
||||
this.tooltip = tooltip;
|
||||
this.isDisabled = isDisabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,45 +7,67 @@
|
||||
*/
|
||||
|
||||
import { EAdminPermission, AdministrationScreenService } from '@cloudbeaver/core-administration';
|
||||
import { SettingsMenuService } from '@cloudbeaver/core-app';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { PermissionsService } from '@cloudbeaver/core-root';
|
||||
import { ScreenService } from '@cloudbeaver/core-routing';
|
||||
import { DATA_CONTEXT_MENU, MenuBaseItem, MenuService } from '@cloudbeaver/core-view';
|
||||
import { TOP_NAV_BAR_SETTINGS_MENU } from '@cloudbeaver/plugin-settings-menu';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private settingsMenuService: SettingsMenuService,
|
||||
private permissionsService: PermissionsService,
|
||||
private screenService: ScreenService,
|
||||
private administrationScreenService: AdministrationScreenService,
|
||||
private readonly permissionsService: PermissionsService,
|
||||
private readonly screenService: ScreenService,
|
||||
private readonly administrationScreenService: AdministrationScreenService,
|
||||
private readonly menuService: MenuService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.settingsMenuService.addMenuItem(
|
||||
SettingsMenuService.settingsMenuToken,
|
||||
{
|
||||
id: 'administrationMenuEnter',
|
||||
order: 0,
|
||||
isHidden: () => !this.permissionsService.has(EAdminPermission.admin)
|
||||
|| this.screenService.isActive(AdministrationScreenService.screenName),
|
||||
title: 'administration_menu_enter',
|
||||
onClick: () => this.administrationScreenService.navigateToRoot(),
|
||||
this.menuService.addCreator({
|
||||
isApplicable: (context) => context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU,
|
||||
getItems: (context, items) => {
|
||||
const administrationScreen = this.screenService.isActive(AdministrationScreenService.screenName);
|
||||
|
||||
if (this.permissionsService.has(EAdminPermission.admin) && !administrationScreen) {
|
||||
return [
|
||||
...items,
|
||||
new MenuBaseItem(
|
||||
'administrationMenuEnter',
|
||||
'administration_menu_enter',
|
||||
'administration_menu_enter',
|
||||
{ onSelect: () => this.administrationScreenService.navigateToRoot() }
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
if (administrationScreen) {
|
||||
return [
|
||||
...items,
|
||||
new MenuBaseItem(
|
||||
'administrationMenuBack',
|
||||
'administration_menu_back',
|
||||
'administration_menu_back',
|
||||
{ onSelect: () => this.screenService.navigateToRoot() }
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
orderItems: (context, items) => {
|
||||
const index = items.findIndex(item => item.id === 'administrationMenuBack' || item.id === 'administrationMenuEnter');
|
||||
|
||||
if (index > -1) {
|
||||
const item = items.splice(index, 1);
|
||||
items.unshift(item[0]);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
);
|
||||
this.settingsMenuService.addMenuItem(
|
||||
SettingsMenuService.settingsMenuToken,
|
||||
{
|
||||
id: 'administrationMenuBack',
|
||||
order: 0,
|
||||
isHidden: () => !this.screenService.isActive(AdministrationScreenService.screenName),
|
||||
title: 'administration_menu_back',
|
||||
onClick: () => this.screenService.navigateToRoot(),
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
load(): void {}
|
||||
load(): void { }
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { SettingsMenuService } from '@cloudbeaver/core-app';
|
||||
import { AuthInfoService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable, Bootstrap } from '@cloudbeaver/core-di';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { DATA_CONTEXT_MENU, MenuBaseItem, MenuService } from '@cloudbeaver/core-view';
|
||||
import { TOP_NAV_BAR_SETTINGS_MENU } from '@cloudbeaver/plugin-settings-menu';
|
||||
|
||||
import { AuthenticationService } from './AuthenticationService';
|
||||
import { AuthDialogService } from './Dialog/AuthDialogService';
|
||||
@@ -21,33 +22,52 @@ export class PluginBootstrap extends Bootstrap {
|
||||
private readonly authDialogService: AuthDialogService,
|
||||
private readonly authenticationService: AuthenticationService,
|
||||
private readonly authInfoService: AuthInfoService,
|
||||
private readonly settingsMenuService: SettingsMenuService,
|
||||
private readonly menuService: MenuService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.settingsMenuService.addMenuItem(
|
||||
SettingsMenuService.settingsMenuToken,
|
||||
{
|
||||
id: 'login',
|
||||
order: 0,
|
||||
isHidden: () => this.serverConfigResource.enabledAuthProviders.length === 0 || !!this.authInfoService.userInfo,
|
||||
title: 'authentication_login',
|
||||
onClick: () => this.authDialogService.showLoginForm(false, null, true),
|
||||
}
|
||||
);
|
||||
this.menuService.addCreator({
|
||||
isApplicable: (context) => context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU,
|
||||
getItems: (context, items) => {
|
||||
if (this.serverConfigResource.enabledAuthProviders.length > 0 && !this.authInfoService.userInfo) {
|
||||
return [
|
||||
...items,
|
||||
new MenuBaseItem(
|
||||
'login',
|
||||
'authentication_login',
|
||||
'authentication_login',
|
||||
{ onSelect: () => this.authDialogService.showLoginForm(false, null, true) }
|
||||
)
|
||||
]
|
||||
};
|
||||
|
||||
this.settingsMenuService.addMenuItem(
|
||||
SettingsMenuService.settingsMenuToken,
|
||||
{
|
||||
id: 'logout',
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
isHidden: () => !this.authInfoService.userInfo,
|
||||
title: 'authentication_logout',
|
||||
onClick: this.authenticationService.logout.bind(this.authenticationService),
|
||||
if (this.authInfoService.userInfo) {
|
||||
return [
|
||||
...items,
|
||||
new MenuBaseItem(
|
||||
'logout',
|
||||
'authentication_logout',
|
||||
'authentication_logout',
|
||||
{ onSelect: this.authenticationService.logout.bind(this.authenticationService) }
|
||||
)
|
||||
]
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
orderItems: (context, items) => {
|
||||
const index = items.findIndex(item => item.id === 'logout' || item.id === 'login')
|
||||
|
||||
if (index > -1) {
|
||||
const item = items.splice(index, 1);
|
||||
items.push(item[0]);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/lib
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env*
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "@cloudbeaver/plugin-localization",
|
||||
"sideEffects": false,
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"license": "Apache-2.0",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.js",
|
||||
"types": "src/index.ts",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf lib/*",
|
||||
"build": "webpack --config ../../configs/webpack.plugin.config.js",
|
||||
"postbuild": "tsc",
|
||||
"lint": "eslint ./src/ --ext .ts,.tsx",
|
||||
"lint-fix": "eslint ./src/ --ext .ts,.tsx --fix"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cloudbeaver/core-administration": "^0.1.0",
|
||||
"@cloudbeaver/core-app": "^0.1.0",
|
||||
"@cloudbeaver/core-authentication": "^0.1.0",
|
||||
"@cloudbeaver/core-blocks": "^0.1.0",
|
||||
"@cloudbeaver/core-connections": "^0.1.0",
|
||||
"@cloudbeaver/core-di": "^0.1.0",
|
||||
"@cloudbeaver/core-dialogs": "^0.1.0",
|
||||
"@cloudbeaver/core-events": "^0.1.0",
|
||||
"@cloudbeaver/core-executor": "^0.1.0",
|
||||
"@cloudbeaver/core-extensions": "^0.1.0",
|
||||
"@cloudbeaver/core-localization": "^0.1.0",
|
||||
"@cloudbeaver/core-notifications": "^0.1.0",
|
||||
"@cloudbeaver/core-plugin": "^0.1.0",
|
||||
"@cloudbeaver/core-product": "^0.1.0",
|
||||
"@cloudbeaver/core-root": "^0.1.0",
|
||||
"@cloudbeaver/core-routing": "^0.1.0",
|
||||
"@cloudbeaver/core-sdk": "^0.1.0",
|
||||
"@cloudbeaver/core-settings": "^0.1.0",
|
||||
"@cloudbeaver/core-theming": "^0.1.0",
|
||||
"@cloudbeaver/core-ui": "^0.1.0",
|
||||
"@cloudbeaver/core-utils": "^0.1.0",
|
||||
"@cloudbeaver/core-view": "^0.1.0",
|
||||
"@cloudbeaver/plugin-settings-menu": "^0.1.0",
|
||||
"react": "^17.x.x",
|
||||
"mobx": "^6.x.x",
|
||||
"mobx-react-lite": "^3.x.x",
|
||||
"reshadow": "^0.x.x"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 { createMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
export const LOCALIZATION_MENU = createMenu('localization-menu', 'app_shared_settingsMenu_lang');
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { LocalizationService } from '@cloudbeaver/core-localization';
|
||||
import { DATA_CONTEXT_MENU, MenuBaseItem, MenuService } from '@cloudbeaver/core-view';
|
||||
import { TOP_NAV_BAR_SETTINGS_MENU } from '@cloudbeaver/plugin-settings-menu';
|
||||
|
||||
import { LOCALIZATION_MENU } from './LOCALIZATION_MENU';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly localizationService: LocalizationService,
|
||||
private readonly menuService: MenuService,
|
||||
private readonly serverConfigResource: ServerConfigResource
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.menuService.setHandler({
|
||||
id: 'localization-menu',
|
||||
isApplicable: (context) => context.get(DATA_CONTEXT_MENU) === LOCALIZATION_MENU,
|
||||
isLoading: () => this.serverConfigResource.isLoading(),
|
||||
handler: () => this.serverConfigResource.load(),
|
||||
})
|
||||
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => {
|
||||
return context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU && !!this.serverConfigResource.data?.supportedLanguages.length
|
||||
},
|
||||
getItems(context, items) {
|
||||
return [
|
||||
...items,
|
||||
LOCALIZATION_MENU
|
||||
]
|
||||
},
|
||||
});
|
||||
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.get(DATA_CONTEXT_MENU) === LOCALIZATION_MENU,
|
||||
getItems: (context, items) => {
|
||||
const supportedLanguages = this.serverConfigResource.data?.supportedLanguages;
|
||||
|
||||
if (!supportedLanguages?.length) {
|
||||
return items;
|
||||
}
|
||||
|
||||
const languages = supportedLanguages.map(lang => {
|
||||
const label = lang.nativeName || lang.isoCode;
|
||||
|
||||
return new MenuBaseItem(
|
||||
lang.isoCode,
|
||||
label,
|
||||
label,
|
||||
{ onSelect: () => this.localizationService.changeLocaleAsync(lang.isoCode) },
|
||||
() => this.localizationService.getCurrentLanguage() === lang.isoCode
|
||||
)
|
||||
})
|
||||
|
||||
return [
|
||||
...items,
|
||||
...languages
|
||||
]
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { localizationPlugin } from './manifest';
|
||||
|
||||
export default localizationPlugin;
|
||||
|
||||
export * from './LOCALIZATION_MENU';
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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 type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
import { PluginBootstrap } from './PluginBootstrap';
|
||||
|
||||
export const localizationPlugin: PluginManifest = {
|
||||
info: { name: 'Localization plugin' },
|
||||
providers: [
|
||||
PluginBootstrap,
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"composite": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules",
|
||||
"**/.*/"
|
||||
],
|
||||
}
|
||||
+7
-1
@@ -54,6 +54,12 @@ const itemStyles = css`
|
||||
menu-icon {
|
||||
padding-right: 8px;
|
||||
}
|
||||
menu-name {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 500px;
|
||||
}
|
||||
TableColumnValue:not(:hover):not([|menuOpened]) {
|
||||
& Icon {
|
||||
opacity: 0;
|
||||
@@ -185,7 +191,7 @@ const ItemName = observer<IItemNameProps>(function ItemName({
|
||||
<menu-icon><Icon name="snack" viewBox="0 0 16 10" /></menu-icon>
|
||||
</ContextMenu>
|
||||
)}
|
||||
<menu-name>{name}</menu-name>
|
||||
<menu-name title={name}>{name}</menu-name>
|
||||
</menu-box>
|
||||
</TableColumnValue>
|
||||
);
|
||||
|
||||
@@ -6,36 +6,40 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { SettingsMenuService } from '@cloudbeaver/core-app';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
|
||||
import { DATA_CONTEXT_MENU, MenuBaseItem, MenuService } from '@cloudbeaver/core-view';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { TOP_NAV_BAR_SETTINGS_MENU } from '@cloudbeaver/plugin-settings-menu';
|
||||
|
||||
import { ProductInfoDialog } from './ProductInfoDialog';
|
||||
|
||||
@injectable()
|
||||
export class ProductBootstrap extends Bootstrap {
|
||||
private productInfoMenuToken = 'productInfoMenu';
|
||||
|
||||
constructor(
|
||||
private settingsMenuService: SettingsMenuService,
|
||||
private serverConfigResource: ServerConfigResource,
|
||||
private commonDialogService: CommonDialogService
|
||||
private readonly serverConfigResource: ServerConfigResource,
|
||||
private readonly commonDialogService: CommonDialogService,
|
||||
private readonly menuService: MenuService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.settingsMenuService.addMenuItem(
|
||||
SettingsMenuService.settingsMenuToken,
|
||||
{
|
||||
id: this.productInfoMenuToken,
|
||||
order: 3,
|
||||
title: 'app_product_info',
|
||||
isHidden: () => !this.serverConfigResource.data?.productInfo,
|
||||
onClick: async () => await this.commonDialogService.open(ProductInfoDialog, null),
|
||||
}
|
||||
);
|
||||
this.menuService.addCreator({
|
||||
isApplicable: (context) => {
|
||||
return context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU && !!this.serverConfigResource.data?.productInfo
|
||||
},
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
new MenuBaseItem(
|
||||
'productInfo',
|
||||
'app_product_info',
|
||||
'app_product_info',
|
||||
{ onSelect: () => this.commonDialogService.open(ProductInfoDialog, null) }
|
||||
)
|
||||
]
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/lib
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env*
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "@cloudbeaver/plugin-settings-menu-administration",
|
||||
"sideEffects": false,
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"license": "Apache-2.0",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.js",
|
||||
"types": "src/index.ts",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf lib/*",
|
||||
"build": "webpack --config ../../configs/webpack.plugin.config.js",
|
||||
"postbuild": "tsc",
|
||||
"lint": "eslint ./src/ --ext .ts,.tsx",
|
||||
"lint-fix": "eslint ./src/ --ext .ts,.tsx --fix"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cloudbeaver/core-administration": "^0.1.0",
|
||||
"@cloudbeaver/core-app": "^0.1.0",
|
||||
"@cloudbeaver/core-authentication": "^0.1.0",
|
||||
"@cloudbeaver/core-blocks": "^0.1.0",
|
||||
"@cloudbeaver/core-connections": "^0.1.0",
|
||||
"@cloudbeaver/core-di": "^0.1.0",
|
||||
"@cloudbeaver/core-dialogs": "^0.1.0",
|
||||
"@cloudbeaver/core-events": "^0.1.0",
|
||||
"@cloudbeaver/core-executor": "^0.1.0",
|
||||
"@cloudbeaver/core-extensions": "^0.1.0",
|
||||
"@cloudbeaver/core-localization": "^0.1.0",
|
||||
"@cloudbeaver/core-notifications": "^0.1.0",
|
||||
"@cloudbeaver/core-plugin": "^0.1.0",
|
||||
"@cloudbeaver/core-product": "^0.1.0",
|
||||
"@cloudbeaver/core-root": "^0.1.0",
|
||||
"@cloudbeaver/core-routing": "^0.1.0",
|
||||
"@cloudbeaver/core-sdk": "^0.1.0",
|
||||
"@cloudbeaver/core-settings": "^0.1.0",
|
||||
"@cloudbeaver/core-theming": "^0.1.0",
|
||||
"@cloudbeaver/core-ui": "^0.1.0",
|
||||
"@cloudbeaver/core-utils": "^0.1.0",
|
||||
"@cloudbeaver/core-view": "^0.1.0",
|
||||
"@cloudbeaver/plugin-settings-menu": "^0.1.0",
|
||||
"react": "^17.x.x",
|
||||
"mobx": "^6.x.x",
|
||||
"mobx-react-lite": "^3.x.x",
|
||||
"reshadow": "^0.x.x"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 { AdministrationTopAppBarService } from '@cloudbeaver/core-administration';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { SettingsMenu } from '@cloudbeaver/plugin-settings-menu';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly administrationTopAppBarService: AdministrationTopAppBarService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.administrationTopAppBarService.placeholder.add(SettingsMenu, 5);
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { settingsMenuAdministrationPlugin } from './manifest';
|
||||
|
||||
export default settingsMenuAdministrationPlugin;
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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 type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
import { PluginBootstrap } from './PluginBootstrap';
|
||||
|
||||
export const settingsMenuAdministrationPlugin: PluginManifest = {
|
||||
info: { name: 'Settings menu administration plugin' },
|
||||
providers: [
|
||||
PluginBootstrap,
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"composite": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules",
|
||||
"**/.*/"
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/lib
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env*
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@cloudbeaver/plugin-settings-menu",
|
||||
"sideEffects": false,
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"license": "Apache-2.0",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.js",
|
||||
"types": "src/index.ts",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf lib/*",
|
||||
"build": "webpack --config ../../configs/webpack.plugin.config.js",
|
||||
"postbuild": "tsc",
|
||||
"lint": "eslint ./src/ --ext .ts,.tsx",
|
||||
"lint-fix": "eslint ./src/ --ext .ts,.tsx --fix"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cloudbeaver/core-administration": "^0.1.0",
|
||||
"@cloudbeaver/core-app": "^0.1.0",
|
||||
"@cloudbeaver/core-authentication": "^0.1.0",
|
||||
"@cloudbeaver/core-blocks": "^0.1.0",
|
||||
"@cloudbeaver/core-connections": "^0.1.0",
|
||||
"@cloudbeaver/core-di": "^0.1.0",
|
||||
"@cloudbeaver/core-dialogs": "^0.1.0",
|
||||
"@cloudbeaver/core-events": "^0.1.0",
|
||||
"@cloudbeaver/core-executor": "^0.1.0",
|
||||
"@cloudbeaver/core-extensions": "^0.1.0",
|
||||
"@cloudbeaver/core-localization": "^0.1.0",
|
||||
"@cloudbeaver/core-notifications": "^0.1.0",
|
||||
"@cloudbeaver/core-plugin": "^0.1.0",
|
||||
"@cloudbeaver/core-product": "^0.1.0",
|
||||
"@cloudbeaver/core-root": "^0.1.0",
|
||||
"@cloudbeaver/core-routing": "^0.1.0",
|
||||
"@cloudbeaver/core-sdk": "^0.1.0",
|
||||
"@cloudbeaver/core-settings": "^0.1.0",
|
||||
"@cloudbeaver/core-theming": "^0.1.0",
|
||||
"@cloudbeaver/core-ui": "^0.1.0",
|
||||
"@cloudbeaver/core-utils": "^0.1.0",
|
||||
"@cloudbeaver/core-view": "^0.1.0",
|
||||
"react": "^17.x.x",
|
||||
"mobx": "^6.x.x",
|
||||
"mobx-react-lite": "^3.x.x",
|
||||
"reshadow": "^0.x.x"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 { TopNavService } from '@cloudbeaver/core-app';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { SettingsMenu } from './SettingsMenu/SettingsMenu';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly topNavService: TopNavService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.topNavService.placeholder.add(SettingsMenu, 5);
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
}
|
||||
+15
-9
@@ -9,21 +9,27 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { Icon } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { MenuTrigger } from '@cloudbeaver/core-dialogs';
|
||||
import { useStyles } from '@cloudbeaver/core-theming';
|
||||
import { ContextMenu } from '@cloudbeaver/core-ui';
|
||||
import { useMenu } from '@cloudbeaver/core-view';
|
||||
import { Icon } from '@cloudbeaver/core-blocks';
|
||||
import { topMenuStyles } from '@cloudbeaver/core-app';
|
||||
|
||||
import { topMenuStyles } from '../shared/topMenuStyles';
|
||||
import { SettingsMenuService } from './SettingsMenuService';
|
||||
import { settingsMenuStyles } from './settingsMenuStyles';
|
||||
import { TOP_NAV_BAR_SETTINGS_MENU } from './TOP_NAV_BAR_SETTINGS_MENU';
|
||||
|
||||
export const SettingsMenu = observer(function SettingsMenu() {
|
||||
const settingsMenuService = useService(SettingsMenuService);
|
||||
const menu = useMenu(TOP_NAV_BAR_SETTINGS_MENU);
|
||||
|
||||
return styled(useStyles(settingsMenuStyles))(
|
||||
<MenuTrigger panel={settingsMenuService.getMenu()} style={[topMenuStyles, settingsMenuStyles]} placement='bottom-end' modal rtl>
|
||||
<ContextMenu
|
||||
menu={menu}
|
||||
style={[topMenuStyles, settingsMenuStyles]}
|
||||
placement='bottom-end'
|
||||
modal
|
||||
rtl
|
||||
>
|
||||
<Icon name="settings" viewBox="0 0 28 28" />
|
||||
</MenuTrigger>
|
||||
</ContextMenu>
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 { createMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
export const TOP_NAV_BAR_SETTINGS_MENU = createMenu('top-nav-bar-settings', 'ui_settings', 'settings', 'ui_settings');
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
import { css } from 'reshadow';
|
||||
|
||||
export const settingsMenuStyles = css`
|
||||
MenuTrigger {
|
||||
ContextMenu {
|
||||
padding: 0 16px !important;
|
||||
height: 48px;
|
||||
cursor: pointer;
|
||||
@@ -33,4 +33,4 @@ export const settingsMenuStyles = css`
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
`;
|
||||
`;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { settingsMenuPlugin } from './manifest';
|
||||
|
||||
export default settingsMenuPlugin;
|
||||
|
||||
export * from './SettingsMenu/SettingsMenu';
|
||||
export * from './SettingsMenu/TOP_NAV_BAR_SETTINGS_MENU';
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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 type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
import { PluginBootstrap } from './PluginBootstrap';
|
||||
|
||||
export const settingsMenuPlugin: PluginManifest = {
|
||||
info: { name: 'Settings menu plugin' },
|
||||
providers: [
|
||||
PluginBootstrap,
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"composite": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules",
|
||||
"**/.*/"
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/lib
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env*
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "@cloudbeaver/plugin-theme",
|
||||
"sideEffects": false,
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"license": "Apache-2.0",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.js",
|
||||
"types": "src/index.ts",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf lib/*",
|
||||
"build": "webpack --config ../../configs/webpack.plugin.config.js",
|
||||
"postbuild": "tsc",
|
||||
"lint": "eslint ./src/ --ext .ts,.tsx",
|
||||
"lint-fix": "eslint ./src/ --ext .ts,.tsx --fix"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cloudbeaver/core-administration": "^0.1.0",
|
||||
"@cloudbeaver/core-app": "^0.1.0",
|
||||
"@cloudbeaver/core-authentication": "^0.1.0",
|
||||
"@cloudbeaver/core-blocks": "^0.1.0",
|
||||
"@cloudbeaver/core-connections": "^0.1.0",
|
||||
"@cloudbeaver/core-di": "^0.1.0",
|
||||
"@cloudbeaver/core-dialogs": "^0.1.0",
|
||||
"@cloudbeaver/core-events": "^0.1.0",
|
||||
"@cloudbeaver/core-executor": "^0.1.0",
|
||||
"@cloudbeaver/core-extensions": "^0.1.0",
|
||||
"@cloudbeaver/core-localization": "^0.1.0",
|
||||
"@cloudbeaver/core-notifications": "^0.1.0",
|
||||
"@cloudbeaver/core-plugin": "^0.1.0",
|
||||
"@cloudbeaver/core-product": "^0.1.0",
|
||||
"@cloudbeaver/core-root": "^0.1.0",
|
||||
"@cloudbeaver/core-routing": "^0.1.0",
|
||||
"@cloudbeaver/core-sdk": "^0.1.0",
|
||||
"@cloudbeaver/core-settings": "^0.1.0",
|
||||
"@cloudbeaver/core-theming": "^0.1.0",
|
||||
"@cloudbeaver/core-ui": "^0.1.0",
|
||||
"@cloudbeaver/core-utils": "^0.1.0",
|
||||
"@cloudbeaver/core-view": "^0.1.0",
|
||||
"@cloudbeaver/plugin-settings-menu": "^0.1.0",
|
||||
"react": "^17.x.x",
|
||||
"mobx": "^6.x.x",
|
||||
"mobx-react-lite": "^3.x.x",
|
||||
"reshadow": "^0.x.x"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { ThemeService } from '@cloudbeaver/core-theming';
|
||||
import { DATA_CONTEXT_MENU, MenuBaseItem, MenuService } from '@cloudbeaver/core-view';
|
||||
import { TOP_NAV_BAR_SETTINGS_MENU } from '@cloudbeaver/plugin-settings-menu';
|
||||
|
||||
import { THEME_MENU } from './THEME_MENU';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly menuService: MenuService,
|
||||
private readonly themeService: ThemeService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.menuService.addCreator({
|
||||
isApplicable: (context) => {
|
||||
return context.get(DATA_CONTEXT_MENU) === TOP_NAV_BAR_SETTINGS_MENU && this.themeService.themes.length > 0;
|
||||
},
|
||||
getItems(context, items) {
|
||||
return [
|
||||
...items,
|
||||
THEME_MENU
|
||||
]
|
||||
},
|
||||
});
|
||||
|
||||
this.menuService.addCreator({
|
||||
isApplicable(context) {
|
||||
return context.get(DATA_CONTEXT_MENU) === THEME_MENU
|
||||
},
|
||||
getItems: (context, items) => {
|
||||
const themes = this.themeService.themes.map(theme => new MenuBaseItem(
|
||||
theme.id,
|
||||
theme.name,
|
||||
theme.name,
|
||||
{
|
||||
onSelect: () => this.themeService.changeThemeAsync(theme.id)
|
||||
},
|
||||
() => this.themeService.currentThemeId === theme.id,
|
||||
))
|
||||
|
||||
return [
|
||||
...items,
|
||||
...themes
|
||||
]
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 { createMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
export const THEME_MENU = createMenu('theme-menu', 'app_shared_settingsMenu_theme');
|
||||
@@ -0,0 +1,5 @@
|
||||
import { themePlugin } from './manifest';
|
||||
|
||||
export default themePlugin;
|
||||
|
||||
export * from './THEME_MENU';
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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 type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
import { PluginBootstrap } from './PluginBootstrap';
|
||||
|
||||
export const themePlugin: PluginManifest = {
|
||||
info: { name: 'Theme plugin' },
|
||||
providers: [
|
||||
PluginBootstrap,
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"composite": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules",
|
||||
"**/.*/"
|
||||
],
|
||||
}
|
||||
@@ -22,6 +22,8 @@
|
||||
"@cloudbeaver/core-bootstrap": "0.1.0",
|
||||
"@cloudbeaver/core-di": "0.1.0",
|
||||
"@cloudbeaver/core-product": "0.1.0",
|
||||
"@cloudbeaver/plugin-theme": "0.1.0",
|
||||
"@cloudbeaver/plugin-localization": "0.1.0",
|
||||
"@cloudbeaver/plugin-administration": "0.1.0",
|
||||
"@cloudbeaver/plugin-authentication": "0.1.0",
|
||||
"@cloudbeaver/plugin-authentication-administration": "0.1.0",
|
||||
@@ -35,7 +37,9 @@
|
||||
"@cloudbeaver/plugin-sql-editor": "0.1.0",
|
||||
"@cloudbeaver/plugin-sql-editor-navigation-tab": "0.1.0",
|
||||
"@cloudbeaver/plugin-sql-editor-screen": "0.1.0",
|
||||
"@cloudbeaver/plugin-version-update-administration": "0.1.0"
|
||||
"@cloudbeaver/plugin-version-update-administration": "0.1.0",
|
||||
"@cloudbeaver/plugin-settings-menu": "0.1.0",
|
||||
"@cloudbeaver/plugin-settings-menu-administration": "0.1.0"
|
||||
},
|
||||
"product": {
|
||||
"name": "CloudBeaver Community"
|
||||
|
||||
@@ -5,6 +5,8 @@ import type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
import administration from '@cloudbeaver/plugin-administration';
|
||||
import authentication from '@cloudbeaver/plugin-authentication';
|
||||
import authenticationAdministration from '@cloudbeaver/plugin-authentication-administration';
|
||||
import theme from '@cloudbeaver/plugin-theme';
|
||||
import localization from '@cloudbeaver/plugin-localization';
|
||||
import connectionCustom from '@cloudbeaver/plugin-connection-custom';
|
||||
import connectionTemplate from '@cloudbeaver/plugin-connection-template';
|
||||
import connectionPlugin from '@cloudbeaver/plugin-connections';
|
||||
@@ -22,6 +24,8 @@ import sqlEditorScreen from '@cloudbeaver/plugin-sql-editor-screen';
|
||||
import userProfile from '@cloudbeaver/plugin-user-profile';
|
||||
import userProfileAdministration from '@cloudbeaver/plugin-user-profile-administration';
|
||||
import versionUpdate from '@cloudbeaver/plugin-version-update-administration';
|
||||
import settingsMenu from '@cloudbeaver/plugin-settings-menu';
|
||||
import settingsMenuAdministration from '@cloudbeaver/plugin-settings-menu-administration';
|
||||
|
||||
import { defaultProductManifest } from './manifest';
|
||||
|
||||
@@ -30,6 +34,8 @@ const PLUGINS: PluginManifest[] = [
|
||||
spreadsheetNew,
|
||||
authentication,
|
||||
authenticationAdministration,
|
||||
theme,
|
||||
localization,
|
||||
connectionCustom,
|
||||
connectionTemplate,
|
||||
dataExport,
|
||||
@@ -47,6 +53,8 @@ const PLUGINS: PluginManifest[] = [
|
||||
connectionAdministration,
|
||||
versionUpdate,
|
||||
productPlugin,
|
||||
settingsMenu,
|
||||
settingsMenuAdministration,
|
||||
];
|
||||
|
||||
bootstrap(PLUGINS);
|
||||
|
||||
Reference in New Issue
Block a user