/
vshmidt
/
cloudbeaver
Обзор
Документация
Войти
/
vshmidt
/
cloudbeaver
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
devel
webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorBootstrap.ts
324 строки
11 KB
Alexey Potsetsuev
dbeaver/pro#7465 refactor: migrate context menu to ariakit (#3963)
13 дек 2025, 05:44
Не верифицирован
13 дек 2025, 05:44
cb23fda
Код
Авторство
О чём код?
/* * CloudBeaver - Cloud Database Manager * Copyright (C) 2020-2025 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 { importLazyComponent, RenameDialog } from '@cloudbeaver/core-blocks'; import { type Connection, ConnectionInfoResource, createConnectionParam, DATA_CONTEXT_CONNECTION, type IConnectionInfoParams, isConnectionProvider, isObjectCatalogProvider, isObjectSchemaProvider, } from '@cloudbeaver/core-connections'; import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs'; import type { IExecutorHandler } from '@cloudbeaver/core-executor'; import { ExtensionUtils } from '@cloudbeaver/core-extensions'; import { LocalizationService } from '@cloudbeaver/core-localization'; import { DATA_CONTEXT_NAV_NODE, EObjectFeature, NodeManagerUtils } from '@cloudbeaver/core-navigation-tree'; import { type ISessionAction, sessionActionContext, SessionActionService } from '@cloudbeaver/core-root'; import { ACTION_OPEN, ACTION_RENAME, ActionService, menuExtractItems, MenuService, ViewService } from '@cloudbeaver/core-view'; import { MENU_CONNECTIONS } from '@cloudbeaver/plugin-connections'; import { NavigationTabsService } from '@cloudbeaver/plugin-navigation-tabs'; import { DATA_CONTEXT_SQL_EDITOR_STATE, ESqlDataSourceFeatures, getSqlEditorName, LocalStorageSqlDataSource, SqlDataSourceService, SqlEditorService, SqlEditorSettingsService, } from '@cloudbeaver/plugin-sql-editor'; import { MENU_APP_ACTIONS } from '@cloudbeaver/plugin-top-app-bar'; import { ACTION_SQL_EDITOR_NEW } from './ACTION_SQL_EDITOR_NEW.js'; import { ACTION_SQL_EDITOR_OPEN } from './ACTION_SQL_EDITOR_OPEN.js'; import { DATA_CONTEXT_SQL_EDITOR_TAB } from './DATA_CONTEXT_SQL_EDITOR_TAB.js'; import { isSessionActionOpenSQLEditor } from './sessionActionOpenSQLEditor.js'; import { SQL_EDITOR_SOURCE_ACTION } from './SQL_EDITOR_SOURCE_ACTION.js'; import { SqlEditorNavigatorService } from './SqlEditorNavigatorService.js'; import { SqlEditorTabService } from './SqlEditorTabService.js'; const WelcomeNewSqlEditor = importLazyComponent(() => import('./WelcomeNewSqlEditor.js').then(m => m.WelcomeNewSqlEditor)); interface IActiveConnectionContext { connectionKey?: IConnectionInfoParams; catalogId?: string; schemaId?: string; } @injectable(() => [ SqlEditorNavigatorService, NavigationTabsService, ViewService, ActionService, MenuService, SessionActionService, CommonDialogService, SqlEditorTabService, SqlDataSourceService, ConnectionInfoResource, SqlEditorService, LocalizationService, SqlEditorSettingsService, ]) export class SqlEditorBootstrap extends Bootstrap { constructor( private readonly sqlEditorNavigatorService: SqlEditorNavigatorService, private readonly navigationTabsService: NavigationTabsService, private readonly viewService: ViewService, private readonly actionService: ActionService, private readonly menuService: MenuService, private readonly sessionActionService: SessionActionService, private readonly commonDialogService: CommonDialogService, private readonly sqlEditorTabService: SqlEditorTabService, private readonly sqlDataSourceService: SqlDataSourceService, private readonly connectionInfoResource: ConnectionInfoResource, private readonly sqlEditorService: SqlEditorService, private readonly localizationService: LocalizationService, private readonly sqlEditorSettingsService: SqlEditorSettingsService, ) { super(); } override register(): void { this.navigationTabsService.welcomeContainer.add(WelcomeNewSqlEditor, undefined, () => this.sqlEditorSettingsService.disabled); this.registerTopAppBarItem(); this.menuService.addCreator({ contexts: [DATA_CONTEXT_SQL_EDITOR_STATE, DATA_CONTEXT_SQL_EDITOR_TAB], getItems: (context, items) => [...items, ACTION_RENAME], orderItems: (context, items) => { items.unshift(...menuExtractItems(items, [ACTION_RENAME])); return items; }, }); this.menuService.addCreator({ root: true, contexts: [DATA_CONTEXT_CONNECTION], isApplicable: context => { const node = context.get(DATA_CONTEXT_NAV_NODE); if (node && !node.objectFeatures.includes(EObjectFeature.dataSource)) { return false; } return true; }, getItems: (context, items) => [...items, ACTION_SQL_EDITOR_OPEN], orderItems: (context, items) => { items.unshift(...menuExtractItems(items, [ACTION_OPEN, ACTION_SQL_EDITOR_OPEN])); return items; }, }); this.actionService.addHandler({ id: 'sql-editor', actions: [ACTION_RENAME, ACTION_SQL_EDITOR_OPEN], isActionApplicable: (context, action) => { switch (action) { case ACTION_RENAME: { const editorState = context.get(DATA_CONTEXT_SQL_EDITOR_STATE); if (!editorState) { return false; } const dataSource = this.sqlDataSourceService.get(editorState.editorId); return dataSource?.hasFeature(ESqlDataSourceFeatures.setName) ?? false; } case ACTION_SQL_EDITOR_OPEN: return context.has(DATA_CONTEXT_CONNECTION); } return false; }, handler: async (context, action) => { switch (action) { case ACTION_RENAME: { const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE)!; const dataSource = this.sqlDataSourceService.get(state.editorId); const executionContext = dataSource?.executionContext; if (!dataSource) { return; } let connection: Connection | undefined; if (executionContext) { connection = this.connectionInfoResource.get(createConnectionParam(executionContext.projectId, executionContext.connectionId)); } const name = getSqlEditorName(state, dataSource, connection); const regexp = /^(.*?)(\.\w+)$/gi.exec(name); const { status, result } = await this.commonDialogService.open(RenameDialog, { name: regexp?.[1] ?? name, objectName: name, icon: dataSource.icon, validation: name => !this.sqlEditorTabService.sqlEditorTabs.some( tab => tab.handlerState.order !== state.order && this.sqlEditorService.getName(tab.handlerState) === name.trim(), ) && dataSource.canRename(name), }); if (status === DialogueStateResult.Resolved && result !== undefined) { dataSource.setName((result ?? '').trim()); } break; } case ACTION_SQL_EDITOR_OPEN: { const connectionKey = context.get(DATA_CONTEXT_CONNECTION)!; this.sqlEditorNavigatorService.openNewEditor({ dataSourceKey: LocalStorageSqlDataSource.key, connectionKey, }); break; } } }, }); this.navigationTabsService.onInit.addHandler(state => { if (state) { this.sessionActionService.onAction.addHandler(this.handleAction); } else { this.sessionActionService.onAction.removeHandler(this.handleAction); } }); } private registerTopAppBarItem() { this.menuService.addCreator({ menus: [MENU_APP_ACTIONS], getItems: (context, items) => [...items, ACTION_SQL_EDITOR_NEW], orderItems: (context, items) => { const actionsOpen = menuExtractItems(items, [ACTION_SQL_EDITOR_NEW]); let placeIndex = items.indexOf(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', actions: [ACTION_SQL_EDITOR_NEW], isLabelVisible: () => false, getActionInfo: (context, action) => { const connectionContext = this.getActiveConnectionContext(); const schemaAndCatalog = NodeManagerUtils.concatSchemaAndCatalog(connectionContext.catalogId, connectionContext.schemaId); let tooltip = action.info.tooltip; if (connectionContext.connectionKey) { const connectionInfo = this.connectionInfoResource.get(connectionContext.connectionKey); if (connectionInfo) { tooltip = this.localizationService.translate( 'plugin_sql_editor_navigation_tab_action_sql_editor_new_tooltip_context', 'plugin_sql_editor_navigation_tab_action_sql_editor_new_tooltip', { connection: `${connectionInfo.name}${schemaAndCatalog ? ' ' + schemaAndCatalog : ''}`, }, ); } } return { ...action.info, label: '', tooltip, }; }, isHidden: (context, action) => { if (action === ACTION_SQL_EDITOR_NEW) { return this.sqlEditorSettingsService.disabled; } return false; }, handler: async (context, action) => { switch (action) { case ACTION_SQL_EDITOR_NEW: { await this.openSQLEditor(); break; } } }, }); } private getActiveConnectionContext(): IActiveConnectionContext { let connectionKey: IConnectionInfoParams | undefined; let catalogId: string | undefined; let schemaId: string | undefined; for (const activeView of this.viewService.activeViews) { ExtensionUtils.from(activeView.extensions) .on(isConnectionProvider, extension => { connectionKey = extension(activeView.context); }) .on(isObjectCatalogProvider, extension => { catalogId = extension(activeView.context); }) .on(isObjectSchemaProvider, extension => { schemaId = extension(activeView.context); }); if (connectionKey) { break; } } return { connectionKey, catalogId, schemaId, }; } async openSQLEditor(): Promise<void> { const connectionContext = this.getActiveConnectionContext(); await this.sqlEditorNavigatorService.openNewEditor({ dataSourceKey: LocalStorageSqlDataSource.key, connectionKey: connectionContext.connectionKey, catalogId: connectionContext.catalogId, schemaId: connectionContext.schemaId, }); } private readonly handleAction: IExecutorHandler<ISessionAction | null> = (data, contexts) => { const processInfo = contexts.getContext(sessionActionContext); if (isSessionActionOpenSQLEditor(data)) { try { this.sqlEditorNavigatorService.openNewEditor({ dataSourceKey: LocalStorageSqlDataSource.key, name: data['editor-name'], connectionKey: createConnectionParam(data['project-id'], data['connection-id']), source: SQL_EDITOR_SOURCE_ACTION, }); } finally { processInfo.process(); } } }; }