feat: CB-1407 open sql editor in the separate browser tab

This commit is contained in:
Wroud
2021-11-15 00:25:22 +03:00
parent 0bf2f970eb
commit 41de331b82
39 changed files with 569 additions and 44 deletions
@@ -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(
@@ -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);
}
}
@@ -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;
}
+1 -1
View File
@@ -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;
}
+8 -1
View File
@@ -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';
+3 -1
View File
@@ -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,