mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-2647 refactor: use new context menu API for top app bar
This commit is contained in:
@@ -1,11 +1,4 @@
|
||||
export default [
|
||||
['app_shared_connectionMenu_newConnection', 'New connection'],
|
||||
['app_shared_connectionMenu_connection', 'Connection'],
|
||||
['app_shared_connectionMenu_custom', 'Manual'],
|
||||
['app_shared_connectionMenu_disconnect', 'Disconnect All'],
|
||||
['app_shared_toolsMenu_tools', 'Tools'],
|
||||
['app_shared_toolsMenu_logViewer', 'Log viewer'],
|
||||
['app_shared_toolsMenu_logViewer_placeholder', 'Log viewer is not active'],
|
||||
['app_shared_settingsMenu_config', 'Configuration'],
|
||||
['app_shared_settingsMenu_theme', 'Theme'],
|
||||
['app_shared_settingsMenu_lang', 'Language'],
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
export default [
|
||||
['app_shared_connectionMenu_newConnection', 'Nuova connessione'],
|
||||
['app_shared_connectionMenu_connection', 'Connessione'],
|
||||
['app_shared_connectionMenu_custom', 'Manuale'],
|
||||
['app_shared_connectionMenu_disconnect', 'Scollegati da tutto'],
|
||||
['app_shared_toolsMenu_tools', 'Strumenti'],
|
||||
['app_shared_toolsMenu_logViewer', 'Visualizzatore del Log'],
|
||||
['app_shared_toolsMenu_logViewer_placeholder', 'Il visualizzatore del log non è attivo'],
|
||||
['app_shared_settingsMenu_config', 'Configurazione'],
|
||||
['app_shared_settingsMenu_theme', 'Tema'],
|
||||
['app_shared_settingsMenu_lang', 'Lingua'],
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
export default [
|
||||
['app_shared_connectionMenu_connection', 'Подключение'],
|
||||
['app_shared_connectionMenu_custom', 'Создать...'],
|
||||
['app_shared_connectionMenu_disconnect', 'Отключить все'],
|
||||
['app_shared_toolsMenu_tools', 'Инструменты'],
|
||||
['app_shared_toolsMenu_logViewer', 'Просмотр лога'],
|
||||
['app_shared_toolsMenu_logViewer_placeholder', 'Просмотр логов неактивен'],
|
||||
['app_shared_settingsMenu_config', 'Настройки'],
|
||||
['app_shared_settingsMenu_theme', 'Тема'],
|
||||
['app_shared_settingsMenu_lang', 'Язык'],
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
export default [
|
||||
['app_shared_connectionMenu_newConnection', '新连接'],
|
||||
['app_shared_connectionMenu_connection', '连接'],
|
||||
['app_shared_connectionMenu_custom', '手动'],
|
||||
['app_shared_connectionMenu_disconnect', '断开所有连接'],
|
||||
['app_shared_toolsMenu_tools', '工具'],
|
||||
['app_shared_toolsMenu_logViewer', '日志查看器'],
|
||||
['app_shared_toolsMenu_logViewer_placeholder', '日志查看器未激活'],
|
||||
['app_shared_settingsMenu_config', '配置'],
|
||||
['app_shared_settingsMenu_theme', '主题'],
|
||||
['app_shared_settingsMenu_lang', '语言'],
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
import type { UserInfo } from '@cloudbeaver/core-sdk';
|
||||
import { createDataContext } from '@cloudbeaver/core-view';
|
||||
|
||||
export const DATA_CONTEXT_USER = createDataContext<UserInfo | null>('user-info', null);
|
||||
export const DATA_CONTEXT_USER = createDataContext<UserInfo | null>('user-info', () => null);
|
||||
|
||||
@@ -11,16 +11,14 @@ import { observer } from 'mobx-react-lite';
|
||||
import { useState, useEffect, useContext, useRef } from 'react';
|
||||
import styled, { use } from 'reshadow';
|
||||
|
||||
|
||||
import type { ComponentStyle } from '@cloudbeaver/core-theming';
|
||||
import { uuid } from '@cloudbeaver/core-utils';
|
||||
import { ILoadableState, uuid } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { Button } from '../Button';
|
||||
import { ExceptionMessage } from '../ExceptionMessage';
|
||||
import { Translate } from '../localization/Translate';
|
||||
import { StaticImage } from '../StaticImage';
|
||||
import { useStyles } from '../useStyles';
|
||||
import type { ILoadableState } from './ILoadableState';
|
||||
import { ILoaderContext, LoaderContext } from './LoaderContext';
|
||||
import { loaderStyles, overlayStyles } from './loaderStyles';
|
||||
|
||||
@@ -276,11 +274,3 @@ export const Loader = observer<Props>(function Loader({
|
||||
</LoaderContext.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
export function isContainsException(exception?: Error[] | Error | null): boolean {
|
||||
if (Array.isArray(exception)) {
|
||||
return exception.some(Boolean);
|
||||
}
|
||||
|
||||
return !!exception;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import type { ILoadableState } from './ILoadableState';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
export type LoaderState = ILoadableState | {
|
||||
loading: boolean;
|
||||
|
||||
@@ -8,18 +8,43 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import type { ILoadableState } from './ILoadableState';
|
||||
import { ILoadableState, isLoadableStateHasException } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { getComputed } from '../getComputed';
|
||||
|
||||
export interface IAutoLoadable extends ILoadableState {
|
||||
load: () => void;
|
||||
}
|
||||
|
||||
export function useAutoLoad(state: IAutoLoadable, enabled = true) {
|
||||
const canBeLoaded = enabled && !state.isLoaded();
|
||||
export function useAutoLoad(state: IAutoLoadable | IAutoLoadable[], enabled = true) {
|
||||
if (!Array.isArray(state)) {
|
||||
state = [state];
|
||||
}
|
||||
|
||||
for (const loader of state as IAutoLoadable[]) {
|
||||
getComputed( // activate mobx subscriptions
|
||||
() => (
|
||||
(
|
||||
!loader.isLoaded()
|
||||
|| loader.isOutdated?.() === true
|
||||
) && !isLoadableStateHasException(loader)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (canBeLoaded) {
|
||||
state.load();
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const loader of state as IAutoLoadable[]) {
|
||||
if (isLoadableStateHasException(loader)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!loader.isLoaded() || loader.isOutdated?.() === true) {
|
||||
loader.load();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -18,7 +18,6 @@ export * from './layout/TopAppBar';
|
||||
|
||||
export * from './Loader/Loader';
|
||||
export * from './Loader/useAutoLoad';
|
||||
export * from './Loader/ILoadableState';
|
||||
|
||||
export * from './localization/Translate';
|
||||
export * from './localization/useTranslate';
|
||||
|
||||
@@ -11,9 +11,9 @@ import { useEffect, useState } from 'react';
|
||||
import { IServiceConstructor, useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { CachedDataResource, CachedDataResourceContext, CachedDataResourceGetter, CachedDataResourceParam, CachedResourceData, CachedResourceIncludeArgs, isResourceKeyList } from '@cloudbeaver/core-sdk';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { getComputed } from './getComputed';
|
||||
import type { ILoadableState } from './Loader/ILoadableState';
|
||||
import { useObjectRef } from './useObjectRef';
|
||||
|
||||
interface KeyWithIncludes<TKey, TIncludes> {
|
||||
@@ -44,6 +44,7 @@ interface IMapResourceResult<
|
||||
resource: TResource;
|
||||
exception: Error | null;
|
||||
reload: () => void;
|
||||
load: () => void;
|
||||
}
|
||||
|
||||
export function useDataResource<
|
||||
@@ -183,6 +184,9 @@ export function useDataResource<
|
||||
setException(null);
|
||||
(refObj as any)[loadFunctionName](true);
|
||||
},
|
||||
load: () => {
|
||||
(refObj as any)[loadFunctionName]();
|
||||
},
|
||||
isLoading: () => {
|
||||
if (refObj.key === null) {
|
||||
return false;
|
||||
|
||||
@@ -12,10 +12,9 @@ import { useEffect, useState } from 'react';
|
||||
import { IServiceConstructor, useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { CachedResourceIncludeArgs, CachedMapResource, CachedMapResourceGetter, ResourceKey, CachedMapResourceValue, CachedMapResourceKey, CachedMapResourceArguments, CachedMapResourceLoader, ResourceKeyList, CachedMapResourceListGetter, isResourceKeyList } from '@cloudbeaver/core-sdk';
|
||||
import { isArraysEqual } from '@cloudbeaver/core-utils';
|
||||
import { ILoadableState, isArraysEqual } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { getComputed } from './getComputed';
|
||||
import type { ILoadableState } from './Loader/ILoadableState';
|
||||
import { useObservableRef } from './useObservableRef';
|
||||
|
||||
interface IActions<
|
||||
@@ -56,6 +55,7 @@ interface IMapResourceState<TResource extends CachedMapResource<any, any, any>>
|
||||
loaded: boolean;
|
||||
resource: TResource;
|
||||
isOutdated: () => boolean;
|
||||
load: () => void;
|
||||
reload: () => void;
|
||||
}
|
||||
|
||||
@@ -355,6 +355,9 @@ export function useMapResource<
|
||||
reload: () => {
|
||||
(refObj as any)[loadFunctionName](true);
|
||||
},
|
||||
load: () => {
|
||||
(refObj as any)[loadFunctionName]();
|
||||
},
|
||||
isLoading() {
|
||||
return this.loading;
|
||||
},
|
||||
|
||||
@@ -10,8 +10,8 @@ import { computed, observable } from 'mobx';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { Task } from '@cloudbeaver/core-executor';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { ILoadableState } from './Loader/ILoadableState';
|
||||
import { useObservableRef } from './useObservableRef';
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ export function usePromiseState<T>(promise: Promise<T> | null): ILoadableState {
|
||||
isLoaded(): boolean {
|
||||
return this.promise === null;
|
||||
},
|
||||
load() {},
|
||||
}), {
|
||||
cancel: computed,
|
||||
promise: observable.ref,
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
import { makeObservable, observable } from 'mobx';
|
||||
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { CachedResource } from './CachedResource';
|
||||
import type { CachedResourceIncludeArgs, CachedResourceValueIncludes } from './CachedResourceIncludes';
|
||||
|
||||
@@ -87,3 +89,35 @@ export abstract class CachedDataResource<
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
|
||||
export function getCachedDataResourceLoaderState<
|
||||
TData,
|
||||
TParam = void,
|
||||
TKey = TParam,
|
||||
TContext extends Record<string, any> | void = void,
|
||||
>(
|
||||
resource: CachedDataResource<TData, TParam, TKey, TContext>,
|
||||
param: TParam,
|
||||
context: ContextArg<TData, TContext>
|
||||
): ILoadableState {
|
||||
return {
|
||||
get exception() {
|
||||
return resource.getException(param);
|
||||
},
|
||||
isLoading() {
|
||||
return resource.isDataLoading(param);
|
||||
},
|
||||
isLoaded() {
|
||||
return resource.isLoaded(param, context);
|
||||
},
|
||||
isOutdated() {
|
||||
return resource.isOutdated(param);
|
||||
},
|
||||
load() {
|
||||
return resource.load(param, context);
|
||||
},
|
||||
reload() {
|
||||
return resource.refresh(param, context);
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
import { action, computed, makeObservable, observable } from 'mobx';
|
||||
|
||||
import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import { isArraysEqual, MetadataMap } from '@cloudbeaver/core-utils';
|
||||
import { ILoadableState, isArraysEqual, MetadataMap } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { CachedResource, CachedResourceKey, ICachedResourceMetadata } from './CachedResource';
|
||||
import type { CachedResourceIncludeArgs, CachedResourceValueIncludes } from './CachedResourceIncludes';
|
||||
@@ -475,3 +475,34 @@ export abstract class CachedMapResource<
|
||||
this.onDataOutdated.execute(key);
|
||||
}
|
||||
}
|
||||
|
||||
export function getCachedMapResourceLoaderState<
|
||||
TKey,
|
||||
TValue,
|
||||
TArguments = Record<string, any>
|
||||
>(
|
||||
resource: CachedMapResource<TKey, TValue, TArguments>,
|
||||
key: ResourceKey<TKey>,
|
||||
includes?: CachedResourceIncludeArgs<TValue, TArguments> | undefined
|
||||
): ILoadableState {
|
||||
return {
|
||||
get exception() {
|
||||
return resource.getException(key);
|
||||
},
|
||||
isLoading() {
|
||||
return resource.isDataLoading(key);
|
||||
},
|
||||
isLoaded() {
|
||||
return resource.isLoaded(key, includes);
|
||||
},
|
||||
isOutdated() {
|
||||
return resource.isOutdated(key);
|
||||
},
|
||||
load() {
|
||||
return resource.load(key, includes);
|
||||
},
|
||||
reload() {
|
||||
return resource.refresh(key, includes);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,9 +11,8 @@ import { ButtonHTMLAttributes, forwardRef, useRef } from 'react';
|
||||
import type { MenuInitialState } from 'reakit/Menu';
|
||||
import styled from 'reshadow';
|
||||
|
||||
import { getComputed, IMenuState, Menu, menuPanelStyles, useObjectRef, useTranslate, useStyles } from '@cloudbeaver/core-blocks';
|
||||
import { getComputed, IMenuState, Menu, menuPanelStyles, useObjectRef, useTranslate, useStyles, useAutoLoad } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
|
||||
import type { ComponentStyle } from '@cloudbeaver/core-theming';
|
||||
import { IMenuData, MenuActionItem, MenuService } from '@cloudbeaver/core-view';
|
||||
|
||||
@@ -62,6 +61,8 @@ export const ContextMenu = observer<IContextMenuProps, HTMLButtonElement>(forwar
|
||||
const menu = useRef<IMenuState>();
|
||||
const styles = useStyles(menuPanelStyles, style);
|
||||
|
||||
useAutoLoad(menuData.loaders, !lazy);
|
||||
|
||||
const handlers = useObjectRef(() => ({
|
||||
handleItemClose() {
|
||||
menu.current?.hide();
|
||||
|
||||
@@ -38,13 +38,13 @@ export const MENU_BAR_DEFAULT_STYLES = css`
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
& item-label {
|
||||
& menu-bar-item-label {
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
& IconOrImage + item-label, & Loader + item-label {
|
||||
& IconOrImage + menu-bar-item-label, & Loader + menu-bar-item-label {
|
||||
padding-left: 8px
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { forwardRef, useCallback } from 'react';
|
||||
import { MenuInitialState, MenuSeparator } from 'reakit';
|
||||
import styled, { use } from 'reshadow';
|
||||
|
||||
import { useStyles } from '@cloudbeaver/core-blocks';
|
||||
import { useAutoLoad, useStyles } from '@cloudbeaver/core-blocks';
|
||||
import type { ComponentStyle } from '@cloudbeaver/core-theming';
|
||||
import { DATA_CONTEXT_MENU_NESTED, IMenuActionItem, IMenuData, IMenuItem, MenuActionItem, MenuBaseItem, MenuSeparatorItem, MenuSubMenuItem, useMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
@@ -36,6 +36,7 @@ export const MenuBar = observer<IMenuBarProps, HTMLDivElement>(forwardRef(functi
|
||||
}, ref) {
|
||||
const styles = useStyles(style);
|
||||
const items = menu.items;
|
||||
useAutoLoad(menu.loaders);
|
||||
|
||||
if (!items.length) {
|
||||
return null;
|
||||
@@ -60,6 +61,7 @@ interface IMenuBarElementProps {
|
||||
item: IMenuItem;
|
||||
menuData: IMenuData;
|
||||
nestedMenuSettings?: INestedMenuSettings;
|
||||
className?: string;
|
||||
style?: ComponentStyle;
|
||||
}
|
||||
|
||||
@@ -67,6 +69,7 @@ const MenuBarElement = observer<IMenuBarElementProps>(function MenuBarElement({
|
||||
item,
|
||||
menuData,
|
||||
nestedMenuSettings,
|
||||
className,
|
||||
style,
|
||||
}) {
|
||||
const styles = useStyles(style);
|
||||
@@ -81,6 +84,7 @@ const MenuBarElement = observer<IMenuBarElementProps>(function MenuBarElement({
|
||||
item={item}
|
||||
menuData={menuData}
|
||||
style={style}
|
||||
className={className}
|
||||
nestedMenuSettings={nestedMenuSettings}
|
||||
/>
|
||||
);
|
||||
@@ -88,7 +92,7 @@ const MenuBarElement = observer<IMenuBarElementProps>(function MenuBarElement({
|
||||
|
||||
if (item instanceof MenuSeparatorItem) {
|
||||
return styled(styles)(
|
||||
<MenuSeparator />
|
||||
<MenuSeparator className={className} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -97,6 +101,7 @@ const MenuBarElement = observer<IMenuBarElementProps>(function MenuBarElement({
|
||||
<MenuBarAction
|
||||
item={item}
|
||||
style={style}
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
@@ -112,6 +117,7 @@ const MenuBarElement = observer<IMenuBarElementProps>(function MenuBarElement({
|
||||
title={item.tooltip}
|
||||
disabled={item.disabled}
|
||||
style={style}
|
||||
className={className}
|
||||
onClick={onClick}
|
||||
{...use({ hidden: item.hidden })}
|
||||
/>
|
||||
@@ -124,10 +130,11 @@ const MenuBarElement = observer<IMenuBarElementProps>(function MenuBarElement({
|
||||
interface IMenuBarActionProps {
|
||||
item: IMenuActionItem;
|
||||
style?: ComponentStyle;
|
||||
className?: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
const MenuBarAction = observer<IMenuBarActionProps>(function MenuBarAction({ item, style, onClick }) {
|
||||
const MenuBarAction = observer<IMenuBarActionProps>(function MenuBarAction({ item, style, className, onClick }) {
|
||||
const styles = useStyles(style);
|
||||
|
||||
const actionInfo = item.action.actionInfo;
|
||||
@@ -148,6 +155,7 @@ const MenuBarAction = observer<IMenuBarActionProps>(function MenuBarAction({ ite
|
||||
disabled={item.disabled}
|
||||
loading={loading}
|
||||
style={style}
|
||||
className={className}
|
||||
onClick={handleClick}
|
||||
{...use({ hidden: item.hidden })}
|
||||
/>
|
||||
@@ -158,6 +166,7 @@ interface ISubMenuItemProps {
|
||||
item: MenuSubMenuItem;
|
||||
menuData: IMenuData;
|
||||
nestedMenuSettings?: INestedMenuSettings;
|
||||
className?: string;
|
||||
style?: ComponentStyle;
|
||||
}
|
||||
|
||||
@@ -165,6 +174,7 @@ const SubMenuItem = observer<ISubMenuItemProps>(function SubmenuItem({
|
||||
item,
|
||||
menuData,
|
||||
nestedMenuSettings,
|
||||
className,
|
||||
style,
|
||||
}) {
|
||||
const styles = useStyles(style);
|
||||
@@ -176,6 +186,7 @@ const SubMenuItem = observer<ISubMenuItemProps>(function SubmenuItem({
|
||||
<ContextMenu
|
||||
menu={subMenuData}
|
||||
style={style}
|
||||
className={className}
|
||||
disclosure
|
||||
{...nestedMenuSettings}
|
||||
>
|
||||
|
||||
@@ -37,7 +37,7 @@ export const MenuBarItem = observer<Props, HTMLButtonElement>(forwardRef(functio
|
||||
<menu-bar-item ref={ref} as='button' {...rest} title={title} aria-label={title}>
|
||||
{loading && <Loader small fullSize />}
|
||||
{!loading && icon && <IconOrImage icon={icon} viewBox={viewBox} />}
|
||||
{label && <item-label>{translate(label)}</item-label>}
|
||||
{label && <menu-bar-item-label>{translate(label)}</menu-bar-item-label>}
|
||||
</menu-bar-item>
|
||||
);
|
||||
}));
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
export interface ILoadableState {
|
||||
isLoading: () => boolean;
|
||||
isLoaded: () => boolean;
|
||||
readonly exception?: (Error | null)[] | Error | null;
|
||||
load: () => void;
|
||||
reload?: () => void;
|
||||
|
||||
isOutdated?: () => boolean;
|
||||
isCancelled?: () => boolean;
|
||||
cancel?: () => void;
|
||||
}
|
||||
|
||||
// export function composeLoadableState(...states: ILoadableState[]): ILoadableState {
|
||||
|
||||
// }
|
||||
|
||||
export function isLoadableStateHasException(state: ILoadableState): boolean {
|
||||
return isContainsException(state.exception);
|
||||
}
|
||||
|
||||
export function isContainsException(exception?: (Error | null)[] | Error | null): boolean {
|
||||
if (Array.isArray(exception)) {
|
||||
return exception.some(Boolean);
|
||||
}
|
||||
|
||||
return !!exception;
|
||||
}
|
||||
@@ -16,6 +16,7 @@ export * from './flat';
|
||||
export * from './generateFileName';
|
||||
export * from './getMIME';
|
||||
export * from './GlobalConstants';
|
||||
export * from './ILoadableState';
|
||||
export * from './isArraysEqual';
|
||||
export * from './isPropertiesEqual';
|
||||
export * from './isValuesEqual';
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { flat } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { IDataContextProvider } from '../DataContext/IDataContextProvider';
|
||||
import type { IAction } from './IAction';
|
||||
import type { IActionHandler } from './IActionHandler';
|
||||
@@ -17,7 +19,7 @@ export class ActionItem implements IActionItem {
|
||||
readonly action: IAction;
|
||||
readonly handler: IActionHandler;
|
||||
readonly binding: IKeyBindingHandler | null;
|
||||
private context: IDataContextProvider;
|
||||
private readonly context: IDataContextProvider;
|
||||
|
||||
get actionInfo(): IActionInfo {
|
||||
if (this.handler.getActionInfo) {
|
||||
@@ -44,7 +46,10 @@ export class ActionItem implements IActionItem {
|
||||
}
|
||||
|
||||
isLoading(): boolean {
|
||||
return this.handler.isLoading?.(this.context, this.action) ?? false;
|
||||
return (
|
||||
this.handler.isLoading?.(this.context, this.action)
|
||||
|| flat([this.handler.getLoader?.(this.context, this.action)]).some(loader => loader?.isLoading())
|
||||
);
|
||||
}
|
||||
|
||||
isDisabled(): boolean {
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { IDataContextProvider } from '../DataContext/IDataContextProvider';
|
||||
import type { IAction } from './IAction';
|
||||
import type { IActionInfo } from './IActionInfo';
|
||||
@@ -14,6 +16,7 @@ export interface IActionHandler {
|
||||
id: string;
|
||||
|
||||
getActionInfo?: (context: IDataContextProvider, action: IAction) => IActionInfo;
|
||||
getLoader?: (context: IDataContextProvider, action: IAction) => ILoadableState[] | ILoadableState;
|
||||
|
||||
isChecked?: (context: IDataContextProvider, action: IAction) => boolean;
|
||||
isLoading?: (context: IDataContextProvider, action: IAction) => boolean;
|
||||
|
||||
@@ -36,8 +36,12 @@ export class DataContext implements IDataContext {
|
||||
this.fallback = fallback;
|
||||
}
|
||||
|
||||
has(context: DataContextGetter<any>): boolean {
|
||||
return this.map.has(context) || this.fallback?.has(context) || false;
|
||||
has(context: DataContextGetter<any>, nested = true): boolean {
|
||||
if (nested) {
|
||||
return this.map.has(context) || this.fallback?.has(context) || false;
|
||||
}
|
||||
|
||||
return this.map.has(context);
|
||||
}
|
||||
|
||||
hasValue<T>(context: DataContextGetter<T>, value: T): boolean {
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { DataContextGetter } from './DataContextGetter';
|
||||
export interface IDataContextProvider {
|
||||
fallback?: IDataContextProvider;
|
||||
readonly map: Map<DataContextGetter<any>, any>;
|
||||
has: (context: DataContextGetter<any>) => boolean;
|
||||
has: (context: DataContextGetter<any>, nested?: boolean) => boolean;
|
||||
get: <T>(context: DataContextGetter<T>) => T;
|
||||
find: <T>(context: DataContextGetter<T>, predicate: (item: T) => boolean) => T | undefined;
|
||||
hasValue: <T>(context: DataContextGetter<T>, value: T) => boolean;
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
|
||||
import type { DataContextGetter } from './DataContextGetter';
|
||||
|
||||
export function createDataContext<T>(name: string, defaultValue?: T): DataContextGetter<T> {
|
||||
export function createDataContext<T>(
|
||||
name: string,
|
||||
defaultValue?: () => T extends any ? T : undefined
|
||||
): DataContextGetter<T> {
|
||||
name = `@context/${name}`;
|
||||
const obj = {
|
||||
[name](): T {
|
||||
return defaultValue as T;
|
||||
return defaultValue?.() as T;
|
||||
},
|
||||
};
|
||||
return obj[name];
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 { flat, ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { createDataContext } from '../DataContext/createDataContext';
|
||||
|
||||
interface ILoadableStateContext {
|
||||
getState(id: string, defaultState: () => ILoadableState | ILoadableState[]): ILoadableState[];
|
||||
}
|
||||
|
||||
export function loadableStateContext(): ILoadableStateContext {
|
||||
const state = new Map<string, ILoadableState[]>();
|
||||
|
||||
return {
|
||||
getState(id, defaultState) {
|
||||
if (!state.has(id)) {
|
||||
state.set(id, flat([defaultState()]));
|
||||
}
|
||||
|
||||
return state.get(id)!;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const DATA_CONTEXT_LOADABLE_STATE = createDataContext<ILoadableStateContext>('loadable-state', loadableStateContext);
|
||||
@@ -8,4 +8,4 @@
|
||||
|
||||
import { createDataContext } from '../DataContext/createDataContext';
|
||||
|
||||
export const DATA_CONTEXT_MENU_LOCAL = createDataContext<boolean | undefined>('menu-local', false);
|
||||
export const DATA_CONTEXT_MENU_LOCAL = createDataContext<boolean | undefined>('menu-local', () => false);
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
|
||||
import { createDataContext } from '../DataContext/createDataContext';
|
||||
|
||||
export const DATA_CONTEXT_MENU_NESTED = createDataContext<boolean>('menu-nested', false);
|
||||
export const DATA_CONTEXT_MENU_NESTED = createDataContext<boolean>('menu-nested', () => false);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { flat, ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { ActionService } from '../Action/ActionService';
|
||||
import { isAction } from '../Action/createAction';
|
||||
@@ -44,11 +45,6 @@ export class MenuService {
|
||||
return null;
|
||||
}
|
||||
|
||||
isMenuAvailable(context: IDataContextProvider): boolean {
|
||||
return this.creators
|
||||
.some(filterApplicable(context));
|
||||
}
|
||||
|
||||
addCreator(creator: IMenuItemsCreator): void {
|
||||
this.creators.push(creator);
|
||||
}
|
||||
@@ -70,18 +66,32 @@ export class MenuService {
|
||||
return null;
|
||||
}
|
||||
|
||||
getMenu(context: IDataContextProvider): IMenuItem[] {
|
||||
const applicableCreators = this.creators.filter(filterApplicable(context));
|
||||
getMenuItemLoaders(context: IDataContextProvider, itemCreators: MenuCreatorItem[]): ILoadableState[] {
|
||||
return flat(itemCreators
|
||||
.map(item => {
|
||||
if (isAction(item)) {
|
||||
const handler = this.actionService.getHandler(context, item);
|
||||
|
||||
return applicableCreators
|
||||
.reduce<MenuCreatorItem[]>(
|
||||
return handler?.getLoader?.(context, item) ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}))
|
||||
.filter<ILoadableState>((item => item !== null) as ((obj: any) => obj is ILoadableState))
|
||||
;
|
||||
}
|
||||
|
||||
getMenuItemCreators(context: IDataContextProvider): MenuCreatorItem[] {
|
||||
const creators = this.creators.filter(filterApplicable(context));
|
||||
|
||||
return creators.reduce<MenuCreatorItem[]>(
|
||||
(items, creator) => {
|
||||
if (creator.orderItems) {
|
||||
return creator.orderItems(context, items);
|
||||
}
|
||||
return items;
|
||||
},
|
||||
applicableCreators
|
||||
creators
|
||||
.reduce<MenuCreatorItem[]>((items, creator) => creator.getItems(context, items), [])
|
||||
.filter(item => {
|
||||
if (isAction(item)) {
|
||||
@@ -90,7 +100,11 @@ export class MenuService {
|
||||
|
||||
return true;
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
getMenu(context: IDataContextProvider, itemCreators: MenuCreatorItem[]): IMenuItem[] {
|
||||
return itemCreators
|
||||
.map(item => {
|
||||
if (isAction(item)) {
|
||||
return this.createActionItem(context, item) as IMenuItem;
|
||||
@@ -132,6 +146,10 @@ function filterApplicable(contexts: IDataContextProvider): (creator: IMenuItemsC
|
||||
return false;
|
||||
}
|
||||
|
||||
return creator.isApplicable?.(contexts) ?? true;
|
||||
if (creator.isApplicable?.(contexts) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,10 +10,12 @@ import { computed, observable } from 'mobx';
|
||||
|
||||
import { useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { IDataContext } from '../DataContext/IDataContext';
|
||||
import { DATA_CONTEXT_MENU_LOCAL } from './DATA_CONTEXT_MENU_LOCAL';
|
||||
import type { IMenu } from './IMenu';
|
||||
import type { MenuCreatorItem } from './IMenuItemsCreator';
|
||||
import type { IMenuItem } from './MenuItem/IMenuItem';
|
||||
import { MenuService } from './MenuService';
|
||||
import { useMenuContext } from './useMenuContext';
|
||||
@@ -22,6 +24,8 @@ export interface IMenuData {
|
||||
menu: IMenu;
|
||||
context: IDataContext;
|
||||
available: boolean;
|
||||
loaders: ILoadableState[];
|
||||
itemCreators: MenuCreatorItem[];
|
||||
items: IMenuItem[];
|
||||
}
|
||||
|
||||
@@ -37,16 +41,24 @@ export function useMenu(options: IMenuOptions): IMenuData {
|
||||
|
||||
context.set(DATA_CONTEXT_MENU_LOCAL, options.local);
|
||||
|
||||
return useObservableRef<IMenuData>(() => ({
|
||||
const state = useObservableRef<IMenuData>(() => ({
|
||||
context,
|
||||
get loaders() {
|
||||
return menuService.getMenuItemLoaders(this.context, this.itemCreators);
|
||||
},
|
||||
get itemCreators() {
|
||||
return menuService.getMenuItemCreators(this.context);
|
||||
},
|
||||
get available() {
|
||||
return menuService.isMenuAvailable(this.context);
|
||||
return this.itemCreators.length > 0;
|
||||
},
|
||||
get items() {
|
||||
return menuService.getMenu(this.context);
|
||||
return menuService.getMenu(this.context, this.itemCreators);
|
||||
},
|
||||
}), {
|
||||
loaders: computed,
|
||||
available: computed,
|
||||
itemCreators: computed,
|
||||
items: computed,
|
||||
menu: observable.ref,
|
||||
context: observable.ref,
|
||||
@@ -54,4 +66,6 @@ export function useMenu(options: IMenuOptions): IMenuData {
|
||||
menu: options.menu,
|
||||
context,
|
||||
});
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useContext } from 'react';
|
||||
|
||||
import type { IDataContext } from '../DataContext/IDataContext';
|
||||
import { useDataContext } from '../DataContext/useDataContext';
|
||||
import { DATA_CONTEXT_LOADABLE_STATE, loadableStateContext } from '../LoadableStateContext/DATA_CONTEXT_LOADABLE_STATE';
|
||||
import { CaptureViewContext } from '../View/CaptureViewContext';
|
||||
import { DATA_CONTEXT_MENU } from './DATA_CONTEXT_MENU';
|
||||
import type { IMenu } from './IMenu';
|
||||
@@ -20,5 +21,9 @@ export function useMenuContext(menu: IMenu, _menuContext?: IDataContext): IDataC
|
||||
|
||||
context.set(DATA_CONTEXT_MENU, menu);
|
||||
|
||||
if (context.has(DATA_CONTEXT_LOADABLE_STATE, false)) {
|
||||
context.set(DATA_CONTEXT_LOADABLE_STATE, loadableStateContext());
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ export * from './DataContext/IDataContext';
|
||||
export * from './DataContext/IDataContextProvider';
|
||||
export * from './DataContext/useDataContext';
|
||||
export * from './DataContext/useDynamicDataContext';
|
||||
export * from './LoadableStateContext/DATA_CONTEXT_LOADABLE_STATE';
|
||||
export * from './Menu/MenuItem/IMenuCheckboxItem';
|
||||
export * from './Menu/MenuItem/IMenuActionItem';
|
||||
export * from './Menu/MenuItem/IMenuBaseItem';
|
||||
|
||||
+2
-3
@@ -10,9 +10,8 @@ import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import type { TeamInfo } from '@cloudbeaver/core-authentication';
|
||||
import { Table, TableHeader, TableColumnHeader, TableBody, TableSelect, Loader, ILoadableState, useTranslate, useStyles } from '@cloudbeaver/core-blocks';
|
||||
|
||||
|
||||
import { Table, TableHeader, TableColumnHeader, TableBody, TableSelect, Loader, useTranslate, useStyles } from '@cloudbeaver/core-blocks';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { Team } from './Team';
|
||||
|
||||
|
||||
+2
-2
@@ -9,12 +9,12 @@
|
||||
import { computed, observable } from 'mobx';
|
||||
|
||||
import { compareTeams, TeamInfo, TeamsResource } from '@cloudbeaver/core-authentication';
|
||||
import { ILoadableState, TableState, useMapResource, useObservableRef, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { TableState, useMapResource, useObservableRef, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService, ConfirmationDialogDelete, DialogueStateResult } from '@cloudbeaver/core-dialogs';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
|
||||
import { CachedMapAllKey, resourceKeyList } from '@cloudbeaver/core-sdk';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
interface State {
|
||||
tableState: TableState;
|
||||
|
||||
@@ -11,10 +11,11 @@ import { useEffect } from 'react';
|
||||
|
||||
import { AdministrationScreenService } from '@cloudbeaver/core-administration';
|
||||
import { AuthInfoService, AuthProvider, AuthProviderConfiguration, AuthProvidersResource, IAuthCredentials } from '@cloudbeaver/core-authentication';
|
||||
import { ILoadableState, useMapResource, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { useMapResource, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { CachedMapAllKey } from '@cloudbeaver/core-sdk';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { FEDERATED_AUTH } from './FEDERATED_AUTH';
|
||||
|
||||
|
||||
+7
-8
@@ -6,12 +6,11 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
export interface ILoadableState {
|
||||
isLoading: () => boolean;
|
||||
isLoaded: () => boolean;
|
||||
readonly exception?: Error[] | Error | null;
|
||||
reload?: () => void;
|
||||
import { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
isCancelled?: () => boolean;
|
||||
cancel?: () => void;
|
||||
}
|
||||
export const ACTION_CONNECTION_CUSTOM = createAction(
|
||||
'connection-custom',
|
||||
{
|
||||
label: 'plugin_connection_custom_action_custom_label',
|
||||
}
|
||||
);
|
||||
@@ -9,35 +9,57 @@
|
||||
import { ConnectionsManagerService } from '@cloudbeaver/core-connections';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
|
||||
import { ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { MainMenuService, EMainMenu } from '@cloudbeaver/plugin-top-app-bar';
|
||||
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
|
||||
import { CachedMapAllKey, getCachedMapResourceLoaderState } from '@cloudbeaver/core-sdk';
|
||||
import { ActionService, DATA_CONTEXT_LOADABLE_STATE, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view';
|
||||
import { MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections';
|
||||
|
||||
import { ACTION_CONNECTION_CUSTOM } from './Actions/ACTION_CONNECTION_CUSTOM';
|
||||
import { CustomConnectionDialog } from './CustomConnection/CustomConnectionDialog';
|
||||
|
||||
@injectable()
|
||||
export class CustomConnectionPluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly mainMenuService: MainMenuService,
|
||||
private readonly commonDialogService: CommonDialogService,
|
||||
private readonly projectsService: ProjectsService,
|
||||
private readonly connectionsManagerService: ConnectionsManagerService
|
||||
private readonly projectInfoResource: ProjectInfoResource,
|
||||
private readonly menuService: MenuService,
|
||||
private readonly actionService: ActionService,
|
||||
private readonly connectionsManagerService: ConnectionsManagerService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.mainMenuService.onConnectionClick.addHandler(() => {
|
||||
this.projectsService.load();
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_CONNECTIONS,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
ACTION_CONNECTION_CUSTOM,
|
||||
],
|
||||
});
|
||||
|
||||
this.mainMenuService.registerMenuItem(EMainMenu.mainMenuConnectionsPanel, {
|
||||
id: 'customConnection',
|
||||
order: 2,
|
||||
title: 'app_shared_connectionMenu_custom',
|
||||
isHidden: () => (
|
||||
!this.projectsService.activeProjects.some(project => project.canEditDataSources)
|
||||
),
|
||||
onClick: () => this.openConnectionsDialog(),
|
||||
this.actionService.addHandler({
|
||||
id: 'connection-custom',
|
||||
isActionApplicable: (context, action) => [
|
||||
ACTION_CONNECTION_CUSTOM,
|
||||
].includes(action),
|
||||
isHidden: () => this.connectionsManagerService.createConnectionProjects.length === 0,
|
||||
getLoader: (context, action) => {
|
||||
const state = context.get(DATA_CONTEXT_LOADABLE_STATE);
|
||||
|
||||
return state.getState(
|
||||
action.id,
|
||||
() => getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey)
|
||||
);
|
||||
},
|
||||
handler: async (context, action) => {
|
||||
switch (action) {
|
||||
case ACTION_CONNECTION_CUSTOM: {
|
||||
await this.openConnectionsDialog();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,4 +17,5 @@ export default [
|
||||
['customConnection_test', 'Test Connection'],
|
||||
['customConnection_create', 'Create'],
|
||||
['customConnection_create_error', 'Сreate connection error'],
|
||||
['plugin_connection_custom_action_custom_label', 'Manual'],
|
||||
];
|
||||
|
||||
@@ -17,4 +17,5 @@ export default [
|
||||
['customConnection_test', 'Prova la connessione'],
|
||||
['customConnection_create', 'Crea'],
|
||||
['customConnection_create_error', 'Errore di creazione connessione'],
|
||||
['plugin_connection_custom_action_custom_label', 'Manuale'],
|
||||
];
|
||||
|
||||
@@ -17,4 +17,5 @@ export default [
|
||||
['customConnection_test', 'Проверить'],
|
||||
['customConnection_create', 'Создать'],
|
||||
['customConnection_create_error', 'Ошибка при создании подключения'],
|
||||
['plugin_connection_custom_action_custom_label', 'Создать'],
|
||||
];
|
||||
|
||||
@@ -17,4 +17,5 @@ export default [
|
||||
['customConnection_test', '测试连接'],
|
||||
['customConnection_create', '创建'],
|
||||
['customConnection_create_error', '创建连接失败'],
|
||||
['plugin_connection_custom_action_custom_label', '手动'],
|
||||
];
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_CONNECTION_SEARCH = createAction(
|
||||
'connection-search',
|
||||
{
|
||||
label: 'plugin_connection_search_action_search_label',
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 { LocalizationService } from '@cloudbeaver/core-localization';
|
||||
|
||||
@injectable()
|
||||
export class LocaleService extends Bootstrap {
|
||||
constructor(private readonly localizationService: LocalizationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.localizationService.addProvider(this.provider.bind(this));
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
|
||||
private async provider(locale: string) {
|
||||
switch (locale) {
|
||||
case 'ru':
|
||||
return (await import('./locales/ru')).default;
|
||||
case 'it':
|
||||
return (await import('./locales/it')).default;
|
||||
case 'zh':
|
||||
return (await import('./locales/zh')).default;
|
||||
default:
|
||||
return (await import('./locales/en')).default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,39 +7,63 @@
|
||||
*/
|
||||
|
||||
import { EAdminPermission } from '@cloudbeaver/core-administration';
|
||||
import { ConnectionsManagerService } from '@cloudbeaver/core-connections';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
|
||||
import { PermissionsService } from '@cloudbeaver/core-root';
|
||||
import { MainMenuService, EMainMenu } from '@cloudbeaver/plugin-top-app-bar';
|
||||
import { getCachedMapResourceLoaderState, CachedMapAllKey } from '@cloudbeaver/core-sdk';
|
||||
import { MenuService, ActionService, DATA_CONTEXT_MENU, DATA_CONTEXT_LOADABLE_STATE } from '@cloudbeaver/core-view';
|
||||
import { MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections';
|
||||
|
||||
import { ACTION_CONNECTION_SEARCH } from './Actions/ACTION_CONNECTION_SEARCH';
|
||||
import { ConnectionSearchService } from './Search/ConnectionSearchService';
|
||||
|
||||
@injectable()
|
||||
export class SearchConnectionPluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly mainMenuService: MainMenuService,
|
||||
private readonly projectsService: ProjectsService,
|
||||
private readonly permissionsService: PermissionsService,
|
||||
private readonly projectInfoResource: ProjectInfoResource,
|
||||
private readonly connectionSearchService: ConnectionSearchService,
|
||||
private readonly connectionsManagerService: ConnectionsManagerService,
|
||||
private readonly menuService: MenuService,
|
||||
private readonly actionService: ActionService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.mainMenuService.onConnectionClick.addHandler(() => {
|
||||
this.projectsService.load();
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_CONNECTIONS,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
ACTION_CONNECTION_SEARCH,
|
||||
],
|
||||
});
|
||||
|
||||
this.mainMenuService.registerMenuItem(EMainMenu.mainMenuConnectionsPanel, {
|
||||
id: 'searchConnection',
|
||||
order: 3,
|
||||
title: 'connections_connection_create_search_database',
|
||||
this.actionService.addHandler({
|
||||
id: 'connection-search',
|
||||
isActionApplicable: (context, action) => [
|
||||
ACTION_CONNECTION_SEARCH,
|
||||
].includes(action),
|
||||
isHidden: () => (
|
||||
!this.projectsService.activeProjects.some(project => project.canEditDataSources)
|
||||
this.connectionsManagerService.createConnectionProjects.length === 0
|
||||
|| !this.permissionsService.has(EAdminPermission.admin)
|
||||
),
|
||||
onClick: () => {
|
||||
this.connectionSearchService.open();
|
||||
getLoader: (context, action) => {
|
||||
const state = context.get(DATA_CONTEXT_LOADABLE_STATE);
|
||||
|
||||
return state.getState(
|
||||
action.id,
|
||||
() => getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey)
|
||||
);
|
||||
},
|
||||
handler: async (context, action) => {
|
||||
switch (action) {
|
||||
case ACTION_CONNECTION_SEARCH: {
|
||||
this.connectionSearchService.open();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_connection_search_action_search_label', 'Search'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_connection_search_action_search_label', 'Search'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_connection_search_action_search_label', 'Поиск'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_connection_search_action_search_label', 'Search'],
|
||||
];
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
|
||||
import { LocaleService } from './LocaleService';
|
||||
import { ConnectionSearchService } from './Search/ConnectionSearchService';
|
||||
import { SearchConnectionPluginBootstrap } from './SearchConnectionPluginBootstrap';
|
||||
|
||||
@@ -10,5 +11,6 @@ export const connectionSearchPlugin: PluginManifest = {
|
||||
providers: [
|
||||
SearchConnectionPluginBootstrap,
|
||||
ConnectionSearchService,
|
||||
LocaleService,
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_CONNECTION_TEMPLATE = createAction(
|
||||
'connection-template',
|
||||
{
|
||||
label: 'plugin_connection_template_action_connection_template_label',
|
||||
}
|
||||
);
|
||||
+40
-28
@@ -8,11 +8,13 @@
|
||||
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { PermissionsService, EPermission } from '@cloudbeaver/core-root';
|
||||
import { MainMenuService, EMainMenu } from '@cloudbeaver/plugin-top-app-bar';
|
||||
import { CachedMapAllKey, getCachedDataResourceLoaderState, getCachedMapResourceLoaderState } from '@cloudbeaver/core-sdk';
|
||||
import { MenuService, ActionService, DATA_CONTEXT_MENU, DATA_CONTEXT_LOADABLE_STATE } from '@cloudbeaver/core-view';
|
||||
import { MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections';
|
||||
|
||||
import { ACTION_CONNECTION_TEMPLATE } from './Actions/ACTION_CONNECTION_TEMPLATE';
|
||||
import { ConnectionDialog } from './ConnectionDialog/ConnectionDialog';
|
||||
import { TemplateConnectionsResource } from './TemplateConnectionsResource';
|
||||
import { TemplateConnectionsService } from './TemplateConnectionsService';
|
||||
@@ -20,10 +22,11 @@ import { TemplateConnectionsService } from './TemplateConnectionsService';
|
||||
@injectable()
|
||||
export class TemplateConnectionPluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly mainMenuService: MainMenuService,
|
||||
private readonly menuService: MenuService,
|
||||
private readonly actionService: ActionService,
|
||||
private readonly projectInfoResource: ProjectInfoResource,
|
||||
private readonly templateConnectionsResource: TemplateConnectionsResource,
|
||||
private readonly commonDialogService: CommonDialogService,
|
||||
private readonly notificationService: NotificationService,
|
||||
private readonly permissionsService: PermissionsService,
|
||||
private readonly templateConnectionsService: TemplateConnectionsService,
|
||||
private readonly projectsService: ProjectsService,
|
||||
@@ -32,40 +35,49 @@ export class TemplateConnectionPluginBootstrap extends Bootstrap {
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.mainMenuService.onConnectionClick.addHandler(this.loadTemplateConnections.bind(this));
|
||||
this.mainMenuService.registerMenuItem(EMainMenu.mainMenuConnectionsPanel, {
|
||||
id: 'mainMenuConnect',
|
||||
order: 1,
|
||||
titleGetter: this.getMenuTitle.bind(this),
|
||||
onClick: this.openConnectionsDialog.bind(this),
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_CONNECTIONS,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
ACTION_CONNECTION_TEMPLATE,
|
||||
],
|
||||
});
|
||||
|
||||
this.actionService.addHandler({
|
||||
id: 'connection-template',
|
||||
isActionApplicable: (context, action) => [
|
||||
ACTION_CONNECTION_TEMPLATE,
|
||||
].includes(action),
|
||||
isHidden: () => (
|
||||
!this.permissionsService.has(EPermission.public)
|
||||
|| !this.projectsService.userProject?.canEditDataSources
|
||||
|| !this.templateConnectionsService.projectTemplates.length
|
||||
),
|
||||
getLoader: (context, action) => {
|
||||
const state = context.get(DATA_CONTEXT_LOADABLE_STATE);
|
||||
|
||||
return state.getState(
|
||||
action.id,
|
||||
() => [
|
||||
getCachedMapResourceLoaderState(this.projectInfoResource, CachedMapAllKey),
|
||||
getCachedDataResourceLoaderState(this.templateConnectionsResource, undefined, undefined),
|
||||
]
|
||||
);
|
||||
},
|
||||
handler: async (context, action) => {
|
||||
switch (action) {
|
||||
case ACTION_CONNECTION_TEMPLATE: {
|
||||
await this.openConnectionsDialog();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
|
||||
private getMenuTitle(): string {
|
||||
if (this.templateConnectionsResource.isLoading()) {
|
||||
return 'ui_processing_loading';
|
||||
}
|
||||
return 'basicConnection_main_menu_item';
|
||||
}
|
||||
|
||||
private async openConnectionsDialog() {
|
||||
this.loadTemplateConnections();
|
||||
await this.commonDialogService.open(ConnectionDialog, null);
|
||||
}
|
||||
|
||||
private async loadTemplateConnections() {
|
||||
try {
|
||||
await this.projectsService.load();
|
||||
await this.templateConnectionsResource.load();
|
||||
} catch (error: any) {
|
||||
this.notificationService.logException(error, 'Template Connections loading failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ export default [
|
||||
['basicConnection_connectionDialog_passwordPlaceholder', 'password'],
|
||||
['basicConnection_connectionDialog_connecting', 'Connecting...'],
|
||||
['basicConnection_connectionDialog_connecting_message', 'Connecting to database...'],
|
||||
['basicConnection_main_menu_item', 'From Template'],
|
||||
['plugin_connection_template_action_connection_template_label', 'From Template'],
|
||||
];
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_CONNECTION_DISCONNECT_ALL = createAction(
|
||||
'connection-disconnect-all',
|
||||
{
|
||||
label: 'plugin_connections_action_disconnect_all_label',
|
||||
}
|
||||
);
|
||||
@@ -13,6 +13,7 @@ import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { DATA_CONTEXT_NAV_NODE, EObjectFeature, NavNodeManagerService } from '@cloudbeaver/core-navigation-tree';
|
||||
import { CONNECTION_NAVIGATOR_VIEW_SETTINGS, isNavigatorViewSettingsEqual, NavigatorViewSettings, PermissionsService } from '@cloudbeaver/core-root';
|
||||
import { ActionService, ACTION_DELETE, DATA_CONTEXT_MENU, DATA_CONTEXT_MENU_NESTED, MenuSeparatorItem, MenuService } from '@cloudbeaver/core-view';
|
||||
import { TOP_APP_BAR_MENU } from '@cloudbeaver/plugin-top-app-bar';
|
||||
|
||||
import { ConnectionsSettingsService } from '../ConnectionsSettingsService';
|
||||
import { PublicConnectionFormService } from '../PublicConnectionForm/PublicConnectionFormService';
|
||||
@@ -23,6 +24,7 @@ import { ACTION_CONNECTION_VIEW_SIMPLE } from './Actions/ACTION_CONNECTION_VIEW_
|
||||
import { ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS } from './Actions/ACTION_CONNECTION_VIEW_SYSTEM_OBJECTS';
|
||||
import { DATA_CONTEXT_CONNECTION } from './DATA_CONTEXT_CONNECTION';
|
||||
import { MENU_CONNECTION_VIEW } from './MENU_CONNECTION_VIEW';
|
||||
import { MENU_CONNECTIONS } from './MENU_CONNECTIONS';
|
||||
|
||||
@injectable()
|
||||
export class ConnectionMenuBootstrap extends Bootstrap {
|
||||
@@ -41,6 +43,8 @@ export class ConnectionMenuBootstrap extends Bootstrap {
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.addConnectionsMenuToTopAppBar();
|
||||
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => {
|
||||
if (
|
||||
@@ -225,4 +229,14 @@ export class ConnectionMenuBootstrap extends Bootstrap {
|
||||
this.notificationService.logException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private addConnectionsMenuToTopAppBar() {
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === TOP_APP_BAR_MENU,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
MENU_CONNECTIONS,
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 MENU_CONNECTIONS = createMenu(
|
||||
'connections',
|
||||
'plugin_connections_menu_connections_label'
|
||||
);
|
||||
@@ -8,28 +8,45 @@
|
||||
|
||||
import { ConnectionsManagerService } from '@cloudbeaver/core-connections';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { EMainMenu, MainMenuService } from '@cloudbeaver/plugin-top-app-bar';
|
||||
import { MenuService, ActionService, DATA_CONTEXT_MENU } from '@cloudbeaver/core-view';
|
||||
|
||||
import { ACTION_CONNECTION_DISCONNECT_ALL } from './ContextMenu/Actions/ACTION_CONNECTION_DISCONNECT_ALL';
|
||||
import { MENU_CONNECTIONS } from './ContextMenu/MENU_CONNECTIONS';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly mainMenuService: MainMenuService,
|
||||
private readonly menuService: MenuService,
|
||||
private readonly actionService: ActionService,
|
||||
private readonly connectionsManagerService: ConnectionsManagerService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.mainMenuService.registerMenuItem(
|
||||
EMainMenu.mainMenuConnectionsPanel,
|
||||
{
|
||||
id: 'mainMenuDisconnect',
|
||||
order: 3,
|
||||
title: 'app_shared_connectionMenu_disconnect',
|
||||
onClick: () => this.connectionsManagerService.closeAllConnections(),
|
||||
isDisabled: () => !this.connectionsManagerService.hasAnyConnection(true),
|
||||
}
|
||||
);
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_CONNECTIONS,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
ACTION_CONNECTION_DISCONNECT_ALL,
|
||||
],
|
||||
});
|
||||
|
||||
this.actionService.addHandler({
|
||||
id: 'connection-base',
|
||||
isActionApplicable: (context, action) => [
|
||||
ACTION_CONNECTION_DISCONNECT_ALL,
|
||||
].includes(action),
|
||||
isDisabled: () => !this.connectionsManagerService.hasAnyConnection(true),
|
||||
handler: async (context, action) => {
|
||||
switch (action) {
|
||||
case ACTION_CONNECTION_DISCONNECT_ALL: {
|
||||
await this.connectionsManagerService.closeAllConnections();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
load(): void { }
|
||||
|
||||
@@ -16,6 +16,7 @@ export * from './ConnectionForm/IConnectionFormProps';
|
||||
export * from './ConnectionForm/useConnectionFormState';
|
||||
export * from './ContextMenu/DATA_CONTEXT_CONNECTION';
|
||||
export * from './ContextMenu/MENU_CONNECTION_VIEW';
|
||||
export * from './ContextMenu/MENU_CONNECTIONS';
|
||||
export * from './PublicConnectionForm/PublicConnectionFormService';
|
||||
export * from './ConnectionAuthService';
|
||||
|
||||
|
||||
@@ -12,4 +12,6 @@ export default [
|
||||
['plugin_connections_connection_form_host_configuration_invalid', 'Host configuration is not supported'],
|
||||
['plugin_connections_connection_form_name_invalid', 'Field \'name\' can\'t be empty'],
|
||||
['connections_public_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'],
|
||||
['plugin_connections_menu_connections_label', 'Connection'],
|
||||
['plugin_connections_action_disconnect_all_label', 'Disconnect All'],
|
||||
];
|
||||
|
||||
@@ -11,4 +11,6 @@ export default [
|
||||
['plugin_connections_connection_form_host_configuration_invalid', 'Host configuration is not supported'],
|
||||
['plugin_connections_connection_form_name_invalid', 'Field \'name\' can\'t be empty'],
|
||||
['connections_public_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'],
|
||||
['plugin_connections_menu_connections_label', 'Connessione'],
|
||||
['plugin_connections_action_disconnect_all_label', 'Scollegati da tutto'],
|
||||
];
|
||||
|
||||
@@ -11,4 +11,6 @@ export default [
|
||||
['plugin_connections_connection_form_host_configuration_invalid', 'Конфигурация хоста не поддерживается'],
|
||||
['plugin_connections_connection_form_name_invalid', 'Поле \'Название\' не может быть пустым'],
|
||||
['connections_public_connection_folder_delete_confirmation', 'Вы удаляете "{arg:name}". Подключения не будут удалены. Вы уверены?'],
|
||||
['plugin_connections_menu_connections_label', 'Подключение'],
|
||||
['plugin_connections_action_disconnect_all_label', 'Отключить все'],
|
||||
];
|
||||
|
||||
@@ -11,4 +11,6 @@ export default [
|
||||
['plugin_connections_connection_form_host_configuration_invalid', 'Host configuration is not supported'],
|
||||
['plugin_connections_connection_form_name_invalid', 'Field \'name\' can\'t be empty'],
|
||||
['connections_public_connection_folder_delete_confirmation', 'You\'re going to delete "{arg:name}". Connections won\'t be deleted. Are you sure?'],
|
||||
['plugin_connections_menu_connections_label', '连接'],
|
||||
['plugin_connections_action_disconnect_all_label', '断开所有连接'],
|
||||
];
|
||||
|
||||
+3
-2
@@ -9,10 +9,11 @@
|
||||
import { action, computed, observable } from 'mobx';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { ILoadableState, isContainsException, useMapResource, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { useMapResource, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { ConnectionInfoResource } from '@cloudbeaver/core-connections';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NavNodeManagerService } from '@cloudbeaver/core-navigation-tree';
|
||||
import { ILoadableState, isContainsException } from '@cloudbeaver/core-utils';
|
||||
import type { ITab } from '@cloudbeaver/plugin-navigation-tabs';
|
||||
import type { IObjectViewerTabState } from '@cloudbeaver/plugin-object-viewer';
|
||||
|
||||
@@ -60,7 +61,7 @@ export function useDataViewerDatabaseDataModel(tab: ITab<IObjectViewerTabState>)
|
||||
},
|
||||
async reload() {
|
||||
if (isContainsException(connection.exception)) {
|
||||
connection.reload?.();
|
||||
connection.reload();
|
||||
}
|
||||
this.init();
|
||||
},
|
||||
|
||||
@@ -51,13 +51,13 @@ const TABLE_HEADER_MENU_BAR_STYLES = css`
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
& item-label {
|
||||
& menu-bar-item-label {
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
& IconOrImage + item-label, & Loader + item-label {
|
||||
& IconOrImage + menu-bar-item-label, & Loader + menu-bar-item-label {
|
||||
padding-left: 8px
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
|
||||
import { createDataContext } from '@cloudbeaver/core-view';
|
||||
|
||||
export const DATA_CONTEXT_MENU_SEARCH = createDataContext<string>('menu-local', '');
|
||||
export const DATA_CONTEXT_MENU_SEARCH = createDataContext<string>('menu-local', () => '');
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_LOG_VIEWER_ENABLE = createAction(
|
||||
'log-viewer-enable',
|
||||
{
|
||||
label: 'plugin_log_viewer_action_enable_label',
|
||||
type: 'checkbox',
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2019-2022 DBeaver Corp
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* NOTICE: All information contained herein is, and remains
|
||||
* the property of DBeaver Corp and its suppliers, if any.
|
||||
* The intellectual and technical concepts contained
|
||||
* herein are proprietary to DBeaver Corp and its suppliers
|
||||
* and may be covered by U.S. and Foreign Patents,
|
||||
* patents in process, and are protected by trade secret or copyright law.
|
||||
* Dissemination of this information or reproduction of this material
|
||||
* is strictly forbidden unless prior written permission is obtained
|
||||
* from DBeaver Corp.
|
||||
*/
|
||||
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { LocalizationService } from '@cloudbeaver/core-localization';
|
||||
|
||||
@injectable()
|
||||
export class LocaleService extends Bootstrap {
|
||||
constructor(private readonly localizationService: LocalizationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.localizationService.addProvider(this.provider.bind(this));
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
|
||||
private async provider(locale: string) {
|
||||
switch (locale) {
|
||||
case 'ru':
|
||||
return (await import('./locales/ru')).default;
|
||||
case 'it':
|
||||
return (await import('./locales/it')).default;
|
||||
case 'zh':
|
||||
return (await import('./locales/zh')).default;
|
||||
default:
|
||||
return (await import('./locales/en')).default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export const LogViewer = observer(function LogViewer() {
|
||||
}, [logViewerState]);
|
||||
|
||||
if (!logViewerState.isActive) {
|
||||
return <TextPlaceholder>{translate('app_shared_toolsMenu_logViewer_placeholder')}</TextPlaceholder>;
|
||||
return <TextPlaceholder>{translate('plugin_log_viewer_placeholder')}</TextPlaceholder>;
|
||||
}
|
||||
|
||||
return styled(style)(
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
*/
|
||||
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { ToolsPanelService } from '@cloudbeaver/plugin-tools-panel';
|
||||
import { MainMenuService, EMainMenu } from '@cloudbeaver/plugin-top-app-bar';
|
||||
import { MenuService, ActionService, DATA_CONTEXT_MENU } from '@cloudbeaver/core-view';
|
||||
import { MENU_TOOLS, ToolsPanelService } from '@cloudbeaver/plugin-tools-panel';
|
||||
|
||||
import { ACTION_LOG_VIEWER_ENABLE } from '../Actions/ACTION_LOG_VIEWER_ENABLE';
|
||||
import { LogViewer } from './LogViewer';
|
||||
import { LogViewerService } from './LogViewerService';
|
||||
|
||||
@@ -17,30 +18,43 @@ import { LogViewerService } from './LogViewerService';
|
||||
@injectable()
|
||||
export class LogViewerBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly mainMenuService: MainMenuService,
|
||||
private readonly toolsPanelService: ToolsPanelService,
|
||||
private readonly menuService: MenuService,
|
||||
private readonly actionService: ActionService,
|
||||
private readonly logViewerService: LogViewerService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.mainMenuService.registerMenuItem(
|
||||
EMainMenu.mainMenuToolsPanel,
|
||||
{
|
||||
id: 'openLogViewer',
|
||||
order: 1,
|
||||
type: 'checkbox',
|
||||
isChecked: () => this.logViewerService.isActive,
|
||||
title: 'app_shared_toolsMenu_logViewer',
|
||||
onClick: () => this.logViewerService.toggle(),
|
||||
}
|
||||
);
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_TOOLS,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
ACTION_LOG_VIEWER_ENABLE,
|
||||
],
|
||||
});
|
||||
|
||||
this.actionService.addHandler({
|
||||
id: 'log-viewer-base',
|
||||
isActionApplicable: (context, action) => [
|
||||
ACTION_LOG_VIEWER_ENABLE,
|
||||
].includes(action),
|
||||
isChecked: () => this.logViewerService.isActive,
|
||||
handler: (context, action) => {
|
||||
switch (action) {
|
||||
case ACTION_LOG_VIEWER_ENABLE: {
|
||||
this.logViewerService.toggle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.toolsPanelService.tabsContainer.add({
|
||||
key: 'log-viewer-tab',
|
||||
order: 0,
|
||||
name: 'app_shared_toolsMenu_logViewer',
|
||||
name: 'plugin_log_viewer_action_enable_label',
|
||||
isHidden: () => !this.logViewerService.isActive,
|
||||
onClose: () => this.logViewerService.toggle(),
|
||||
panel: () => LogViewer,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
export default [
|
||||
['plugin_log_viewer_action_enable_label', 'Log Viewer'],
|
||||
['plugin_log_viewer_placeholder', 'Log viewer is not active'],
|
||||
];
|
||||
@@ -0,0 +1,4 @@
|
||||
export default [
|
||||
['plugin_log_viewer_action_enable_label', 'Visualizzatore del Log'],
|
||||
['plugin_log_viewer_placeholder', 'Il visualizzatore del log non è attivo'],
|
||||
];
|
||||
@@ -0,0 +1,4 @@
|
||||
export default [
|
||||
['plugin_log_viewer_action_enable_label', 'Просмотр лога'],
|
||||
['plugin_log_viewer_placeholder', 'Просмотр логов неактивен'],
|
||||
];
|
||||
@@ -0,0 +1,4 @@
|
||||
export default [
|
||||
['plugin_log_viewer_action_enable_label', '日志查看器'],
|
||||
['plugin_log_viewer_placeholder', '日志查看器未激活'],
|
||||
];
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
|
||||
import { LocaleService } from './LocaleService';
|
||||
import { LogViewerBootstrap } from './LogViewer/LogViewerBootstrap';
|
||||
import { LogViewerService } from './LogViewer/LogViewerService';
|
||||
import { LogViewerSettingsService } from './LogViewer/LogViewerSettingsService';
|
||||
@@ -17,6 +18,7 @@ export const logViewerPlugin: PluginManifest = {
|
||||
providers: [
|
||||
LogViewerBootstrap,
|
||||
LogViewerService,
|
||||
LocaleService,
|
||||
LogViewerSettingsService,
|
||||
],
|
||||
};
|
||||
+2
-2
@@ -9,8 +9,8 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { ILoadableState, Loader, Translate, TreeNodeNestedMessage, TREE_NODE_STYLES } from '@cloudbeaver/core-blocks';
|
||||
|
||||
import { Loader, Translate, TreeNodeNestedMessage, TREE_NODE_STYLES } from '@cloudbeaver/core-blocks';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { IElementsTreeContext } from './ElementsTreeContext';
|
||||
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ const MENU_STYLES = css`
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
& item-label {
|
||||
& menu-bar-item-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
import { action, computed, observable, runInAction } from 'mobx';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { IFolderExplorerContext, ILoadableState, useExecutor, useMapResource, useObjectRef, useObservableRef, useUserData } from '@cloudbeaver/core-blocks';
|
||||
import { IFolderExplorerContext, useExecutor, useMapResource, useObjectRef, useObservableRef, useUserData } from '@cloudbeaver/core-blocks';
|
||||
import { ConnectionInfoResource } from '@cloudbeaver/core-connections';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
@@ -17,7 +17,7 @@ import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import { type NavNode, NavNodeInfoResource, NavTreeResource } from '@cloudbeaver/core-navigation-tree';
|
||||
import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { CachedMapAllKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk';
|
||||
import { MetadataMap, throttle } from '@cloudbeaver/core-utils';
|
||||
import { ILoadableState, MetadataMap, throttle } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { IElementsTreeAction } from './IElementsTreeAction';
|
||||
import type { NavigationNodeRendererComponent } from './NavigationNodeComponent';
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_RESOURCE_MANAGER = createAction(
|
||||
'resource-manager-enable',
|
||||
{
|
||||
label: 'plugin_resource_manager_action_enable_label',
|
||||
type: 'checkbox',
|
||||
}
|
||||
);
|
||||
@@ -7,35 +7,61 @@
|
||||
*/
|
||||
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { getCachedDataResourceLoaderState } from '@cloudbeaver/core-sdk';
|
||||
import { SideBarPanelService } from '@cloudbeaver/core-ui';
|
||||
import { EMainMenu, MainMenuService } from '@cloudbeaver/plugin-top-app-bar';
|
||||
import { ActionService, DATA_CONTEXT_LOADABLE_STATE, DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view';
|
||||
import { MENU_TOOLS } from '@cloudbeaver/plugin-tools-panel';
|
||||
|
||||
import { ACTION_RESOURCE_MANAGER } from './Actions/ACTION_RESOURCE_MANAGER';
|
||||
import { ResourceManager } from './ResourceManager';
|
||||
import { ResourceManagerService } from './ResourceManagerService';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly mainMenuService: MainMenuService,
|
||||
private readonly resourceManagerService: ResourceManagerService,
|
||||
private readonly sideBarPanelService: SideBarPanelService,
|
||||
private readonly menuService: MenuService,
|
||||
private readonly actionService: ActionService,
|
||||
private readonly serverConfigResource: ServerConfigResource
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.mainMenuService.registerMenuItem(
|
||||
EMainMenu.mainMenuToolsPanel,
|
||||
{
|
||||
id: 'resourceManagementTrigger',
|
||||
order: 3,
|
||||
type: 'checkbox',
|
||||
title: 'plugin_resource_manager_title',
|
||||
isHidden: () => !this.resourceManagerService.enabled,
|
||||
isChecked: () => this.resourceManagerService.active,
|
||||
onClick: this.resourceManagerService.togglePanel,
|
||||
}
|
||||
);
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === MENU_TOOLS,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
ACTION_RESOURCE_MANAGER,
|
||||
],
|
||||
});
|
||||
|
||||
this.actionService.addHandler({
|
||||
id: 'resource-manager-base',
|
||||
isActionApplicable: (context, action) => [
|
||||
ACTION_RESOURCE_MANAGER,
|
||||
].includes(action),
|
||||
isHidden: () => !this.resourceManagerService.enabled,
|
||||
isChecked: () => this.resourceManagerService.active,
|
||||
getLoader: (context, action) => {
|
||||
const state = context.get(DATA_CONTEXT_LOADABLE_STATE);
|
||||
|
||||
return state.getState(
|
||||
action.id,
|
||||
() => getCachedDataResourceLoaderState(this.serverConfigResource, undefined, undefined)
|
||||
);
|
||||
},
|
||||
handler: (context, action) => {
|
||||
switch (action) {
|
||||
case ACTION_RESOURCE_MANAGER: {
|
||||
this.resourceManagerService.togglePanel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.sideBarPanelService.tabsContainer.add({
|
||||
key: 'resource-manager-tab',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export default [
|
||||
['plugin_resource_manager_action_enable_label', 'Resource manager'],
|
||||
['plugin_resource_manager_title', 'Resource manager'],
|
||||
['plugin_resource_manager_no_resources_placeholder', 'There are no resources yet'],
|
||||
['plugin_resource_manager_script_name', 'Script name'],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export default [
|
||||
['plugin_resource_manager_action_enable_label', 'Resource manager'],
|
||||
['plugin_resource_manager_title', 'Resource manager'],
|
||||
['plugin_resource_manager_no_resources_placeholder', 'No resources'],
|
||||
['plugin_resource_manager_script_name', 'Script name'],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export default [
|
||||
['plugin_resource_manager_action_enable_label', 'Управление ресурсами'],
|
||||
['plugin_resource_manager_title', 'Управление ресурсами'],
|
||||
['plugin_resource_manager_no_resources_placeholder', 'Нет ресурсов'],
|
||||
['plugin_resource_manager_script_name', 'Имя скрипта'],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export default [
|
||||
['plugin_resource_manager_action_enable_label', '资源管理器'],
|
||||
['plugin_resource_manager_title', '资源管理器'],
|
||||
['plugin_resource_manager_no_resources_placeholder', '无资源'],
|
||||
['plugin_resource_manager_script_name', '脚本名称'],
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_SQL_EDITOR_NEW = createAction(
|
||||
'sql-editor-new',
|
||||
{
|
||||
label: 'plugin_sql_editor_navigation_tab_action_sql_editor_new',
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2019-2022 DBeaver Corp
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* NOTICE: All information contained herein is, and remains
|
||||
* the property of DBeaver Corp and its suppliers, if any.
|
||||
* The intellectual and technical concepts contained
|
||||
* herein are proprietary to DBeaver Corp and its suppliers
|
||||
* and may be covered by U.S. and Foreign Patents,
|
||||
* patents in process, and are protected by trade secret or copyright law.
|
||||
* Dissemination of this information or reproduction of this material
|
||||
* is strictly forbidden unless prior written permission is obtained
|
||||
* from DBeaver Corp.
|
||||
*/
|
||||
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { LocalizationService } from '@cloudbeaver/core-localization';
|
||||
|
||||
@injectable()
|
||||
export class LocaleService extends Bootstrap {
|
||||
constructor(private readonly localizationService: LocalizationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.localizationService.addProvider(this.provider.bind(this));
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
|
||||
private async provider(locale: string) {
|
||||
switch (locale) {
|
||||
case 'ru':
|
||||
return (await import('./locales/ru')).default;
|
||||
case 'it':
|
||||
return (await import('./locales/it')).default;
|
||||
case 'zh':
|
||||
return (await import('./locales/zh')).default;
|
||||
default:
|
||||
return (await import('./locales/en')).default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,13 +13,14 @@ import type { IExecutorHandler } from '@cloudbeaver/core-executor';
|
||||
import { ExtensionUtils } from '@cloudbeaver/core-extensions';
|
||||
import { DATA_CONTEXT_NAV_NODE, EObjectFeature } from '@cloudbeaver/core-navigation-tree';
|
||||
import { ISessionAction, sessionActionContext, SessionActionService } from '@cloudbeaver/core-root';
|
||||
import { ActionService, ACTION_RENAME, DATA_CONTEXT_MENU_NESTED, menuExtractActions, MenuService, ViewService } from '@cloudbeaver/core-view';
|
||||
import { DATA_CONTEXT_CONNECTION } from '@cloudbeaver/plugin-connections';
|
||||
import { ActionService, ACTION_RENAME, DATA_CONTEXT_MENU, DATA_CONTEXT_MENU_NESTED, menuExtractActions, MenuService, ViewService } from '@cloudbeaver/core-view';
|
||||
import { DATA_CONTEXT_CONNECTION, MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections';
|
||||
import { ConnectionSchemaManagerService } from '@cloudbeaver/plugin-datasource-context-switch';
|
||||
import { NavigationTabsService } from '@cloudbeaver/plugin-navigation-tabs';
|
||||
import { DATA_CONTEXT_SQL_EDITOR_STATE, ESqlDataSourceFeatures, getSqlEditorName, LocalStorageSqlDataSource, SqlDataSourceService, SqlEditorService } from '@cloudbeaver/plugin-sql-editor';
|
||||
import { MainMenuService } from '@cloudbeaver/plugin-top-app-bar';
|
||||
import { TOP_APP_BAR_MENU } from '@cloudbeaver/plugin-top-app-bar';
|
||||
|
||||
import { ACTION_SQL_EDITOR_NEW } from './ACTION_SQL_EDITOR_NEW';
|
||||
import { ACTION_SQL_EDITOR_OPEN } from './ACTION_SQL_EDITOR_OPEN';
|
||||
import { DATA_CONTEXT_SQL_EDITOR_TAB } from './DATA_CONTEXT_SQL_EDITOR_TAB';
|
||||
import { isSessionActionOpenSQLEditor } from './sessionActionOpenSQLEditor';
|
||||
@@ -30,7 +31,6 @@ import { SqlEditorTabService } from './SqlEditorTabService';
|
||||
@injectable()
|
||||
export class SqlEditorBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly mainMenuService: MainMenuService,
|
||||
private readonly sqlEditorNavigatorService: SqlEditorNavigatorService,
|
||||
private readonly navigationTabsService: NavigationTabsService,
|
||||
private readonly connectionSchemaManagerService: ConnectionSchemaManagerService,
|
||||
@@ -48,14 +48,7 @@ export class SqlEditorBootstrap extends Bootstrap {
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.mainMenuService.registerRootItem(
|
||||
{
|
||||
id: 'sql-editor',
|
||||
title: 'SQL',
|
||||
order: 2,
|
||||
onClick: this.openSQLEditor.bind(this),
|
||||
}
|
||||
);
|
||||
this.registerTopAppBarItem();
|
||||
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.has(DATA_CONTEXT_SQL_EDITOR_STATE) && context.has(DATA_CONTEXT_SQL_EDITOR_TAB),
|
||||
@@ -179,6 +172,48 @@ export class SqlEditorBootstrap extends Bootstrap {
|
||||
|
||||
load(): void { }
|
||||
|
||||
private registerTopAppBarItem() {
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === TOP_APP_BAR_MENU,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
ACTION_SQL_EDITOR_NEW,
|
||||
],
|
||||
orderItems: (context, items) => {
|
||||
let placeIndex = items.indexOf(ACTION_SQL_EDITOR_NEW);
|
||||
|
||||
const actionsOpen = menuExtractActions(items, [
|
||||
ACTION_SQL_EDITOR_NEW,
|
||||
]);
|
||||
|
||||
const connectionsIndex = items.indexOf(MENU_CONNECTIONS);
|
||||
|
||||
if (connectionsIndex !== -1) {
|
||||
placeIndex = connectionsIndex + 1;
|
||||
}
|
||||
|
||||
items.splice(placeIndex, 0, ...actionsOpen);
|
||||
|
||||
return items;
|
||||
},
|
||||
});
|
||||
|
||||
this.actionService.addHandler({
|
||||
id: 'sql-editor-new',
|
||||
isActionApplicable: (context, action) => [
|
||||
ACTION_SQL_EDITOR_NEW,
|
||||
].includes(action),
|
||||
handler: (context, action) => {
|
||||
switch (action) {
|
||||
case ACTION_SQL_EDITOR_NEW: {
|
||||
this.openSQLEditor();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private openSQLEditor() {
|
||||
let connectionKey: IConnectionInfoParams | undefined;
|
||||
let catalogId: string | undefined;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_sql_editor_navigation_tab_action_sql_editor_new', 'SQL'],
|
||||
];
|
||||
@@ -0,0 +1,2 @@
|
||||
export default [
|
||||
];
|
||||
@@ -0,0 +1,2 @@
|
||||
export default [
|
||||
];
|
||||
@@ -0,0 +1,2 @@
|
||||
export default [
|
||||
];
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import type { PluginManifest } from '@cloudbeaver/core-di';
|
||||
|
||||
import { LocaleService } from './LocaleService';
|
||||
import { SqlEditorBootstrap } from './SqlEditorBootstrap';
|
||||
import { SqlEditorNavigatorService } from './SqlEditorNavigatorService';
|
||||
import { SqlEditorTabService } from './SqlEditorTabService';
|
||||
@@ -21,5 +22,6 @@ export const sqlEditorTabPluginManifest: PluginManifest = {
|
||||
SqlEditorBootstrap,
|
||||
SqlEditorTabService,
|
||||
SqlEditorNavigatorService,
|
||||
LocaleService,
|
||||
],
|
||||
};
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import type { ILoadableState } from '@cloudbeaver/core-blocks';
|
||||
import type { IConnectionExecutionContextInfo } from '@cloudbeaver/core-connections';
|
||||
import type { ISyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import type { ILoadableState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import type { ESqlDataSourceFeatures } from './ESqlDataSourceFeatures';
|
||||
|
||||
|
||||
@@ -43,13 +43,13 @@ export const SQL_EDITOR_ACTIONS_MENU_STYLES = css`
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
& item-label {
|
||||
& menu-bar-item-label {
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
& IconOrImage + item-label, & Loader + item-label {
|
||||
& IconOrImage + menu-bar-item-label, & Loader + menu-bar-item-label {
|
||||
padding-left: 8px
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
"@cloudbeaver/core-utils": "~0.1.0",
|
||||
"@cloudbeaver/core-view": "~0.1.0",
|
||||
"@cloudbeaver/plugin-version": "~0.1.0",
|
||||
"@cloudbeaver/plugin-settings-menu": "~0.1.0"
|
||||
"@cloudbeaver/plugin-settings-menu": "~0.1.0",
|
||||
"@cloudbeaver/plugin-top-app-bar": "~0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "~18.x.x",
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2019-2022 DBeaver Corp
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* NOTICE: All information contained herein is, and remains
|
||||
* the property of DBeaver Corp and its suppliers, if any.
|
||||
* The intellectual and technical concepts contained
|
||||
* herein are proprietary to DBeaver Corp and its suppliers
|
||||
* and may be covered by U.S. and Foreign Patents,
|
||||
* patents in process, and are protected by trade secret or copyright law.
|
||||
* Dissemination of this information or reproduction of this material
|
||||
* is strictly forbidden unless prior written permission is obtained
|
||||
* from DBeaver Corp.
|
||||
*/
|
||||
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { LocalizationService } from '@cloudbeaver/core-localization';
|
||||
|
||||
@injectable()
|
||||
export class LocaleService extends Bootstrap {
|
||||
constructor(private readonly localizationService: LocalizationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.localizationService.addProvider(this.provider.bind(this));
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
|
||||
private async provider(locale: string) {
|
||||
switch (locale) {
|
||||
case 'ru':
|
||||
return (await import('./locales/ru')).default;
|
||||
case 'it':
|
||||
return (await import('./locales/it')).default;
|
||||
case 'zh':
|
||||
return (await import('./locales/zh')).default;
|
||||
default:
|
||||
return (await import('./locales/en')).default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2022 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 MENU_TOOLS = createMenu(
|
||||
'tools',
|
||||
'plugin_tools_panel_menu_title'
|
||||
);
|
||||
@@ -7,14 +7,28 @@
|
||||
*/
|
||||
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { DATA_CONTEXT_MENU, MenuService } from '@cloudbeaver/core-view';
|
||||
import { TOP_APP_BAR_MENU } from '@cloudbeaver/plugin-top-app-bar';
|
||||
|
||||
import { MENU_TOOLS } from './Menu/MENU_TOOLS';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor() {
|
||||
constructor(
|
||||
private readonly menuService: MenuService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> { }
|
||||
register(): void {
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.tryGet(DATA_CONTEXT_MENU) === TOP_APP_BAR_MENU,
|
||||
getItems: (context, items) => [
|
||||
...items,
|
||||
MENU_TOOLS,
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './Menu/MENU_TOOLS';
|
||||
export * from './ToolsPanel/ToolsPanelService';
|
||||
export * from './ToolsPanel/ToolsPanel';
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_tools_panel_menu_title', 'Tools'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_tools_panel_menu_title', 'Strumenti'],
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
export default [
|
||||
['plugin_tools_panel_menu_title', 'Инструменты'],
|
||||
];
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user