mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
feat: CB-1407 open sql editor in the separate browser tab
This commit is contained in:
+3
-1
@@ -11,13 +11,15 @@ import { useCallback } from 'react';
|
||||
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { usePermission } from '@cloudbeaver/core-root';
|
||||
import type { ScreenComponent } from '@cloudbeaver/core-routing';
|
||||
|
||||
import { Administration } from '../Administration/Administration';
|
||||
import { EAdminPermission } from '../EAdminPermission';
|
||||
import { AdministrationScreenService } from './AdministrationScreenService';
|
||||
import { AdministrationTopAppBar } from './AdministrationTopAppBar/AdministrationTopAppBar';
|
||||
import type { IAdministrationScreenParams } from './IAdministrationScreenParams';
|
||||
|
||||
export const AdministrationScreen = observer(function AdministrationScreen() {
|
||||
export const AdministrationScreen: ScreenComponent<IAdministrationScreenParams> = observer(function AdministrationScreen() {
|
||||
const administrationScreenService = useService(AdministrationScreenService);
|
||||
|
||||
const handleSelect = useCallback(
|
||||
|
||||
+8
-8
@@ -103,9 +103,9 @@ export class AdministrationScreenService {
|
||||
|
||||
navigateToRoot(): void {
|
||||
if (this.isConfigurationMode) {
|
||||
this.screenService.navigate(AdministrationScreenService.setupName);
|
||||
this.screenService.navigateToScreen(AdministrationScreenService.setupName);
|
||||
} else {
|
||||
this.screenService.navigate(AdministrationScreenService.screenName);
|
||||
this.screenService.navigateToScreen(AdministrationScreenService.screenName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,25 +119,25 @@ export class AdministrationScreenService {
|
||||
|
||||
navigateToItem(item: string): void {
|
||||
if (this.isConfigurationMode) {
|
||||
this.screenService.navigate(AdministrationScreenService.setupItemRouteName, item);
|
||||
this.screenService.navigateToScreen(AdministrationScreenService.setupItemRouteName, item);
|
||||
} else {
|
||||
this.screenService.navigate(AdministrationScreenService.itemRouteName, item);
|
||||
this.screenService.navigateToScreen(AdministrationScreenService.itemRouteName, item);
|
||||
}
|
||||
}
|
||||
|
||||
navigateToItemSub(item: string, sub: string, param?: string | null): void {
|
||||
if (!param) {
|
||||
if (this.isConfigurationMode) {
|
||||
this.screenService.navigate(AdministrationScreenService.setupItemSubRouteName, item, sub);
|
||||
this.screenService.navigateToScreen(AdministrationScreenService.setupItemSubRouteName, item, sub);
|
||||
} else {
|
||||
this.screenService.navigate(AdministrationScreenService.itemSubRouteName, item, sub);
|
||||
this.screenService.navigateToScreen(AdministrationScreenService.itemSubRouteName, item, sub);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.isConfigurationMode) {
|
||||
this.screenService.navigate(AdministrationScreenService.setupItemSubParamRouteName, item, sub, param);
|
||||
this.screenService.navigateToScreen(AdministrationScreenService.setupItemSubParamRouteName, item, sub, param);
|
||||
} else {
|
||||
this.screenService.navigate(AdministrationScreenService.itemSubParamRouteName, item, sub, param);
|
||||
this.screenService.navigateToScreen(AdministrationScreenService.itemSubParamRouteName, item, sub, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface IAdministrationScreenParams {
|
||||
item?: string;
|
||||
sub?: string;
|
||||
param?: string;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ export const Body = observer(function Body() {
|
||||
<theme ref={ref}>
|
||||
<Loader state={permissionsService}>{() => styled(style)(
|
||||
<>
|
||||
{Screen && <Screen />}
|
||||
{Screen && <Screen {...screenService.routerService.params} />}
|
||||
</>
|
||||
)}
|
||||
</Loader>
|
||||
|
||||
@@ -14,7 +14,7 @@ import { injectable } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import { LocalStorageSaveService } from '@cloudbeaver/core-settings';
|
||||
import { IActiveView, View } from '@cloudbeaver/core-view';
|
||||
import { ACTION_OPEN_IN_TAB, IActiveView, View } from '@cloudbeaver/core-view';
|
||||
|
||||
import type { ITab } from './ITab';
|
||||
import { TabHandler, TabHandlerOptions, TabHandlerEvent } from './TabHandler';
|
||||
@@ -73,6 +73,8 @@ export class NavigationTabsService extends View<ITab<any>> {
|
||||
this.onTabSelect = new SyncExecutor();
|
||||
this.onTabClose = new SyncExecutor();
|
||||
|
||||
this.registerAction(ACTION_OPEN_IN_TAB);
|
||||
|
||||
makeObservable<NavigationTabsService, 'unloadTabs'>(this, {
|
||||
handlers: observable,
|
||||
tabsMap: observable,
|
||||
|
||||
@@ -38,6 +38,7 @@ export const defaultENLocale = [
|
||||
['ui_revoke', 'Revoke'],
|
||||
['ui_grant', 'Grant'],
|
||||
['ui_edit', 'Edit'],
|
||||
['ui_open_in_tab', 'Open in tab'],
|
||||
['ui_rename', 'Rename'],
|
||||
['ui_rename_processing', 'Renaming...'],
|
||||
['ui_name', 'Name'],
|
||||
|
||||
@@ -36,6 +36,7 @@ export const defaultRULocale = [
|
||||
['ui_revoke', 'Запретить'],
|
||||
['ui_grant', 'Разрешить'],
|
||||
['ui_edit', 'Редактировать'],
|
||||
['ui_open_in_tab', 'Открыть во вкладке'],
|
||||
['ui_rename', 'Переименовать'],
|
||||
['ui_rename_processing', 'Переименование...'],
|
||||
['ui_name', 'Название'],
|
||||
|
||||
@@ -10,14 +10,14 @@ import type { Route, State as RouterState } from 'router5';
|
||||
|
||||
export type ScreenRoute = Omit<Route, 'children'>;
|
||||
|
||||
export interface IScreen {
|
||||
export interface IScreen<T extends Record<string, any> = Record<string, any>> {
|
||||
name: string;
|
||||
routes: ScreenRoute[];
|
||||
component: ScreenComponent;
|
||||
component: ScreenComponent<T>;
|
||||
root?: boolean;
|
||||
onActivate?: (state: RouterState, prevState?: RouterState) => void | Promise<void>;
|
||||
onDeactivate?: (state: RouterState, nextState: RouterState) => void | Promise<void>;
|
||||
canDeActivate?: (state: RouterState, nextState: RouterState) => boolean | Promise<boolean>;
|
||||
}
|
||||
|
||||
export type ScreenComponent = React.FunctionComponent;
|
||||
export type ScreenComponent<T = Record<string, any>> = React.FunctionComponent<T>;
|
||||
|
||||
@@ -17,13 +17,13 @@ import type { IScreen, ScreenRoute } from './IScreen';
|
||||
|
||||
@injectable()
|
||||
export class ScreenService {
|
||||
get screen(): IScreen | undefined {
|
||||
get screen(): IScreen<any> | undefined {
|
||||
return this.getScreenByRoute(this.routerService.route);
|
||||
}
|
||||
|
||||
readonly routeChange: IExecutor;
|
||||
|
||||
private screens = new Map<string, IScreen>();
|
||||
private screens = new Map<string, IScreen<any>>();
|
||||
private routeScreenMap = new Map<string, string>();
|
||||
|
||||
constructor(
|
||||
@@ -47,11 +47,15 @@ export class ScreenService {
|
||||
}
|
||||
}
|
||||
|
||||
navigate(screen: string, item?: string, sub?: string, param?: string): void {
|
||||
navigateToScreen(screen: string, item?: string, sub?: string, param?: string): void {
|
||||
this.routerService.router.navigate(screen, { item, sub, param });
|
||||
}
|
||||
|
||||
create(screen: IScreen): void {
|
||||
navigate(screen: string, params?: Record<string, any>) {
|
||||
this.routerService.router.navigate(screen, params as any);
|
||||
}
|
||||
|
||||
create<T extends Record<string, any>>(screen: IScreen<T>): void {
|
||||
if (this.screens.has(screen.name)) {
|
||||
return;
|
||||
}
|
||||
@@ -78,11 +82,11 @@ export class ScreenService {
|
||||
return screen?.name === name;
|
||||
}
|
||||
|
||||
buildUrl(screen: string): string {
|
||||
return this.routerService.router.buildUrl(screen);
|
||||
buildUrl(screen: string, params?: Record<string, any>): string {
|
||||
return this.routerService.router.buildUrl(screen, params);
|
||||
}
|
||||
|
||||
getScreenByRoute(route: string): IScreen | undefined {
|
||||
getScreenByRoute(route: string): IScreen<any> | undefined {
|
||||
const screen = this.routeScreenMap.get(route);
|
||||
if (!screen) {
|
||||
return undefined;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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 { createAction } from '../createAction';
|
||||
|
||||
export const ACTION_OPEN_IN_TAB = createAction('open-in-tab', {
|
||||
label: 'ui_open_in_tab',
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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 { createKeyBinding } from '../createKeyBinding';
|
||||
|
||||
export const KEY_BINDING_OPEN_IN_TAB = createKeyBinding({
|
||||
id: 'open-in-tab',
|
||||
label: 'ui_rename',
|
||||
keys: 'alt+t',
|
||||
});
|
||||
@@ -20,6 +20,13 @@ export class KeyBindingService {
|
||||
this.handlers = new Map();
|
||||
}
|
||||
|
||||
addKeyBindingHandler(handler: IKeyBindingHandler): void {
|
||||
if (this.handlers.has(handler.id)) {
|
||||
throw new Error(`Key binding handler with same id (${handler.id}) already exists`);
|
||||
}
|
||||
this.handlers.set(handler.id, handler);
|
||||
}
|
||||
|
||||
getKeyBindingHandler(context: IDataContextProvider, action: IAction): IKeyBindingHandler | null {
|
||||
for (const handler of this.handlers.values()) {
|
||||
if (handler.isBindingApplicable(context, action)) {
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { makeObservable, observable } from 'mobx';
|
||||
|
||||
import type { DataContextGetter } from './DataContextGetter';
|
||||
import type { IDataContext } from './IDataContext';
|
||||
import type { IDataContextProvider } from './IDataContextProvider';
|
||||
@@ -17,6 +19,11 @@ export class DataContext implements IDataContext {
|
||||
constructor(fallback?: IDataContextProvider) {
|
||||
this.map = new Map();
|
||||
this.fallback = fallback;
|
||||
|
||||
makeObservable<this, 'map'>(this, {
|
||||
map: observable.shallow,
|
||||
fallback: observable.ref,
|
||||
});
|
||||
}
|
||||
|
||||
setFallBack(fallback?: IDataContextProvider): void {
|
||||
@@ -50,6 +57,12 @@ export class DataContext implements IDataContext {
|
||||
return this;
|
||||
}
|
||||
|
||||
delete(context: DataContextGetter<any>): this {
|
||||
this.map.delete(context);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
get<T>(context: DataContextGetter<T>): T {
|
||||
if (!this.map.has(context)) {
|
||||
const defaultValue = context();
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 { makeObservable, observable } from 'mobx';
|
||||
|
||||
import type { DataContextGetter } from './DataContextGetter';
|
||||
import type { IDataContext } from './IDataContext';
|
||||
|
||||
export class DynamicDataContext implements IDataContext {
|
||||
fallback: IDataContext;
|
||||
contexts: Array<DataContextGetter<any>>;
|
||||
|
||||
constructor(fallback: IDataContext) {
|
||||
this.fallback = fallback;
|
||||
this.contexts = [];
|
||||
|
||||
makeObservable(this, {
|
||||
fallback: observable.ref,
|
||||
});
|
||||
}
|
||||
|
||||
setFallBack(fallback: IDataContext): void {
|
||||
this.fallback = fallback;
|
||||
}
|
||||
|
||||
set<T>(context: DataContextGetter<T>, value: T): this {
|
||||
this.contexts.push(context);
|
||||
this.fallback.set(context, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
delete(context: DataContextGetter<any>): this {
|
||||
this.fallback.delete(context);
|
||||
return this;
|
||||
}
|
||||
|
||||
has(context: DataContextGetter<any>): boolean {
|
||||
return this.fallback.has(context);
|
||||
}
|
||||
|
||||
get <T>(context: DataContextGetter<T>): T {
|
||||
return this.fallback.get(context);
|
||||
}
|
||||
|
||||
find <T>(context: DataContextGetter<T>, value: T): boolean {
|
||||
return this.fallback.find(context, value);
|
||||
}
|
||||
|
||||
tryGet <T>(context: DataContextGetter<T>): T | undefined {
|
||||
return this.fallback.tryGet(context);
|
||||
}
|
||||
|
||||
flush(): void {
|
||||
this.contexts = [];
|
||||
}
|
||||
}
|
||||
@@ -11,4 +11,5 @@ import type { IDataContextProvider } from './IDataContextProvider';
|
||||
|
||||
export interface IDataContext extends IDataContextProvider {
|
||||
set: <T>(context: DataContextGetter<T>, value: T) => this;
|
||||
delete: (context: DataContextGetter<any>) => this;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 { action } from 'mobx';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useObjectRef } from '@cloudbeaver/core-blocks';
|
||||
|
||||
import { DataContext } from './DataContext';
|
||||
import type { DataContextGetter } from './DataContextGetter';
|
||||
import { DynamicDataContext } from './DynamicDataContext';
|
||||
import type { IDataContext } from './IDataContext';
|
||||
|
||||
export function useDynamicDataContext(context: IDataContext | undefined): IDataContext {
|
||||
const state = useObjectRef(() => ({
|
||||
dynamic: new DynamicDataContext(context || new DataContext()),
|
||||
contexts: [] as Array<DataContextGetter<any>>,
|
||||
}));
|
||||
|
||||
if (context) {
|
||||
state.dynamic.setFallBack(context);
|
||||
}
|
||||
state.contexts = state.dynamic.contexts;
|
||||
state.dynamic.flush();
|
||||
|
||||
useEffect(action(() => {
|
||||
for (const context of state.contexts) {
|
||||
if (!state.dynamic.contexts.includes(context)) {
|
||||
state.dynamic.delete(context);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
return state.dynamic;
|
||||
}
|
||||
@@ -54,7 +54,7 @@ export const CaptureView = observer<Props>(function CaptureView({
|
||||
|
||||
const handlers = actionItems.reduce((map, item) => ({
|
||||
...map,
|
||||
[item.binding!.id]: item.activate.bind(item.handler, true),
|
||||
[item.binding!.id]: () => item.activate(true),
|
||||
}), {});
|
||||
|
||||
return styled(styles)(
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
|
||||
import { createContext } from 'react';
|
||||
|
||||
import type { IDataContextProvider } from '../DataContext/IDataContextProvider';
|
||||
import type { IDataContext } from '../DataContext/IDataContext';
|
||||
|
||||
export const CaptureViewContext = createContext<IDataContextProvider | undefined>(undefined);
|
||||
export const CaptureViewContext = createContext<IDataContext | undefined>(undefined);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 { useContext } from 'react';
|
||||
|
||||
import type { IDataContext } from '../DataContext/IDataContext';
|
||||
import { useDynamicDataContext } from '../DataContext/useDynamicDataContext';
|
||||
import { CaptureViewContext } from './CaptureViewContext';
|
||||
|
||||
export function useCaptureViewContext(): IDataContext | undefined {
|
||||
const context = useContext(CaptureViewContext);
|
||||
const dynamic = useDynamicDataContext(context);
|
||||
|
||||
if (context === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return dynamic;
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
export * from './Action/Actions/ACTION_DELETE';
|
||||
export * from './Action/Actions/ACTION_EXPORT';
|
||||
export * from './Action/Actions/ACTION_OPEN_IN_TAB';
|
||||
export * from './Action/Actions/ACTION_OPEN';
|
||||
export * from './Action/Actions/ACTION_REFRESH';
|
||||
export * from './Action/Actions/ACTION_RENAME';
|
||||
export * from './Action/KeyBinding/Bindings/KEY_BINDING_OPEN_IN_TAB';
|
||||
export * from './Action/KeyBinding/KeyBindingService';
|
||||
export * from './Action/KeyBinding/createKeyBinding';
|
||||
export * from './Action/ActionService';
|
||||
export * from './Action/createAction';
|
||||
export * from './DataContext/DataContext';
|
||||
export * from './DataContext/createDataContext';
|
||||
export * from './DataContext/DataContext';
|
||||
export * from './DataContext/DynamicDataContext';
|
||||
export * from './DataContext/IDataContext';
|
||||
export * from './DataContext/IDataContextProvider';
|
||||
export * from './DataContext/useDynamicDataContext';
|
||||
export * from './Menu/MenuItem/IMenuActionItem';
|
||||
export * from './Menu/MenuItem/IMenuBaseItem';
|
||||
export * from './Menu/MenuItem/IMenuItem';
|
||||
@@ -32,6 +38,7 @@ export * from './View/CaptureViewContext';
|
||||
export * from './View/IActiveView';
|
||||
export * from './View/IView';
|
||||
export * from './View/useActiveView';
|
||||
export * from './View/useCaptureViewContext';
|
||||
export * from './View/View';
|
||||
export * from './View/ViewService';
|
||||
export { manifest as coreViewManifest } from './manifest';
|
||||
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
import type { TabHandlerPanelComponent } from '@cloudbeaver/core-app';
|
||||
import { useTab } from '@cloudbeaver/core-blocks';
|
||||
import { ISqlEditorTabState, SqlEditor } from '@cloudbeaver/plugin-sql-editor';
|
||||
import { useCaptureViewContext } from '@cloudbeaver/core-view';
|
||||
import { DATA_CONTEXT_SQL_EDITOR_STATE, ISqlEditorTabState, SqlEditor } from '@cloudbeaver/plugin-sql-editor';
|
||||
|
||||
export const SqlEditorPanel: TabHandlerPanelComponent<ISqlEditorTabState> = function SqlEditorPanel({ tab }) {
|
||||
const baseTab = useTab(tab.id);
|
||||
const viewContext = useCaptureViewContext();
|
||||
// const navigatorService = useService(SqlEditorNavigatorService);
|
||||
|
||||
// const handleOpen = ({ tabId }: ITabData<any>) => navigatorService.openEditorResult(editorId, tabId);
|
||||
@@ -21,5 +23,7 @@ export const SqlEditorPanel: TabHandlerPanelComponent<ISqlEditorTabState> = func
|
||||
return null;
|
||||
}
|
||||
|
||||
return <SqlEditor editorId={tab.id} state={tab.handlerState} />;
|
||||
viewContext?.set(DATA_CONTEXT_SQL_EDITOR_STATE, tab.handlerState);
|
||||
|
||||
return <SqlEditor state={tab.handlerState} />;
|
||||
};
|
||||
|
||||
@@ -88,16 +88,7 @@ export class SqlEditorTabService extends Bootstrap {
|
||||
|
||||
return {
|
||||
handlerId: sqlEditorTabHandlerKey,
|
||||
handlerState: {
|
||||
query: '',
|
||||
order,
|
||||
executionContext: { ...executionContext.context },
|
||||
tabs: [],
|
||||
resultGroups: [],
|
||||
resultTabs: [],
|
||||
executionPlanTabs: [],
|
||||
statisticsTabs: [],
|
||||
},
|
||||
handlerState: this.sqlEditorService.getState(order, executionContext.context),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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,48 @@
|
||||
{
|
||||
"name": "@cloudbeaver/plugin-sql-editor-screen",
|
||||
"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/plugin-sql-editor": "^0.1.0",
|
||||
"@cloudbeaver/plugin-codemirror": "^0.1.0",
|
||||
"@cloudbeaver/plugin-data-viewer": "^0.1.0",
|
||||
"@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": "^16.x.x",
|
||||
"mobx": "^6.x.x",
|
||||
"mobx-react-lite": "^3.x.x",
|
||||
"reshadow": "^0.x.x"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 { injectable, Bootstrap } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ActionService, ACTION_OPEN_IN_TAB, KeyBindingService, KEY_BINDING_OPEN_IN_TAB } from '@cloudbeaver/core-view';
|
||||
import { DATA_CONTEXT_SQL_EDITOR_STATE } from '@cloudbeaver/plugin-sql-editor';
|
||||
|
||||
import { SqlEditorScreenService } from './Screen/SqlEditorScreenService';
|
||||
|
||||
@injectable()
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly actionService: ActionService,
|
||||
private readonly keyBindingService: KeyBindingService,
|
||||
private readonly sqlEditorScreenService: SqlEditorScreenService,
|
||||
private readonly notificationService: NotificationService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.actionService.addHandler({
|
||||
id: 'sql-editor-screen',
|
||||
isActionApplicable: (contexts, action) => (
|
||||
action === ACTION_OPEN_IN_TAB
|
||||
&& contexts.has(DATA_CONTEXT_SQL_EDITOR_STATE)
|
||||
),
|
||||
handler: (context, action) => { },
|
||||
});
|
||||
this.keyBindingService.addKeyBindingHandler({
|
||||
id: 'sql-editor',
|
||||
binding: KEY_BINDING_OPEN_IN_TAB,
|
||||
isBindingApplicable: (contexts, action) => action === ACTION_OPEN_IN_TAB,
|
||||
handler: (contexts, action) => {
|
||||
const context = contexts.get(DATA_CONTEXT_SQL_EDITOR_STATE);
|
||||
|
||||
if (!context.executionContext) {
|
||||
this.notificationService.logError({
|
||||
title: 'sd',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const url = this.sqlEditorScreenService.createURL({
|
||||
connectionId: context.executionContext.connectionId,
|
||||
contextId: context.executionContext.baseId,
|
||||
});
|
||||
|
||||
window.open(url, '_blank')?.focus();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async load(): Promise<void> { }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface ISqlEditorScreenParams {
|
||||
readonly connectionId: string;
|
||||
readonly contextId: string;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 { observable } from 'mobx';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import { Loader, TextPlaceholder, useMapResource, useObservableRef } from '@cloudbeaver/core-blocks';
|
||||
import { ConnectionExecutionContextResource, ConnectionExecutionContextService, ConnectionInfoResource, IConnectionExecutionContextInfo } from '@cloudbeaver/core-connections';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import type { ScreenComponent } from '@cloudbeaver/core-routing';
|
||||
import { CachedMapAllKey } from '@cloudbeaver/core-sdk';
|
||||
import { ISqlEditorTabState, SqlEditor, SqlEditorService } from '@cloudbeaver/plugin-sql-editor';
|
||||
|
||||
import type { ISqlEditorScreenParams } from './ISqlEditorScreenParams';
|
||||
|
||||
export const SqlEditorScreen: ScreenComponent<ISqlEditorScreenParams> = observer(function SqlEditorScreen({
|
||||
connectionId,
|
||||
contextId,
|
||||
}) {
|
||||
const connectionInfoResource = useMapResource(
|
||||
SqlEditorScreen,
|
||||
ConnectionInfoResource,
|
||||
connectionId
|
||||
);
|
||||
const connectionExecutionContextResource = useMapResource(
|
||||
SqlEditorScreen,
|
||||
ConnectionExecutionContextResource,
|
||||
CachedMapAllKey
|
||||
);
|
||||
const sqlEditorService = useService(SqlEditorService);
|
||||
const connectionExecutionContextService = useService(ConnectionExecutionContextService);
|
||||
const context = connectionExecutionContextService.get(contextId);
|
||||
|
||||
const state = useObservableRef(() => ({
|
||||
state: null as null | ISqlEditorTabState,
|
||||
setState(contextInfo: IConnectionExecutionContextInfo) {
|
||||
this.state = sqlEditorService.getState(0, contextInfo);
|
||||
},
|
||||
}), { state: observable }, false);
|
||||
|
||||
if (context?.context && context.context.baseId !== state.state?.executionContext?.baseId) {
|
||||
state.setState(context.context);
|
||||
}
|
||||
|
||||
return (
|
||||
<Loader state={[connectionInfoResource, connectionExecutionContextResource]}>
|
||||
{state.state
|
||||
? <SqlEditor state={state.state} />
|
||||
: <TextPlaceholder>Context not found</TextPlaceholder>}
|
||||
</Loader>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 { injectable, Bootstrap } from '@cloudbeaver/core-di';
|
||||
import { ScreenService } from '@cloudbeaver/core-routing';
|
||||
|
||||
import { SqlEditorScreenService } from './SqlEditorScreenService';
|
||||
|
||||
@injectable()
|
||||
export class SqlEditorScreenBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly screenService: ScreenService,
|
||||
private sqlEditorScreenService: SqlEditorScreenService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.screenService.create(this.sqlEditorScreenService.screen);
|
||||
}
|
||||
|
||||
load(): void | Promise<void> { }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 { injectable } from '@cloudbeaver/core-di';
|
||||
import { IScreen, ScreenService } from '@cloudbeaver/core-routing';
|
||||
|
||||
import type { ISqlEditorScreenParams } from './ISqlEditorScreenParams';
|
||||
import { SqlEditorScreen } from './SqlEditorScreen';
|
||||
|
||||
@injectable()
|
||||
export class SqlEditorScreenService {
|
||||
readonly screen: IScreen<ISqlEditorScreenParams>;
|
||||
constructor(
|
||||
private readonly screenService: ScreenService
|
||||
) {
|
||||
this.screen = {
|
||||
name: 'sql-editor',
|
||||
routes: [
|
||||
{ name: 'sql-editor', path: '/sql-editor/:connectionId/:contextId' },
|
||||
],
|
||||
component: SqlEditorScreen,
|
||||
};
|
||||
}
|
||||
|
||||
createURL(params: ISqlEditorScreenParams): string {
|
||||
return this.screenService.buildUrl(this.screen.name, params);
|
||||
}
|
||||
|
||||
navigate(params: ISqlEditorScreenParams): void {
|
||||
this.screenService.navigate(this.screen.name, params);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { sqlEditorPagePluginManifest } from './manifest';
|
||||
|
||||
export default sqlEditorPagePluginManifest;
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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';
|
||||
import { SqlEditorScreenBootstrap } from './Screen/SqlEditorScreenBootstrap';
|
||||
import { SqlEditorScreenService } from './Screen/SqlEditorScreenService';
|
||||
|
||||
export const sqlEditorPagePluginManifest: PluginManifest = {
|
||||
info: {
|
||||
name: 'Sql Editor Page plugin',
|
||||
},
|
||||
|
||||
providers: [
|
||||
PluginBootstrap,
|
||||
SqlEditorScreenBootstrap,
|
||||
SqlEditorScreenService,
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["**/node_modules", "**/.*/"],
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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 { createDataContext } from '@cloudbeaver/core-view';
|
||||
|
||||
import type { ISqlEditorTabState } from './ISqlEditorTabState';
|
||||
|
||||
export const DATA_CONTEXT_SQL_EDITOR_STATE = createDataContext<ISqlEditorTabState>('sql-editor-state');
|
||||
@@ -29,11 +29,10 @@ const viewerStyles = css`
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
editorId: string;
|
||||
state: ISqlEditorTabState;
|
||||
}
|
||||
|
||||
export const SqlEditor = observer<Props>(function SqlEditor({ editorId, state }) {
|
||||
export const SqlEditor = observer<Props>(function SqlEditor({ state }) {
|
||||
const styles = useStyles(splitStyles, splitHorizontalStyles, viewerStyles);
|
||||
|
||||
return styled(styles)(
|
||||
@@ -43,7 +42,7 @@ export const SqlEditor = observer<Props>(function SqlEditor({ editorId, state })
|
||||
</Pane>
|
||||
<ResizerControls />
|
||||
<Pane main>
|
||||
<SqlResultTabs editorId={editorId} state={state} />
|
||||
<SqlResultTabs state={state} />
|
||||
</Pane>
|
||||
</Split>
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
import { ConnectionExecutionContextService, ConnectionsManagerService, IConnectionExecutionContext } from '@cloudbeaver/core-connections';
|
||||
import { ConnectionExecutionContextService, ConnectionsManagerService, IConnectionExecutionContext, IConnectionExecutionContextInfo } from '@cloudbeaver/core-connections';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { GraphQLService, QuerySqlCompletionProposalsQuery } from '@cloudbeaver/core-sdk';
|
||||
@@ -22,6 +22,20 @@ export class SqlEditorService {
|
||||
) {
|
||||
}
|
||||
|
||||
getState(order: number, contextInfo: IConnectionExecutionContextInfo): ISqlEditorTabState {
|
||||
return {
|
||||
|
||||
query: '',
|
||||
order,
|
||||
executionContext: { ...contextInfo },
|
||||
tabs: [],
|
||||
resultGroups: [],
|
||||
resultTabs: [],
|
||||
executionPlanTabs: [],
|
||||
statisticsTabs: [],
|
||||
};
|
||||
}
|
||||
|
||||
async getAutocomplete(
|
||||
connectionId: string,
|
||||
contextId: string,
|
||||
|
||||
@@ -51,13 +51,12 @@ const styles = composes(
|
||||
);
|
||||
|
||||
interface Props {
|
||||
editorId: string;
|
||||
state: ISqlEditorTabState;
|
||||
onTabSelect?: (tabId: string) => void;
|
||||
onTabClose?: (tabId: string) => void;
|
||||
}
|
||||
|
||||
export const SqlResultTabs = observer<Props>(function SqlDataResult({ editorId, state, onTabSelect, onTabClose }) {
|
||||
export const SqlResultTabs = observer<Props>(function SqlDataResult({ state, onTabSelect, onTabClose }) {
|
||||
const style = useStyles(styles);
|
||||
const translate = useTranslate();
|
||||
const sqlResultTabsService = useService(SqlResultTabsService);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { sqlEditorPluginManifest } from './manifest';
|
||||
export * from './SqlEditor/SQLCodeEditor/SQLCodeEditorLoader';
|
||||
export * from './SqlResultTabs/SqlResultTabsService';
|
||||
export * from './DATA_CONTEXT_SQL_EDITOR_STATE';
|
||||
export * from './QueryDataSource';
|
||||
export * from './SqlDialectInfoService';
|
||||
export * from './ISqlEditorTabState';
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
"@cloudbeaver/plugin-data-viewer": "0.1.0",
|
||||
"@cloudbeaver/plugin-ddl-viewer": "0.1.0",
|
||||
"@cloudbeaver/plugin-object-viewer": "0.1.0",
|
||||
"@cloudbeaver/plugin-sql-editor-navigation-tab": "0.1.0"
|
||||
"@cloudbeaver/plugin-sql-editor": "0.1.0",
|
||||
"@cloudbeaver/plugin-sql-editor-navigation-tab": "0.1.0",
|
||||
"@cloudbeaver/plugin-sql-editor-screen": "0.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import objectViewer from '@cloudbeaver/plugin-object-viewer';
|
||||
import productPlugin from '@cloudbeaver/plugin-product';
|
||||
import sqlEditor from '@cloudbeaver/plugin-sql-editor';
|
||||
import sqlEditorTab from '@cloudbeaver/plugin-sql-editor-navigation-tab';
|
||||
import sqlEditorScreen from '@cloudbeaver/plugin-sql-editor-screen';
|
||||
import userProfile from '@cloudbeaver/plugin-user-profile';
|
||||
|
||||
import { defaultProductManifest } from './manifest';
|
||||
@@ -36,6 +37,7 @@ const PLUGINS: PluginManifest[] = [
|
||||
objectViewer,
|
||||
sqlEditor,
|
||||
sqlEditorTab,
|
||||
sqlEditorScreen,
|
||||
userProfile,
|
||||
defaultProductManifest,
|
||||
connectionPlugin,
|
||||
|
||||
Reference in New Issue
Block a user