From 91826a3ed3d6b3f19cf5a908ebba143d242f37fc Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Mon, 11 Sep 2023 01:14:21 +0200 Subject: [PATCH 01/13] CB-3924: add show output button --- .../plugin-sql-editor/src/MenuBootstrap.ts | 16 ++++++++++++++++ .../src/SqlEditor/SqlEditor.tsx | 5 +++++ .../plugin-sql-editor/src/SqlEditorView.ts | 2 ++ .../src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts | 13 +++++++++++++ .../KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT.ts | 14 ++++++++++++++ webapp/packages/plugin-sql-editor/src/index.ts | 1 + .../packages/plugin-sql-editor/src/locales/en.ts | 1 + .../packages/plugin-sql-editor/src/locales/it.ts | 1 + .../packages/plugin-sql-editor/src/locales/ru.ts | 1 + .../packages/plugin-sql-editor/src/locales/zh.ts | 1 + 10 files changed, 55 insertions(+) create mode 100644 webapp/packages/plugin-sql-editor/src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts create mode 100644 webapp/packages/plugin-sql-editor/src/actions/bindings/KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT.ts diff --git a/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts index 2652018a18..0164c37f98 100644 --- a/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts +++ b/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts @@ -22,11 +22,13 @@ import { ACTION_SQL_EDITOR_EXECUTE_NEW } from './actions/ACTION_SQL_EDITOR_EXECU import { ACTION_SQL_EDITOR_EXECUTE_SCRIPT } from './actions/ACTION_SQL_EDITOR_EXECUTE_SCRIPT'; import { ACTION_SQL_EDITOR_FORMAT } from './actions/ACTION_SQL_EDITOR_FORMAT'; import { ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN } from './actions/ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN'; +import { ACTION_SQL_EDITOR_SHOW_OUTPUT } from './actions/ACTION_SQL_EDITOR_SHOW_OUTPUT'; import { KEY_BINDING_SQL_EDITOR_EXECUTE } from './actions/bindings/KEY_BINDING_SQL_EDITOR_EXECUTE'; import { KEY_BINDING_SQL_EDITOR_EXECUTE_NEW } from './actions/bindings/KEY_BINDING_SQL_EDITOR_EXECUTE_NEW'; import { KEY_BINDING_SQL_EDITOR_EXECUTE_SCRIPT } from './actions/bindings/KEY_BINDING_SQL_EDITOR_EXECUTE_SCRIPT'; import { KEY_BINDING_SQL_EDITOR_FORMAT } from './actions/bindings/KEY_BINDING_SQL_EDITOR_FORMAT'; import { KEY_BINDING_SQL_EDITOR_SHOW_EXECUTION_PLAN } from './actions/bindings/KEY_BINDING_SQL_EDITOR_SHOW_EXECUTION_PLAN'; +import { KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT } from './actions/bindings/KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT'; import { ESqlDataSourceFeatures } from './SqlDataSource/ESqlDataSourceFeatures'; import { DATA_CONTEXT_SQL_EDITOR_DATA } from './SqlEditor/DATA_CONTEXT_SQL_EDITOR_DATA'; @@ -57,11 +59,13 @@ export class MenuBootstrap extends Bootstrap { ACTION_SQL_EDITOR_EXECUTE_NEW, ACTION_SQL_EDITOR_EXECUTE_SCRIPT, ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN, + ACTION_SQL_EDITOR_SHOW_OUTPUT, ].includes(action) ) { return false; } + // TODO we have to add check for output action ? if ( !sqlEditorData.dataSource?.hasFeature(ESqlDataSourceFeatures.query) && [ACTION_SQL_EDITOR_EXECUTE, ACTION_SQL_EDITOR_EXECUTE_NEW, ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN].includes(action) @@ -77,6 +81,7 @@ export class MenuBootstrap extends Bootstrap { ACTION_REDO, ACTION_UNDO, ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN, + ACTION_SQL_EDITOR_SHOW_OUTPUT, ].includes(action); }, isDisabled: (context, action) => !context.has(DATA_CONTEXT_SQL_EDITOR_DATA), @@ -135,6 +140,13 @@ export class MenuBootstrap extends Bootstrap { handler: this.sqlEditorActionHandler.bind(this), }); + this.keyBindingService.addKeyBindingHandler({ + id: 'sql-editor-show-output', + binding: KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT, + isBindingApplicable: (contexts, action) => action === ACTION_SQL_EDITOR_SHOW_OUTPUT, + handler: this.sqlEditorActionHandler.bind(this), + }); + // this.menuService.addCreator({ // isApplicable: context => ( // context.tryGet(DATA_CONTEXT_SQL_EDITOR_DATA) !== undefined @@ -180,6 +192,10 @@ export class MenuBootstrap extends Bootstrap { case ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN: data.showExecutionPlan(); break; + case ACTION_SQL_EDITOR_SHOW_OUTPUT: + // TODO change it to show output + data.showExecutionPlan(); + break; } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx index e239468302..5de8b170c8 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx @@ -185,6 +185,11 @@ export const SqlEditor = observer(function SqlEditor({ state, c )} + {isQuery && data.dialect?.supportsExplainExecutionPlan && ( + + )} )} diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorView.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorView.ts index 58f8bb152e..0178d42e5c 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditorView.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditorView.ts @@ -14,6 +14,7 @@ import { ACTION_SQL_EDITOR_EXECUTE_NEW } from './actions/ACTION_SQL_EDITOR_EXECU import { ACTION_SQL_EDITOR_EXECUTE_SCRIPT } from './actions/ACTION_SQL_EDITOR_EXECUTE_SCRIPT'; import { ACTION_SQL_EDITOR_FORMAT } from './actions/ACTION_SQL_EDITOR_FORMAT'; import { ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN } from './actions/ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN'; +import { ACTION_SQL_EDITOR_SHOW_OUTPUT } from './actions/ACTION_SQL_EDITOR_SHOW_OUTPUT'; @injectable() export class SqlEditorView extends View { @@ -27,6 +28,7 @@ export class SqlEditorView extends View { ACTION_UNDO, ACTION_REDO, ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN, + ACTION_SQL_EDITOR_SHOW_OUTPUT, ACTION_SAVE, ); } diff --git a/webapp/packages/plugin-sql-editor/src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts b/webapp/packages/plugin-sql-editor/src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts new file mode 100644 index 0000000000..f786a61583 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts @@ -0,0 +1,13 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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_SHOW_OUTPUT = createAction('sql-editor-show-output', { + icon: '/icons/sql_output.svg', + label: 'sql_editor_output_button_tooltip', +}); diff --git a/webapp/packages/plugin-sql-editor/src/actions/bindings/KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT.ts b/webapp/packages/plugin-sql-editor/src/actions/bindings/KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT.ts new file mode 100644 index 0000000000..2508b02b88 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/actions/bindings/KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT.ts @@ -0,0 +1,14 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 '@cloudbeaver/core-view'; + +export const KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT = createKeyBinding({ + id: 'sql-editor-show-output', + keys: 'shift+ctrl+o', + preventDefault: true, +}); diff --git a/webapp/packages/plugin-sql-editor/src/index.ts b/webapp/packages/plugin-sql-editor/src/index.ts index 5ee2f5bd1d..40625f236f 100644 --- a/webapp/packages/plugin-sql-editor/src/index.ts +++ b/webapp/packages/plugin-sql-editor/src/index.ts @@ -10,6 +10,7 @@ export * from './actions/ACTION_SQL_EDITOR_EXECUTE_SCRIPT'; export * from './actions/ACTION_SQL_EDITOR_EXECUTE'; export * from './actions/ACTION_SQL_EDITOR_FORMAT'; export * from './actions/ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN'; +export * from './actions/ACTION_SQL_EDITOR_SHOW_OUTPUT' export * from './SqlDataSource/LocalStorage/ILocalStorageSqlDataSourceState'; export * from './SqlDataSource/LocalStorage/LocalStorageSqlDataSource'; export * from './SqlDataSource/LocalStorage/LocalStorageSqlDataSourceBootstrap'; diff --git a/webapp/packages/plugin-sql-editor/src/locales/en.ts b/webapp/packages/plugin-sql-editor/src/locales/en.ts index 3c20f7b3bd..18019d3dd0 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/en.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/en.ts @@ -7,6 +7,7 @@ export default [ ['sql_editor_placeholder', 'Execute query with Ctrl+Enter to see results'], ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', 'Explain execution plan (Shift + Ctrl + E)'], + ['sql_editor_output_button_tooltip', 'Show server output (Shift + Ctrl + O)'], ['sql_editor_sql_execution_button_tooltip', 'Execute SQL Statement (Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', 'Execute SQL Statement in new tab (Ctrl + \\)(Shift + Ctrl + Enter)'], ['sql_editor_sql_execution_script_button_tooltip', 'Execute SQL Script (Alt + X)'], diff --git a/webapp/packages/plugin-sql-editor/src/locales/it.ts b/webapp/packages/plugin-sql-editor/src/locales/it.ts index e0649ef0a6..71cbb5572d 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/it.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/it.ts @@ -7,6 +7,7 @@ export default [ ['sql_editor_placeholder', 'Esegui la query con Ctrl+Enter per vedere i risultati'], ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', 'Mostra il piano di esecuzione (Shift + Ctrl + E)'], + ['sql_editor_output_button_tooltip', 'Show server output (Shift + Ctrl + O)'], ['sql_editor_sql_execution_button_tooltip', "Esegui l'istruzione SQL (Ctrl + Enter)"], ['sql_editor_sql_execution_new_tab_button_tooltip', "Esegui l'istruzione SQL in una nuova tab (Ctrl + \\)(Shift + Ctrl + Enter)"], ['sql_editor_sql_execution_script_button_tooltip', 'Esegui lo script SQL (Alt + X)'], diff --git a/webapp/packages/plugin-sql-editor/src/locales/ru.ts b/webapp/packages/plugin-sql-editor/src/locales/ru.ts index f16baf789f..7acfdb34b9 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/ru.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/ru.ts @@ -7,6 +7,7 @@ export default [ ['sql_editor_placeholder', 'Нажмите Ctrl+Enter, чтобы выполнить запрос и увидеть результат'], ['sql_editor_hint_empty', 'Нет авто-дополнений...'], ['sql_editor_execution_plan_button_tooltip', 'Посмотреть информацию о плане выполнения запроса (Shift + Ctrl + E)'], + ['sql_editor_output_button_tooltip', 'Показать вывод сервера (Shift + Ctrl + O)'], ['sql_editor_sql_execution_button_tooltip', 'Выполнить SQL Выражение (Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', 'Выполнить SQL Выражение в новой вкладке (Ctrl + \\)(Shift + Ctrl + Enter)'], ['sql_editor_sql_execution_script_button_tooltip', 'Исполнить SQL Скрипт (Alt + X)'], diff --git a/webapp/packages/plugin-sql-editor/src/locales/zh.ts b/webapp/packages/plugin-sql-editor/src/locales/zh.ts index ca1124c0f8..3c3fe39221 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/zh.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/zh.ts @@ -7,6 +7,7 @@ export default [ ['sql_editor_placeholder', '使用Ctrl + Enter执行查询以查看结果'], ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', '解释执行计划(Shift + Ctrl + E)'], + ['sql_editor_output_button_tooltip', 'Show server output (Shift + Ctrl + O)'], ['sql_editor_sql_execution_button_tooltip', '执行SQL语句(Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', '在新选项卡中执行SQL语句(Ctrl + \\)(Shift + Ctrl + Enter)'], ['sql_editor_sql_execution_script_button_tooltip', '执行SQL脚本(Alt + X)'], From 89c08d5b3539edc103ad5f84b9443d1b55d45fde Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Mon, 11 Sep 2023 11:56:10 +0200 Subject: [PATCH 02/13] CB-3924: add output event handler and resource --- .../src/queries/grid/asyncSqlExecuteQuery.gql | 1 + .../SqlOutputLogsEventHandler.ts | 24 ++++++++++ .../SqlOutputLogs/SqlOutputLogsResource.ts | 44 +++++++++++++++++++ .../packages/plugin-sql-editor/src/index.ts | 2 + .../plugin-sql-editor/src/manifest.ts | 4 ++ 5 files changed, 75 insertions(+) create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler.ts create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource.ts diff --git a/webapp/packages/core-sdk/src/queries/grid/asyncSqlExecuteQuery.gql b/webapp/packages/core-sdk/src/queries/grid/asyncSqlExecuteQuery.gql index b2e1d0ec18..76936e0765 100644 --- a/webapp/packages/core-sdk/src/queries/grid/asyncSqlExecuteQuery.gql +++ b/webapp/packages/core-sdk/src/queries/grid/asyncSqlExecuteQuery.gql @@ -13,6 +13,7 @@ mutation asyncSqlExecuteQuery( resultId: $resultId filter: $filter dataFormat: $dataFormat + readLogs: true ) { ...AsyncTaskInfo } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler.ts new file mode 100644 index 0000000000..6db75af1bf --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler.ts @@ -0,0 +1,24 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { ISessionEvent, SessionEventSource, SessionEventTopic, TopicEventHandler } from '@cloudbeaver/core-root'; +import type { CbSessionLogEvent as ISessionLogEvent } from '@cloudbeaver/core-sdk'; + +export { type ISessionLogEvent }; + +@injectable() +export class SqlOutputLogsEventHandler extends TopicEventHandler { + constructor(sessionEventSource: SessionEventSource) { + super(SessionEventTopic.CbOutputLog, sessionEventSource); + } + + map(event: any) { + console.log('map', event); + return event; + } +} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource.ts new file mode 100644 index 0000000000..595d32c352 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource.ts @@ -0,0 +1,44 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { ServerEventId } from '@cloudbeaver/core-root'; +import { CachedDataResource, GraphQLService, LogEntry } from '@cloudbeaver/core-sdk'; + +import { SqlOutputLogsEventHandler } from './SqlOutputLogsEventHandler'; + +export interface ILogEntry extends LogEntry { + id: string; +} + +@injectable() +export class SqlOutputLogsResource extends CachedDataResource { + constructor(sqlOutputLogsEventHandler: SqlOutputLogsEventHandler, private readonly graphQLService: GraphQLService) { + super(() => []); + + sqlOutputLogsEventHandler.onEvent( + ServerEventId.CbDatabaseOutputLogUpdated, + event => { + // @ts-ignore + console.log('onEvent', event?.messages as any); + // @ts-ignore + this.setData((this.data || []).concat(event?.messages as any)); + this.markOutdated(); + }, + e => e, + this, + ); + } + + protected async loader(): Promise { + console.groupCollapsed('SqlOutputLogsResource'); + console.log('loader', this.data); + console.groupEnd(); + + return this.data; + } +} diff --git a/webapp/packages/plugin-sql-editor/src/index.ts b/webapp/packages/plugin-sql-editor/src/index.ts index 40625f236f..ee63a1233f 100644 --- a/webapp/packages/plugin-sql-editor/src/index.ts +++ b/webapp/packages/plugin-sql-editor/src/index.ts @@ -28,6 +28,8 @@ export * from './SqlEditor/SQL_EDITOR_TOOLS_MENU'; export * from './SqlEditor/SQLEditorModeContext'; export * from './SqlResultTabs/DATA_CONTEXT_SQL_EDITOR_RESULT_ID'; export * from './SqlResultTabs/SqlResultTabsService'; +export * from './SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler'; +export * from './SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource'; export * from './DATA_CONTEXT_SQL_EDITOR_STATE'; export * from './getSqlEditorName'; export * from './QueryDataSource'; diff --git a/webapp/packages/plugin-sql-editor/src/manifest.ts b/webapp/packages/plugin-sql-editor/src/manifest.ts index 1118d92010..799d1942e6 100644 --- a/webapp/packages/plugin-sql-editor/src/manifest.ts +++ b/webapp/packages/plugin-sql-editor/src/manifest.ts @@ -17,6 +17,8 @@ import { SqlEditorService } from './SqlEditorService'; import { SqlEditorSettingsService } from './SqlEditorSettingsService'; import { SqlEditorView } from './SqlEditorView'; import { SqlExecutionPlanService } from './SqlResultTabs/ExecutionPlan/SqlExecutionPlanService'; +import { SqlOutputLogsEventHandler } from './SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler'; +import { SqlOutputLogsResource } from './SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource'; import { SqlQueryResultService } from './SqlResultTabs/SqlQueryResultService'; import { SqlQueryService } from './SqlResultTabs/SqlQueryService'; import { SqlResultTabsService } from './SqlResultTabs/SqlResultTabsService'; @@ -40,5 +42,7 @@ export const sqlEditorPluginManifest: PluginManifest = { MenuBootstrap, SqlDataSourceService, LocalStorageSqlDataSourceBootstrap, + SqlOutputLogsEventHandler, + SqlOutputLogsResource, ], }; From 86651a8f95245d76457b5671057f2d7868c8dee5 Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Tue, 12 Sep 2023 03:43:34 +0200 Subject: [PATCH 03/13] CB-3924: add server output logs panel --- .../plugin-codemirror6/src/Editor.tsx | 7 ++- .../plugin-codemirror6/src/IEditorProps.ts | 1 + .../src/ISqlEditorTabState.ts | 6 ++ .../src/SqlEditor/ISQLEditorData.ts | 1 + .../src/SqlEditor/useSqlEditor.ts | 7 +++ .../plugin-sql-editor/src/SqlEditorService.ts | 1 + .../OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts | 3 + .../OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts | 5 ++ .../OutputLogs/OutputFilterMenuBootstrap.ts | 58 +++++++++++++++++++ .../OutputLogs/OutputLogTypesFilterMenu.m.css | 10 ++++ .../OutputLogs/OutputLogTypesFilterMenu.tsx | 29 ++++++++++ .../OutputLogsEventHandler.ts} | 3 +- .../OutputLogs/OutputLogsPanel.m.css | 13 +++++ .../OutputLogs/OutputLogsPanel.tsx | 32 ++++++++++ .../OutputLogs/OutputLogsResource.ts | 47 +++++++++++++++ .../OutputLogs/OutputLogsService.ts | 57 ++++++++++++++++++ .../OutputLogs/OutputLogsToolbar.m.css | 16 +++++ .../OutputLogs/OutputLogsToolbar.tsx | 33 +++++++++++ .../OutputLogs/useOutputLogsPanelState.ts | 54 +++++++++++++++++ .../SqlOutputLogs/SqlOutputLogsResource.ts | 44 -------------- .../src/SqlResultTabs/SqlResultPanel.tsx | 9 +++ .../packages/plugin-sql-editor/src/index.ts | 7 ++- .../plugin-sql-editor/src/locales/en.ts | 3 +- .../plugin-sql-editor/src/locales/it.ts | 3 +- .../plugin-sql-editor/src/locales/ru.ts | 3 +- .../plugin-sql-editor/src/locales/zh.ts | 3 +- .../plugin-sql-editor/src/manifest.ts | 12 ++-- 27 files changed, 408 insertions(+), 59 deletions(-) create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.m.css create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx rename webapp/packages/plugin-sql-editor/src/SqlResultTabs/{SqlOutputLogs/SqlOutputLogsEventHandler.ts => OutputLogs/OutputLogsEventHandler.ts} (83%) create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.m.css create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.m.css create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts delete mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource.ts diff --git a/webapp/packages/plugin-codemirror6/src/Editor.tsx b/webapp/packages/plugin-codemirror6/src/Editor.tsx index 1e6b7526c8..74dd233f51 100644 --- a/webapp/packages/plugin-codemirror6/src/Editor.tsx +++ b/webapp/packages/plugin-codemirror6/src/Editor.tsx @@ -19,10 +19,13 @@ import { useCodemirrorExtensions } from './useCodemirrorExtensions'; import { type IDefaultExtensions, useEditorDefaultExtensions } from './useEditorDefaultExtensions'; export const Editor = observer( - forwardRef(function Editor({ lineNumbers, extensions, ...rest }, ref) { + forwardRef(function Editor({ lineNumbers, extensions, useDefaultExtensions = true, ...rest }, ref) { extensions = useCodemirrorExtensions(extensions); + const defaultExtensions = useEditorDefaultExtensions({ lineNumbers }); - extensions.set(...defaultExtensions); + if (useDefaultExtensions) { + extensions.set(...defaultExtensions); + } return styled(EDITOR_BASE_STYLES)( diff --git a/webapp/packages/plugin-codemirror6/src/IEditorProps.ts b/webapp/packages/plugin-codemirror6/src/IEditorProps.ts index 03b38d14b9..f13cacd381 100644 --- a/webapp/packages/plugin-codemirror6/src/IEditorProps.ts +++ b/webapp/packages/plugin-codemirror6/src/IEditorProps.ts @@ -9,4 +9,5 @@ import type { IReactCodeMirrorProps } from './IReactCodemirrorProps'; export interface IEditorProps extends IReactCodeMirrorProps { className?: string; + useDefaultExtensions?: boolean; } diff --git a/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts b/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts index 7c2c59154c..ef02de7e4c 100644 --- a/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts +++ b/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts @@ -41,6 +41,11 @@ export interface IExecutionPlanTab { options?: Record; } +export interface IOutputLogsTab { + tabId: string; + order: number; +} + export interface ISqlEditorTabState { editorId: string; datasourceKey: string; @@ -54,6 +59,7 @@ export interface ISqlEditorTabState { resultTabs: IResultTab[]; statisticsTabs: IStatisticsTab[]; executionPlanTabs: IExecutionPlanTab[]; + outputLogsTab?: IOutputLogsTab; // mode currentModeId?: string; diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/ISQLEditorData.ts b/webapp/packages/plugin-sql-editor/src/SqlEditor/ISQLEditorData.ts index 20b99daca7..d8eeaf83f3 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/ISQLEditorData.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/ISQLEditorData.ts @@ -56,6 +56,7 @@ export interface ISQLEditorData { executeQuery(): Promise; executeQueryNewTab(): Promise; showExecutionPlan(): Promise; + showOutputLogs(): Promise; executeScript(): Promise; switchEditing(): Promise; getHintProposals(position: number, simple: boolean): Promise; diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts b/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts index a313d6475a..bc422eae2d 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts @@ -25,6 +25,7 @@ import { SqlDialectInfoService } from '../SqlDialectInfoService'; import { SqlEditorService } from '../SqlEditorService'; import { ISQLScriptSegment, SQLParser } from '../SQLParser'; import { SqlExecutionPlanService } from '../SqlResultTabs/ExecutionPlan/SqlExecutionPlanService'; +import { OutputLogsService } from '../SqlResultTabs/OutputLogs/OutputLogsService'; import { SqlQueryService } from '../SqlResultTabs/SqlQueryService'; import { SqlResultTabsService } from '../SqlResultTabs/SqlResultTabsService'; import type { ICursor, ISQLEditorData } from './ISQLEditorData'; @@ -68,6 +69,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { const sqlResultTabsService = useService(SqlResultTabsService); const commonDialogService = useService(CommonDialogService); const sqlDataSourceService = useService(SqlDataSourceService); + const sqlOutputLogsService = useService(OutputLogsService); const data = useObservableRef( () => ({ @@ -298,6 +300,10 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { } catch {} }, + async showOutputLogs(): Promise { + sqlOutputLogsService.showOutputLogs(this.state); + }, + async switchEditing(): Promise { this.dataSource?.setEditing(!this.dataSource.isEditing()); }, @@ -465,6 +471,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { executeQuery: action.bound, executeQueryNewTab: action.bound, showExecutionPlan: action.bound, + showOutputLogs: action.bound, executeScript: action.bound, switchEditing: action.bound, dialect: computed, diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorService.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorService.ts index 07d65961e8..7d625aaa36 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditorService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditorService.ts @@ -72,6 +72,7 @@ export class SqlEditorService { resultTabs: observable([]), executionPlanTabs: observable([]), statisticsTabs: observable([]), + outputLogsTab: undefined, currentModeId: undefined, modeState: observable([]), }); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts new file mode 100644 index 0000000000..1c56a7a126 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts @@ -0,0 +1,3 @@ +import { createMenu } from '@cloudbeaver/core-view'; + +export const OUTPUT_LOGS_FILTER_MENU = createMenu('output_logs_filter_menu', 'Output Logs'); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts new file mode 100644 index 0000000000..04e715ee85 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts @@ -0,0 +1,5 @@ +import { createDataContext } from '@cloudbeaver/core-view'; + +import type { SqlOutputLogsPanelState } from './useOutputLogsPanelState'; + +export const OUTPUT_LOGS_PANEL_STATE = createDataContext('output-logs-panel-state'); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts new file mode 100644 index 0000000000..eeb5a8b65b --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts @@ -0,0 +1,58 @@ +import { Bootstrap, injectable } from '@cloudbeaver/core-di'; +import { MenuCheckboxItem, MenuService } from '@cloudbeaver/core-view'; + +import { OUTPUT_LOGS_FILTER_MENU } from './OUTPUT_LOGS_FILTER_MENU'; +import { OUTPUT_LOGS_PANEL_STATE } from './OUTPUT_LOGS_PANEL_STATE'; +import { OUTPUT_LOG_TYPES } from './useOutputLogsPanelState'; + +@injectable() +export class OutputFilterMenuBootstrap extends Bootstrap { + constructor(private readonly menuService: MenuService) { + super(); + } + + register(): void | Promise { + this.menuService.addCreator({ + menus: [OUTPUT_LOGS_FILTER_MENU], + isApplicable: context => true, + getItems: (context, items) => [...items], + }); + + this.menuService.addCreator({ + menus: [OUTPUT_LOGS_FILTER_MENU], + getItems: context => { + const state = context.get(OUTPUT_LOGS_PANEL_STATE); + const items = []; + + for (const logType of OUTPUT_LOG_TYPES) { + items.push( + new MenuCheckboxItem( + { + id: logType, + label: logType, + tooltip: logType, + }, + { + onSelect: () => { + console.log(context.get(OUTPUT_LOGS_PANEL_STATE)); + if (state.selectedLogTypes.includes(logType)) { + state.setSelectedLogTypes(state.selectedLogTypes.filter(type => type !== logType)); + return; + } + state.setSelectedLogTypes([...state.selectedLogTypes, logType]); + }, + }, + { + isChecked: () => state.selectedLogTypes.includes(logType), + }, + ), + ); + } + + return items; + }, + }); + } + + async load(): Promise {} +} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.m.css b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.m.css new file mode 100644 index 0000000000..1000b127c5 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.m.css @@ -0,0 +1,10 @@ +.contextMenu { + height: 100%; + padding: 0; + + & .icon { + width: 16px; + height: 100%; + padding: 0 8px; + } +} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx new file mode 100644 index 0000000000..4346f5d538 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx @@ -0,0 +1,29 @@ +import { observer } from 'mobx-react-lite'; +import styled from 'reshadow'; + +import { Icon, s, useS } from '@cloudbeaver/core-blocks'; +import { ContextMenu } from '@cloudbeaver/core-ui'; +import { useMenu } from '@cloudbeaver/core-view'; + +import { OUTPUT_LOGS_FILTER_MENU } from './OUTPUT_LOGS_FILTER_MENU'; +import { OUTPUT_LOGS_PANEL_STATE } from './OUTPUT_LOGS_PANEL_STATE'; +import style from './OutputLogTypesFilterMenu.m.css'; +import type { SqlOutputLogsPanelState } from './useOutputLogsPanelState'; + +interface Props { + state: SqlOutputLogsPanelState; +} + +export const OutputLogsFilterMenu = observer(function OutputLogTypesFilterMenu({ state }) { + const styles = useS(style); + const menu = useMenu({ + menu: OUTPUT_LOGS_FILTER_MENU, + }); + menu.context.set(OUTPUT_LOGS_PANEL_STATE, state); + + return styled(styles)( + + + , + ); +}); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts similarity index 83% rename from webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler.ts rename to webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts index 6db75af1bf..c9b2ee025f 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts @@ -12,13 +12,12 @@ import type { CbSessionLogEvent as ISessionLogEvent } from '@cloudbeaver/core-sd export { type ISessionLogEvent }; @injectable() -export class SqlOutputLogsEventHandler extends TopicEventHandler { +export class OutputLogsEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { super(SessionEventTopic.CbOutputLog, sessionEventSource); } map(event: any) { - console.log('map', event); return event; } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.m.css b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.m.css new file mode 100644 index 0000000000..985fa8272d --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.m.css @@ -0,0 +1,13 @@ +.container { + composes: theme-background-secondary from global; + height: 100%; + display: flex; + flex-direction: column; + width: 100%; +} + +.editorContainer { + padding: 8px; + overflow: auto; + height: 100%; +} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx new file mode 100644 index 0000000000..0a142421ff --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx @@ -0,0 +1,32 @@ +import { highlightSelectionMatches } from '@codemirror/search'; +import { observer } from 'mobx-react-lite'; + +import { s, useResource, useS } from '@cloudbeaver/core-blocks'; +import { EditorLoader, useCodemirrorExtensions } from '@cloudbeaver/plugin-codemirror6'; + +import type { IOutputLogsTab } from '../../ISqlEditorTabState'; +import style from './OutputLogsPanel.m.css'; +import { OutputLogsResource } from './OutputLogsResource'; +import { OutputLogsToolbar } from './OutputLogsToolbar'; +import { useOutputLogsPanelState } from './useOutputLogsPanelState'; + +interface Props { + outputLogsTab: IOutputLogsTab; +} + +export const OutputLogsPanel = observer(function SqlOutputLogsPanel({ outputLogsTab }) { + const styles = useS(style); + const { data } = useResource(SqlOutputLogsPanel, OutputLogsResource, undefined); + const state = useOutputLogsPanelState(data); + + const editorExtensions = useCodemirrorExtensions(undefined, [highlightSelectionMatches()]); + + return ( +
+ +
+ {data && } +
+
+ ); +}); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts new file mode 100644 index 0000000000..fe1743b40d --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts @@ -0,0 +1,47 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { ServerEventId } from '@cloudbeaver/core-root'; +import { CachedDataResource, CbServerEvent, GraphQLService } from '@cloudbeaver/core-sdk'; + +import { OutputLogsEventHandler } from './OutputLogsEventHandler'; +import type { OutputLogType } from './useOutputLogsPanelState'; + +export interface IOutputLog { + message: string; + severity: OutputLogType; +} + +interface IOutputLogEvent extends CbServerEvent { + eventTimestamp: number; + timestamp: number; + asyncTaskId: number; + messages: IOutputLog[]; +} + +@injectable() +export class OutputLogsResource extends CachedDataResource { + constructor(sqlOutputLogsEventHandler: OutputLogsEventHandler, private readonly graphQLService: GraphQLService) { + super(() => []); + + sqlOutputLogsEventHandler.onEvent( + ServerEventId.CbDatabaseOutputLogUpdated, + (event: IOutputLogEvent) => { + console.log('event', event); + this.setData((this.data || []).concat(event.messages)); + this.markOutdated(); + }, + undefined, + this, + ); + } + + protected async loader(): Promise { + return this.data; + } +} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts new file mode 100644 index 0000000000..e0869b4aa1 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts @@ -0,0 +1,57 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 type { ISqlEditorTabState } from '../../ISqlEditorTabState'; +import { SqlDataSourceService } from '../../SqlDataSource/SqlDataSourceService'; + +@injectable() +export class OutputLogsService { + constructor(private readonly sqlDataSourceService: SqlDataSourceService) {} + + async showOutputLogs(editorState: ISqlEditorTabState): Promise { + const tabId = this.createOutputLogsTab(editorState); + editorState.currentTabId = tabId; + } + + removeOutputLogsTab(state: ISqlEditorTabState, tabId: string): void { + const outputLogsTab = state.tabs.find(outputLogsTab => outputLogsTab.id === tabId); + + if (outputLogsTab) { + state.tabs.splice(state.tabs.indexOf(outputLogsTab), 1); + } + } + + private createOutputLogsTab(state: ISqlEditorTabState) { + const dataSource = this.sqlDataSourceService.get(state.editorId); + if (!dataSource) { + throw new Error('SQL Data Source is not provided'); + } + + const id = 'output-logs'; + const order = Math.max(0, ...state.tabs.map(tab => tab.order + 1)); + + if (state.tabs.find(tab => tab.id === id)) { + return; + } + + state.outputLogsTab = { + tabId: id, + order, + }; + + state.tabs.push({ + id, + name: 'Output', + icon: 'execution-plan-tab', // todo change icon + order, + }); + + return id; + } +} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.m.css b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.m.css new file mode 100644 index 0000000000..c02dccdbb5 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.m.css @@ -0,0 +1,16 @@ +.container { + display: flex; + align-content: center; + justify-content: center; + align-items: center; + padding: 8px 8px 0 8px; + gap: 8px; + + & > .inlineEditor { + height: 24px; + } +} + +.inlineEditor { + composes: theme-background-surface theme-text-on-surface from global; +} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx new file mode 100644 index 0000000000..7ce7e52ff4 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx @@ -0,0 +1,33 @@ +import { observer } from 'mobx-react-lite'; +import React from 'react'; + +import { s, useS, useTranslate } from '@cloudbeaver/core-blocks'; +import { InlineEditor } from '@cloudbeaver/core-ui'; + +import style from './OutputLogsToolbar.m.css'; +import { OutputLogsFilterMenu } from './OutputLogTypesFilterMenu'; +import type { SqlOutputLogsPanelState } from './useOutputLogsPanelState'; + +interface Props { + state: SqlOutputLogsPanelState; +} + +export const OutputLogsToolbar = observer(function SqlOutputLogsToolbar({ state }) { + const styles = useS(style); + const translate = useTranslate(); + + return ( +
+ + +
+ ); +}); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts new file mode 100644 index 0000000000..7004728a6e --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts @@ -0,0 +1,54 @@ +import { action, computed, observable } from 'mobx'; + +import { useObservableRef } from '@cloudbeaver/core-blocks'; + +import type { IOutputLog } from './OutputLogsResource'; + +export interface SqlOutputLogsPanelState { + searchValue: any; + setSearchValue: (value: string) => void; + selectedLogTypes: OutputLogType[]; + readonly resultValue: string; + setSelectedLogTypes: (value: OutputLogType[]) => void; + readonly filteredLogs: IOutputLog[]; +} + +export const OUTPUT_LOG_TYPES = ['Debug', 'Log', 'Info', 'Notice', 'Warning', 'Error'] as const; +export type OutputLogType = (typeof OUTPUT_LOG_TYPES)[number]; +export const useOutputLogsPanelState = (outputLogs: IOutputLog[]) => { + return useObservableRef( + () => ({ + searchValue: '', + selectedLogTypes: [...OUTPUT_LOG_TYPES], + setSearchValue(value: string) { + this.searchValue = value; + }, + setSelectedLogTypes(value: OutputLogType[]) { + this.selectedLogTypes = value; + }, + get filteredLogs() { + return outputLogs.filter(log => { + if (this.selectedLogTypes.length > 0 && !this.selectedLogTypes.includes(log.severity)) { + return false; + } + if (this.searchValue.length > 0 && !log.message.includes(this.searchValue)) { + return false; + } + return true; + }); + }, + get resultValue() { + return this.filteredLogs.map(log => `[${log.severity}] ${log.message}`).join('\n'); + }, + }), + { + searchValue: observable.ref, + selectedLogTypes: observable.ref, + setSearchValue: action.bound, + setSelectedLogTypes: action.bound, + filteredLogs: computed, + resultValue: computed, + }, + false, + ); +}; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource.ts deleted file mode 100644 index 595d32c352..0000000000 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 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 { ServerEventId } from '@cloudbeaver/core-root'; -import { CachedDataResource, GraphQLService, LogEntry } from '@cloudbeaver/core-sdk'; - -import { SqlOutputLogsEventHandler } from './SqlOutputLogsEventHandler'; - -export interface ILogEntry extends LogEntry { - id: string; -} - -@injectable() -export class SqlOutputLogsResource extends CachedDataResource { - constructor(sqlOutputLogsEventHandler: SqlOutputLogsEventHandler, private readonly graphQLService: GraphQLService) { - super(() => []); - - sqlOutputLogsEventHandler.onEvent( - ServerEventId.CbDatabaseOutputLogUpdated, - event => { - // @ts-ignore - console.log('onEvent', event?.messages as any); - // @ts-ignore - this.setData((this.data || []).concat(event?.messages as any)); - this.markOutdated(); - }, - e => e, - this, - ); - } - - protected async loader(): Promise { - console.groupCollapsed('SqlOutputLogsResource'); - console.log('loader', this.data); - console.groupEnd(); - - return this.data; - } -} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultPanel.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultPanel.tsx index 523fa6876d..171c33e94b 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultPanel.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultPanel.tsx @@ -10,6 +10,7 @@ import styled, { css } from 'reshadow'; import type { ISqlEditorTabState } from '../ISqlEditorTabState'; import { SqlExecutionPlanPanel } from './ExecutionPlan/SqlExecutionPlanPanel'; +import { OutputLogsPanel } from './OutputLogs/OutputLogsPanel'; import { SqlResultSetPanel } from './SqlResultSetPanel'; import { SqlScriptStatisticsPanel } from './SqlScriptStatisticsPanel'; @@ -59,5 +60,13 @@ export const SqlResultPanel = observer(function SqlResultPanel({ state, i ); } + if (state.outputLogsTab) { + return styled(style)( + + + , + ); + } + return null; }); diff --git a/webapp/packages/plugin-sql-editor/src/index.ts b/webapp/packages/plugin-sql-editor/src/index.ts index ee63a1233f..755f70e50a 100644 --- a/webapp/packages/plugin-sql-editor/src/index.ts +++ b/webapp/packages/plugin-sql-editor/src/index.ts @@ -10,7 +10,7 @@ export * from './actions/ACTION_SQL_EDITOR_EXECUTE_SCRIPT'; export * from './actions/ACTION_SQL_EDITOR_EXECUTE'; export * from './actions/ACTION_SQL_EDITOR_FORMAT'; export * from './actions/ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN'; -export * from './actions/ACTION_SQL_EDITOR_SHOW_OUTPUT' +export * from './actions/ACTION_SQL_EDITOR_SHOW_OUTPUT'; export * from './SqlDataSource/LocalStorage/ILocalStorageSqlDataSourceState'; export * from './SqlDataSource/LocalStorage/LocalStorageSqlDataSource'; export * from './SqlDataSource/LocalStorage/LocalStorageSqlDataSourceBootstrap'; @@ -28,8 +28,9 @@ export * from './SqlEditor/SQL_EDITOR_TOOLS_MENU'; export * from './SqlEditor/SQLEditorModeContext'; export * from './SqlResultTabs/DATA_CONTEXT_SQL_EDITOR_RESULT_ID'; export * from './SqlResultTabs/SqlResultTabsService'; -export * from './SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler'; -export * from './SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource'; +export * from './SqlResultTabs/OutputLogs/OutputLogsEventHandler'; +export * from './SqlResultTabs/OutputLogs/OutputLogsResource'; +export * from './SqlResultTabs/OutputLogs/OutputLogsService'; export * from './DATA_CONTEXT_SQL_EDITOR_STATE'; export * from './getSqlEditorName'; export * from './QueryDataSource'; diff --git a/webapp/packages/plugin-sql-editor/src/locales/en.ts b/webapp/packages/plugin-sql-editor/src/locales/en.ts index 18019d3dd0..1cdf95433a 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/en.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/en.ts @@ -7,7 +7,8 @@ export default [ ['sql_editor_placeholder', 'Execute query with Ctrl+Enter to see results'], ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', 'Explain execution plan (Shift + Ctrl + E)'], - ['sql_editor_output_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_input_placeholder', 'Enter a part of a message to search for here'], ['sql_editor_sql_execution_button_tooltip', 'Execute SQL Statement (Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', 'Execute SQL Statement in new tab (Ctrl + \\)(Shift + Ctrl + Enter)'], ['sql_editor_sql_execution_script_button_tooltip', 'Execute SQL Script (Alt + X)'], diff --git a/webapp/packages/plugin-sql-editor/src/locales/it.ts b/webapp/packages/plugin-sql-editor/src/locales/it.ts index 71cbb5572d..4f9b26d165 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/it.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/it.ts @@ -7,7 +7,8 @@ export default [ ['sql_editor_placeholder', 'Esegui la query con Ctrl+Enter per vedere i risultati'], ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', 'Mostra il piano di esecuzione (Shift + Ctrl + E)'], - ['sql_editor_output_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_input_placeholder', 'Enter a part of a message to search for here'], ['sql_editor_sql_execution_button_tooltip', "Esegui l'istruzione SQL (Ctrl + Enter)"], ['sql_editor_sql_execution_new_tab_button_tooltip', "Esegui l'istruzione SQL in una nuova tab (Ctrl + \\)(Shift + Ctrl + Enter)"], ['sql_editor_sql_execution_script_button_tooltip', 'Esegui lo script SQL (Alt + X)'], diff --git a/webapp/packages/plugin-sql-editor/src/locales/ru.ts b/webapp/packages/plugin-sql-editor/src/locales/ru.ts index 7acfdb34b9..97058038e2 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/ru.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/ru.ts @@ -7,7 +7,8 @@ export default [ ['sql_editor_placeholder', 'Нажмите Ctrl+Enter, чтобы выполнить запрос и увидеть результат'], ['sql_editor_hint_empty', 'Нет авто-дополнений...'], ['sql_editor_execution_plan_button_tooltip', 'Посмотреть информацию о плане выполнения запроса (Shift + Ctrl + E)'], - ['sql_editor_output_button_tooltip', 'Показать вывод сервера (Shift + Ctrl + O)'], + ['sql_editor_output_logs_button_tooltip', 'Показать вывод сервера (Shift + Ctrl + O)'], + ['sql_editor_output_logs_input_placeholder', 'Введите часть сообщения для поиска'], ['sql_editor_sql_execution_button_tooltip', 'Выполнить SQL Выражение (Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', 'Выполнить SQL Выражение в новой вкладке (Ctrl + \\)(Shift + Ctrl + Enter)'], ['sql_editor_sql_execution_script_button_tooltip', 'Исполнить SQL Скрипт (Alt + X)'], diff --git a/webapp/packages/plugin-sql-editor/src/locales/zh.ts b/webapp/packages/plugin-sql-editor/src/locales/zh.ts index 3c3fe39221..7cecf67b40 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/zh.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/zh.ts @@ -7,7 +7,8 @@ export default [ ['sql_editor_placeholder', '使用Ctrl + Enter执行查询以查看结果'], ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', '解释执行计划(Shift + Ctrl + E)'], - ['sql_editor_output_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_input_placeholder', 'Enter a part of a message to search for here'], ['sql_editor_sql_execution_button_tooltip', '执行SQL语句(Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', '在新选项卡中执行SQL语句(Ctrl + \\)(Shift + Ctrl + Enter)'], ['sql_editor_sql_execution_script_button_tooltip', '执行SQL脚本(Alt + X)'], diff --git a/webapp/packages/plugin-sql-editor/src/manifest.ts b/webapp/packages/plugin-sql-editor/src/manifest.ts index 799d1942e6..6b47f50f91 100644 --- a/webapp/packages/plugin-sql-editor/src/manifest.ts +++ b/webapp/packages/plugin-sql-editor/src/manifest.ts @@ -17,8 +17,10 @@ import { SqlEditorService } from './SqlEditorService'; import { SqlEditorSettingsService } from './SqlEditorSettingsService'; import { SqlEditorView } from './SqlEditorView'; import { SqlExecutionPlanService } from './SqlResultTabs/ExecutionPlan/SqlExecutionPlanService'; -import { SqlOutputLogsEventHandler } from './SqlResultTabs/SqlOutputLogs/SqlOutputLogsEventHandler'; -import { SqlOutputLogsResource } from './SqlResultTabs/SqlOutputLogs/SqlOutputLogsResource'; +import { OutputFilterMenuBootstrap } from './SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap'; +import { OutputLogsEventHandler } from './SqlResultTabs/OutputLogs/OutputLogsEventHandler'; +import { OutputLogsResource } from './SqlResultTabs/OutputLogs/OutputLogsResource'; +import { OutputLogsService } from './SqlResultTabs/OutputLogs/OutputLogsService'; import { SqlQueryResultService } from './SqlResultTabs/SqlQueryResultService'; import { SqlQueryService } from './SqlResultTabs/SqlQueryService'; import { SqlResultTabsService } from './SqlResultTabs/SqlResultTabsService'; @@ -42,7 +44,9 @@ export const sqlEditorPluginManifest: PluginManifest = { MenuBootstrap, SqlDataSourceService, LocalStorageSqlDataSourceBootstrap, - SqlOutputLogsEventHandler, - SqlOutputLogsResource, + OutputLogsEventHandler, + OutputLogsResource, + OutputLogsService, + OutputFilterMenuBootstrap, ], }; From 852d5e41af935bc43dfcfe66bbae4805edcc38be Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Tue, 12 Sep 2023 04:00:07 +0200 Subject: [PATCH 04/13] CB-3924: fix bugs --- .../plugin-sql-editor/src/MenuBootstrap.ts | 2 +- .../src/SqlEditor/SqlEditor.tsx | 20 +++++++++++++------ .../OutputLogs/OutputFilterMenuBootstrap.ts | 1 - .../OutputLogs/OutputLogsResource.ts | 1 - .../actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts | 4 ++-- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts index 0164c37f98..cb7c23f74a 100644 --- a/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts +++ b/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts @@ -194,7 +194,7 @@ export class MenuBootstrap extends Bootstrap { break; case ACTION_SQL_EDITOR_SHOW_OUTPUT: // TODO change it to show output - data.showExecutionPlan(); + data.showOutputLogs(); break; } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx index 5de8b170c8..66cfbd636c 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx @@ -9,7 +9,14 @@ import { observer } from 'mobx-react-lite'; import { useEffect, useMemo, useState } from 'react'; import styled, { css } from 'reshadow'; -import { getComputed, preventFocusHandler, StaticImage, useSplit, useTranslate } from '@cloudbeaver/core-blocks'; +import { + getComputed, + preventFocusHandler, + StaticImage, + useResource, + useSplit, + useTranslate +} from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { BASE_TAB_STYLES, ITabData, TabList, TabPanelList, TabsState, VERTICAL_ROTATED_TAB_STYLES } from '@cloudbeaver/core-ui'; import { MetadataMap } from '@cloudbeaver/core-utils'; @@ -22,6 +29,7 @@ import type { ISqlEditorProps } from './ISqlEditorProps'; import { SqlEditorActionsMenu } from './SqlEditorActionsMenu'; import { SqlEditorTools } from './SqlEditorTools'; import { useSqlEditor } from './useSqlEditor'; +import {OutputLogsResource} from "../SqlResultTabs/OutputLogs/OutputLogsResource"; const styles = css` button, @@ -109,6 +117,7 @@ export const SqlEditor = observer(function SqlEditor({ state, c const sqlEditorModeService = useService(SqlEditorModeService); const data = useSqlEditor(state); const [modesState] = useState(() => new MetadataMap()); + useResource(SqlEditor, OutputLogsResource, undefined); useMemo(() => { modesState.sync(state.modeState); @@ -185,11 +194,10 @@ export const SqlEditor = observer(function SqlEditor({ state, c )} - {isQuery && data.dialect?.supportsExplainExecutionPlan && ( - - )} + {/*TODO update icon*/} + )} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts index eeb5a8b65b..140b388228 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts @@ -34,7 +34,6 @@ export class OutputFilterMenuBootstrap extends Bootstrap { }, { onSelect: () => { - console.log(context.get(OUTPUT_LOGS_PANEL_STATE)); if (state.selectedLogTypes.includes(logType)) { state.setSelectedLogTypes(state.selectedLogTypes.filter(type => type !== logType)); return; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts index fe1743b40d..db2913868d 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts @@ -32,7 +32,6 @@ export class OutputLogsResource extends CachedDataResource { sqlOutputLogsEventHandler.onEvent( ServerEventId.CbDatabaseOutputLogUpdated, (event: IOutputLogEvent) => { - console.log('event', event); this.setData((this.data || []).concat(event.messages)); this.markOutdated(); }, diff --git a/webapp/packages/plugin-sql-editor/src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts b/webapp/packages/plugin-sql-editor/src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts index f786a61583..ef3a9deee5 100644 --- a/webapp/packages/plugin-sql-editor/src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts +++ b/webapp/packages/plugin-sql-editor/src/actions/ACTION_SQL_EDITOR_SHOW_OUTPUT.ts @@ -8,6 +8,6 @@ import { createAction } from '@cloudbeaver/core-view'; export const ACTION_SQL_EDITOR_SHOW_OUTPUT = createAction('sql-editor-show-output', { - icon: '/icons/sql_output.svg', - label: 'sql_editor_output_button_tooltip', + icon: '/icons/sql_output.svg', // todo change icon + label: 'sql_editor_output_logs_button_tooltip', }); From 47c5c61d8f1fd04e02686f9ef7229d64ec47eea2 Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Tue, 12 Sep 2023 12:29:57 +0200 Subject: [PATCH 05/13] CB-3924: fixes after review --- .../plugin-codemirror6/src/Editor.tsx | 28 +++++- .../src/useEditorDefaultExtensions.ts | 95 +++++++++++-------- .../src/SqlEditor/SqlEditor.tsx | 2 +- .../OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts | 7 ++ .../OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts | 7 ++ .../OutputLogs/OutputFilterMenuBootstrap.ts | 7 ++ .../OutputLogs/OutputLogTypesFilterMenu.tsx | 12 ++- .../OutputLogs/OutputLogsPanel.tsx | 11 ++- .../OutputLogs/OutputLogsResource.ts | 1 - .../OutputLogs/OutputLogsToolbar.tsx | 7 ++ .../OutputLogs/useOutputLogsPanelState.ts | 13 ++- 11 files changed, 132 insertions(+), 58 deletions(-) diff --git a/webapp/packages/plugin-codemirror6/src/Editor.tsx b/webapp/packages/plugin-codemirror6/src/Editor.tsx index 74dd233f51..a8818e8942 100644 --- a/webapp/packages/plugin-codemirror6/src/Editor.tsx +++ b/webapp/packages/plugin-codemirror6/src/Editor.tsx @@ -18,14 +18,32 @@ import { EDITOR_BASE_STYLES } from './theme'; import { useCodemirrorExtensions } from './useCodemirrorExtensions'; import { type IDefaultExtensions, useEditorDefaultExtensions } from './useEditorDefaultExtensions'; +const defaultExtensionsFlags: IDefaultExtensions = { + lineNumbers: false, + tooltips: true, + highlightSpecialChars: true, + syntaxHighlighting: true, + bracketMatching: true, + dropCursor: true, + crosshairCursor: true, + foldGutter: true, + highlightActiveLineGutter: true, + highlightActiveLine: true, + indentOnInput: true, + rectangularSelection: true, + keymap: true, +}; + export const Editor = observer( - forwardRef(function Editor({ lineNumbers, extensions, useDefaultExtensions = true, ...rest }, ref) { + forwardRef(function Editor({ extensions, ...rest }, ref) { extensions = useCodemirrorExtensions(extensions); - const defaultExtensions = useEditorDefaultExtensions({ lineNumbers }); - if (useDefaultExtensions) { - extensions.set(...defaultExtensions); - } + const defaultExtensions = useEditorDefaultExtensions({ + ...defaultExtensionsFlags, + ...rest, + }); + + extensions.set(...defaultExtensions); return styled(EDITOR_BASE_STYLES)( diff --git a/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts b/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts index cbfd1ca01b..c8acff30bb 100644 --- a/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts +++ b/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts @@ -36,53 +36,66 @@ DEFAULT_KEY_MAP.push({ export interface IDefaultExtensions { lineNumbers?: boolean; + tooltips?: boolean; + highlightSpecialChars?: boolean; + syntaxHighlighting?: boolean; + bracketMatching?: boolean; + dropCursor?: boolean; + crosshairCursor?: boolean; + foldGutter?: boolean; + highlightActiveLineGutter?: boolean; + highlightActiveLine?: boolean; + indentOnInput?: boolean; + rectangularSelection?: boolean; + keymap?: boolean; } -const DEFAULT_EXTENSIONS_COMPARTMENT = new Compartment(); - -/** Provides the necessary extensions to establish a basic editor */ -export function useEditorDefaultExtensions(options?: IDefaultExtensions): [Compartment, Extension] { - return useMemo(() => { - const extensions = []; - if (options?.lineNumbers) { - extensions.push(lineNumbers()); - } +const extensionMap = { + lineNumbers, + tooltips: () => tooltips({ parent: document.body }), + highlightSpecialChars, + syntaxHighlighting: () => syntaxHighlighting(classHighlighter), + bracketMatching, + dropCursor, + crosshairCursor, + foldGutter: () => + foldGutter({ + markerDOM: (open: boolean) => { + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + svg.setAttributeNS(null, 'viewBox', '0 0 15 8'); + svg.style.maxWidth = '100%'; + svg.style.maxHeight = '100%'; - extensions.push( - tooltips({ - parent: document.body, - }), - highlightSpecialChars(), - highlightSelectionMatches(), - syntaxHighlighting(classHighlighter), - bracketMatching(), - dropCursor(), - crosshairCursor(), - foldGutter({ - markerDOM: (open: boolean) => { - const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - svg.setAttributeNS(null, 'viewBox', '0 0 15 8'); - svg.style.maxWidth = '100%'; - svg.style.maxHeight = '100%'; + const use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); + use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', GlobalConstants.absoluteUrl('/icons/icons.svg#angle')); + svg.appendChild(use); - const use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); - use.setAttributeNS('http://www.w3.org/1999/xlink', 'href', GlobalConstants.absoluteUrl('/icons/icons.svg#angle')); - svg.appendChild(use); + const element = document.createElement('div'); + element.appendChild(svg); + element.className = clsx('cm-gutterElement-icon', open ? 'cm-foldGutter-open' : 'cm-foldGutter-folded'); - const element = document.createElement('div'); - element.appendChild(svg); - element.className = clsx('cm-gutterElement-icon', open ? 'cm-foldGutter-open' : 'cm-foldGutter-folded'); + return element; + }, + }), + highlightActiveLineGutter, + highlightActiveLine, + indentOnInput, + rectangularSelection, + keymap: () => keymap.of(DEFAULT_KEY_MAP), +}; - return element; - }, - }), - highlightActiveLineGutter(), - highlightActiveLine(), - indentOnInput(), - rectangularSelection(), - keymap.of(DEFAULT_KEY_MAP), - ); +const DEFAULT_EXTENSIONS_COMPARTMENT = new Compartment(); +/** Provides the necessary extensions to establish a basic editor */ +export function useEditorDefaultExtensions(options?: IDefaultExtensions): [Compartment, Extension] { + return useMemo(() => { + const extensions = Object.entries(options || {}) + .filter(([, isEnabled]) => isEnabled) + .map(([key]) => { + const extensionFunction = extensionMap[key as keyof typeof extensionMap]; + return extensionFunction?.(); + }) + .filter(Boolean); return [DEFAULT_EXTENSIONS_COMPARTMENT, extensions]; - }, [options?.lineNumbers]); + }, [options]); } diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx index 66cfbd636c..683eb7606d 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/SqlEditor.tsx @@ -29,7 +29,7 @@ import type { ISqlEditorProps } from './ISqlEditorProps'; import { SqlEditorActionsMenu } from './SqlEditorActionsMenu'; import { SqlEditorTools } from './SqlEditorTools'; import { useSqlEditor } from './useSqlEditor'; -import {OutputLogsResource} from "../SqlResultTabs/OutputLogs/OutputLogsResource"; +import { OutputLogsResource } from '../SqlResultTabs/OutputLogs/OutputLogsResource'; const styles = css` button, diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts index 1c56a7a126..e1f53931bd 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_FILTER_MENU.ts @@ -1,3 +1,10 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 OUTPUT_LOGS_FILTER_MENU = createMenu('output_logs_filter_menu', 'Output Logs'); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts index 04e715ee85..40309fa33c 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts @@ -1,3 +1,10 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { SqlOutputLogsPanelState } from './useOutputLogsPanelState'; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts index 140b388228..c0922d428b 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts @@ -1,3 +1,10 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { MenuCheckboxItem, MenuService } from '@cloudbeaver/core-view'; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx index 4346f5d538..2175be6a73 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx @@ -1,5 +1,11 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { observer } from 'mobx-react-lite'; -import styled from 'reshadow'; import { Icon, s, useS } from '@cloudbeaver/core-blocks'; import { ContextMenu } from '@cloudbeaver/core-ui'; @@ -21,9 +27,9 @@ export const OutputLogsFilterMenu = observer(function OutputLogTypesFilte }); menu.context.set(OUTPUT_LOGS_PANEL_STATE, state); - return styled(styles)( + return ( - , + ); }); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx index 0a142421ff..3eb64a0da8 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx @@ -1,3 +1,10 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { highlightSelectionMatches } from '@codemirror/search'; import { observer } from 'mobx-react-lite'; @@ -19,13 +26,11 @@ export const OutputLogsPanel = observer(function SqlOutputLogsPanel({ out const { data } = useResource(SqlOutputLogsPanel, OutputLogsResource, undefined); const state = useOutputLogsPanelState(data); - const editorExtensions = useCodemirrorExtensions(undefined, [highlightSelectionMatches()]); - return (
- {data && } + {data && }
); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts index db2913868d..0af5471634 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts @@ -33,7 +33,6 @@ export class OutputLogsResource extends CachedDataResource { ServerEventId.CbDatabaseOutputLogUpdated, (event: IOutputLogEvent) => { this.setData((this.data || []).concat(event.messages)); - this.markOutdated(); }, undefined, this, diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx index 7ce7e52ff4..f805071b97 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx @@ -1,3 +1,10 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { observer } from 'mobx-react-lite'; import React from 'react'; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts index 7004728a6e..7e7d8bc2c0 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts @@ -1,3 +1,10 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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, computed, observable } from 'mobx'; import { useObservableRef } from '@cloudbeaver/core-blocks'; @@ -5,7 +12,7 @@ import { useObservableRef } from '@cloudbeaver/core-blocks'; import type { IOutputLog } from './OutputLogsResource'; export interface SqlOutputLogsPanelState { - searchValue: any; + searchValue: string; setSearchValue: (value: string) => void; selectedLogTypes: OutputLogType[]; readonly resultValue: string; @@ -15,8 +22,7 @@ export interface SqlOutputLogsPanelState { export const OUTPUT_LOG_TYPES = ['Debug', 'Log', 'Info', 'Notice', 'Warning', 'Error'] as const; export type OutputLogType = (typeof OUTPUT_LOG_TYPES)[number]; -export const useOutputLogsPanelState = (outputLogs: IOutputLog[]) => { - return useObservableRef( +export const useOutputLogsPanelState = (outputLogs: IOutputLog[]) => useObservableRef( () => ({ searchValue: '', selectedLogTypes: [...OUTPUT_LOG_TYPES], @@ -51,4 +57,3 @@ export const useOutputLogsPanelState = (outputLogs: IOutputLog[]) => { }, false, ); -}; From cd8c526acd530603583fc963523d9cad20fbbc52 Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Tue, 12 Sep 2023 14:07:10 +0200 Subject: [PATCH 06/13] CB-3924: fixes after review --- .../plugin-codemirror6/src/Editor.tsx | 41 ++++++++++++++++++- .../plugin-codemirror6/src/IEditorProps.ts | 1 - 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/webapp/packages/plugin-codemirror6/src/Editor.tsx b/webapp/packages/plugin-codemirror6/src/Editor.tsx index a8818e8942..0b582ac3b6 100644 --- a/webapp/packages/plugin-codemirror6/src/Editor.tsx +++ b/webapp/packages/plugin-codemirror6/src/Editor.tsx @@ -35,12 +35,49 @@ const defaultExtensionsFlags: IDefaultExtensions = { }; export const Editor = observer( - forwardRef(function Editor({ extensions, ...rest }, ref) { + forwardRef(function Editor( + { + extensions, + lineNumbers, + tooltips, + highlightSpecialChars, + syntaxHighlighting, + bracketMatching, + dropCursor, + crosshairCursor, + foldGutter, + highlightActiveLineGutter, + highlightActiveLine, + indentOnInput, + rectangularSelection, + keymap, + ...rest + }, + ref, + ) { extensions = useCodemirrorExtensions(extensions); + const filteredDefaultExtensionsFlagsFromProps = Object.fromEntries( + Object.entries({ + lineNumbers, + tooltips, + highlightSpecialChars, + syntaxHighlighting, + bracketMatching, + dropCursor, + crosshairCursor, + foldGutter, + highlightActiveLineGutter, + highlightActiveLine, + indentOnInput, + rectangularSelection, + keymap, + }).filter(([, value]) => value !== undefined), + ); + const defaultExtensions = useEditorDefaultExtensions({ ...defaultExtensionsFlags, - ...rest, + ...filteredDefaultExtensionsFlagsFromProps, }); extensions.set(...defaultExtensions); diff --git a/webapp/packages/plugin-codemirror6/src/IEditorProps.ts b/webapp/packages/plugin-codemirror6/src/IEditorProps.ts index f13cacd381..03b38d14b9 100644 --- a/webapp/packages/plugin-codemirror6/src/IEditorProps.ts +++ b/webapp/packages/plugin-codemirror6/src/IEditorProps.ts @@ -9,5 +9,4 @@ import type { IReactCodeMirrorProps } from './IReactCodemirrorProps'; export interface IEditorProps extends IReactCodeMirrorProps { className?: string; - useDefaultExtensions?: boolean; } From 48c23d004e35c25c3ae33ff4c1d7191f047b8e00 Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Tue, 12 Sep 2023 15:18:31 +0200 Subject: [PATCH 07/13] CB-3924: add line wrapper extension for editor --- webapp/packages/plugin-codemirror6/src/Editor.tsx | 6 ++++++ .../plugin-codemirror6/src/useEditorDefaultExtensions.ts | 6 +++++- .../src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/webapp/packages/plugin-codemirror6/src/Editor.tsx b/webapp/packages/plugin-codemirror6/src/Editor.tsx index 0b582ac3b6..6394a30bcb 100644 --- a/webapp/packages/plugin-codemirror6/src/Editor.tsx +++ b/webapp/packages/plugin-codemirror6/src/Editor.tsx @@ -28,10 +28,12 @@ const defaultExtensionsFlags: IDefaultExtensions = { crosshairCursor: true, foldGutter: true, highlightActiveLineGutter: true, + highlightSelectionMatches: true, highlightActiveLine: true, indentOnInput: true, rectangularSelection: true, keymap: true, + lineWrapping: false, }; export const Editor = observer( @@ -47,10 +49,12 @@ export const Editor = observer( crosshairCursor, foldGutter, highlightActiveLineGutter, + highlightSelectionMatches, highlightActiveLine, indentOnInput, rectangularSelection, keymap, + lineWrapping, ...rest }, ref, @@ -68,10 +72,12 @@ export const Editor = observer( crosshairCursor, foldGutter, highlightActiveLineGutter, + highlightSelectionMatches, highlightActiveLine, indentOnInput, rectangularSelection, keymap, + lineWrapping, }).filter(([, value]) => value !== undefined), ); diff --git a/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts b/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts index c8acff30bb..4294bf0b98 100644 --- a/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts +++ b/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts @@ -11,7 +11,7 @@ import { highlightSelectionMatches } from '@codemirror/search'; import { Compartment, Extension } from '@codemirror/state'; import { crosshairCursor, - dropCursor, + dropCursor, EditorView, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, @@ -44,10 +44,12 @@ export interface IDefaultExtensions { crosshairCursor?: boolean; foldGutter?: boolean; highlightActiveLineGutter?: boolean; + highlightSelectionMatches?: boolean; highlightActiveLine?: boolean; indentOnInput?: boolean; rectangularSelection?: boolean; keymap?: boolean; + lineWrapping?: boolean; } const extensionMap = { @@ -57,6 +59,7 @@ const extensionMap = { syntaxHighlighting: () => syntaxHighlighting(classHighlighter), bracketMatching, dropCursor, + highlightSelectionMatches, crosshairCursor, foldGutter: () => foldGutter({ @@ -82,6 +85,7 @@ const extensionMap = { indentOnInput, rectangularSelection, keymap: () => keymap.of(DEFAULT_KEY_MAP), + lineWrapping: () => EditorView.lineWrapping, }; const DEFAULT_EXTENSIONS_COMPARTMENT = new Compartment(); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx index 3eb64a0da8..b3d90bb2e0 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx @@ -30,7 +30,7 @@ export const OutputLogsPanel = observer(function SqlOutputLogsPanel({ out
- {data && } + {data && }
); From ec78d7ca124caf922c75601984fe8452e76b4894 Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Tue, 12 Sep 2023 18:59:27 +0200 Subject: [PATCH 08/13] CB-3924: show output logs for current context --- .../plugin-codemirror6/src/Editor.tsx | 23 +------------------ .../src/useEditorDefaultExtensions.ts | 23 +++++++++++++++++-- .../OutputLogs/OutputLogsEventHandler.ts | 2 +- .../OutputLogs/OutputLogsPanel.tsx | 16 ++++++++----- .../OutputLogs/OutputLogsResource.ts | 23 ++++--------------- .../OutputLogs/OutputLogsService.ts | 10 ++++++++ .../OutputLogs/useOutputLogsPanelState.ts | 14 ++++++----- .../src/SqlResultTabs/SqlResultPanel.tsx | 2 +- 8 files changed, 57 insertions(+), 56 deletions(-) diff --git a/webapp/packages/plugin-codemirror6/src/Editor.tsx b/webapp/packages/plugin-codemirror6/src/Editor.tsx index 6394a30bcb..5dc732a7e2 100644 --- a/webapp/packages/plugin-codemirror6/src/Editor.tsx +++ b/webapp/packages/plugin-codemirror6/src/Editor.tsx @@ -18,24 +18,6 @@ import { EDITOR_BASE_STYLES } from './theme'; import { useCodemirrorExtensions } from './useCodemirrorExtensions'; import { type IDefaultExtensions, useEditorDefaultExtensions } from './useEditorDefaultExtensions'; -const defaultExtensionsFlags: IDefaultExtensions = { - lineNumbers: false, - tooltips: true, - highlightSpecialChars: true, - syntaxHighlighting: true, - bracketMatching: true, - dropCursor: true, - crosshairCursor: true, - foldGutter: true, - highlightActiveLineGutter: true, - highlightSelectionMatches: true, - highlightActiveLine: true, - indentOnInput: true, - rectangularSelection: true, - keymap: true, - lineWrapping: false, -}; - export const Editor = observer( forwardRef(function Editor( { @@ -81,10 +63,7 @@ export const Editor = observer( }).filter(([, value]) => value !== undefined), ); - const defaultExtensions = useEditorDefaultExtensions({ - ...defaultExtensionsFlags, - ...filteredDefaultExtensionsFlagsFromProps, - }); + const defaultExtensions = useEditorDefaultExtensions(filteredDefaultExtensionsFlagsFromProps); extensions.set(...defaultExtensions); diff --git a/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts b/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts index 4294bf0b98..2df2369438 100644 --- a/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts +++ b/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts @@ -11,7 +11,8 @@ import { highlightSelectionMatches } from '@codemirror/search'; import { Compartment, Extension } from '@codemirror/state'; import { crosshairCursor, - dropCursor, EditorView, + dropCursor, + EditorView, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, @@ -34,6 +35,24 @@ DEFAULT_KEY_MAP.push({ run: () => true, }); +const defaultExtensionsFlags: IDefaultExtensions = { + lineNumbers: false, + tooltips: true, + highlightSpecialChars: true, + syntaxHighlighting: true, + bracketMatching: true, + dropCursor: true, + crosshairCursor: true, + foldGutter: true, + highlightActiveLineGutter: true, + highlightSelectionMatches: true, + highlightActiveLine: true, + indentOnInput: true, + rectangularSelection: true, + keymap: true, + lineWrapping: false, +}; + export interface IDefaultExtensions { lineNumbers?: boolean; tooltips?: boolean; @@ -93,7 +112,7 @@ const DEFAULT_EXTENSIONS_COMPARTMENT = new Compartment(); /** Provides the necessary extensions to establish a basic editor */ export function useEditorDefaultExtensions(options?: IDefaultExtensions): [Compartment, Extension] { return useMemo(() => { - const extensions = Object.entries(options || {}) + const extensions = Object.entries({ ...defaultExtensionsFlags, ...options } || {}) .filter(([, isEnabled]) => isEnabled) .map(([key]) => { const extensionFunction = extensionMap[key as keyof typeof extensionMap]; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts index c9b2ee025f..8c37f52adf 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts @@ -14,7 +14,7 @@ export { type ISessionLogEvent }; @injectable() export class OutputLogsEventHandler extends TopicEventHandler { constructor(sessionEventSource: SessionEventSource) { - super(SessionEventTopic.CbOutputLog, sessionEventSource); + super(SessionEventTopic.CbDatabaseOutputLog, sessionEventSource); } map(event: any) { diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx index b3d90bb2e0..e8c0fde08f 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx @@ -5,26 +5,30 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import { highlightSelectionMatches } from '@codemirror/search'; import { observer } from 'mobx-react-lite'; import { s, useResource, useS } from '@cloudbeaver/core-blocks'; -import { EditorLoader, useCodemirrorExtensions } from '@cloudbeaver/plugin-codemirror6'; +import { useService } from '@cloudbeaver/core-di'; +import { EditorLoader } from '@cloudbeaver/plugin-codemirror6'; -import type { IOutputLogsTab } from '../../ISqlEditorTabState'; +import type { ISqlEditorTabState } from '../../ISqlEditorTabState'; import style from './OutputLogsPanel.m.css'; import { OutputLogsResource } from './OutputLogsResource'; +import { OutputLogsService } from './OutputLogsService'; import { OutputLogsToolbar } from './OutputLogsToolbar'; import { useOutputLogsPanelState } from './useOutputLogsPanelState'; interface Props { - outputLogsTab: IOutputLogsTab; + sqlEditorTabState: ISqlEditorTabState; } -export const OutputLogsPanel = observer(function SqlOutputLogsPanel({ outputLogsTab }) { +export const OutputLogsPanel = observer(function SqlOutputLogsPanel({ sqlEditorTabState }) { const styles = useS(style); + const outputLogsService = useService(OutputLogsService); const { data } = useResource(SqlOutputLogsPanel, OutputLogsResource, undefined); - const state = useOutputLogsPanelState(data); + const outputLogs = outputLogsService.getOutputLogs(data, sqlEditorTabState); + + const state = useOutputLogsPanelState(outputLogs); return (
diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts index 0af5471634..90455e0839 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts @@ -7,39 +7,26 @@ */ import { injectable } from '@cloudbeaver/core-di'; import { ServerEventId } from '@cloudbeaver/core-root'; -import { CachedDataResource, CbServerEvent, GraphQLService } from '@cloudbeaver/core-sdk'; +import { CachedDataResource, CbDatabaseOutputLogEvent, GraphQLService } from '@cloudbeaver/core-sdk'; import { OutputLogsEventHandler } from './OutputLogsEventHandler'; -import type { OutputLogType } from './useOutputLogsPanelState'; - -export interface IOutputLog { - message: string; - severity: OutputLogType; -} - -interface IOutputLogEvent extends CbServerEvent { - eventTimestamp: number; - timestamp: number; - asyncTaskId: number; - messages: IOutputLog[]; -} @injectable() -export class OutputLogsResource extends CachedDataResource { +export class OutputLogsResource extends CachedDataResource { constructor(sqlOutputLogsEventHandler: OutputLogsEventHandler, private readonly graphQLService: GraphQLService) { super(() => []); sqlOutputLogsEventHandler.onEvent( ServerEventId.CbDatabaseOutputLogUpdated, - (event: IOutputLogEvent) => { - this.setData((this.data || []).concat(event.messages)); + (event: CbDatabaseOutputLogEvent) => { + this.setData((this.data || []).concat(event)); }, undefined, this, ); } - protected async loader(): Promise { + protected async loader(): Promise { return this.data; } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts index e0869b4aa1..746be69314 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts @@ -6,6 +6,7 @@ * you may not use this file except in compliance with the License. */ import { injectable } from '@cloudbeaver/core-di'; +import type { CbDatabaseOutputLogEvent } from '@cloudbeaver/core-sdk'; import type { ISqlEditorTabState } from '../../ISqlEditorTabState'; import { SqlDataSourceService } from '../../SqlDataSource/SqlDataSourceService'; @@ -54,4 +55,13 @@ export class OutputLogsService { return id; } + + getOutputLogs(events: CbDatabaseOutputLogEvent[], editorState: ISqlEditorTabState) { + const dataSource = this.sqlDataSourceService.get(editorState.editorId); + + return events + .filter(event => event.contextId === dataSource?.executionContext?.id) + .map(event => event.messages) + .flat(); + } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts index 7e7d8bc2c0..c5fdd5c65b 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts @@ -8,21 +8,23 @@ import { action, computed, observable } from 'mobx'; import { useObservableRef } from '@cloudbeaver/core-blocks'; - -import type { IOutputLog } from './OutputLogsResource'; +import type { WsOutputLogInfo } from '@cloudbeaver/core-sdk'; export interface SqlOutputLogsPanelState { searchValue: string; setSearchValue: (value: string) => void; + logMessages: WsOutputLogInfo['message'][]; selectedLogTypes: OutputLogType[]; readonly resultValue: string; setSelectedLogTypes: (value: OutputLogType[]) => void; - readonly filteredLogs: IOutputLog[]; + readonly filteredLogs: WsOutputLogInfo[]; } export const OUTPUT_LOG_TYPES = ['Debug', 'Log', 'Info', 'Notice', 'Warning', 'Error'] as const; export type OutputLogType = (typeof OUTPUT_LOG_TYPES)[number]; -export const useOutputLogsPanelState = (outputLogs: IOutputLog[]) => useObservableRef( + +export const useOutputLogsPanelState = (outputLogs: WsOutputLogInfo[]) => + useObservableRef( () => ({ searchValue: '', selectedLogTypes: [...OUTPUT_LOG_TYPES], @@ -34,10 +36,10 @@ export const useOutputLogsPanelState = (outputLogs: IOutputLog[]) => useObservab }, get filteredLogs() { return outputLogs.filter(log => { - if (this.selectedLogTypes.length > 0 && !this.selectedLogTypes.includes(log.severity)) { + if (this.selectedLogTypes.length > 0 && !this.selectedLogTypes.includes(log?.severity as OutputLogType)) { return false; } - if (this.searchValue.length > 0 && !log.message.includes(this.searchValue)) { + if (this.searchValue.length > 0 && !log?.message?.includes(this.searchValue)) { return false; } return true; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultPanel.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultPanel.tsx index 171c33e94b..89b6caeb03 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultPanel.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultPanel.tsx @@ -63,7 +63,7 @@ export const SqlResultPanel = observer(function SqlResultPanel({ state, i if (state.outputLogsTab) { return styled(style)( - + , ); } From dacb08164ae93940d0c8e00c3931624589e5365e Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Thu, 14 Sep 2023 23:59:56 +0200 Subject: [PATCH 09/13] CB-3924: fixes after review --- .../src/queries/grid/asyncSqlExecuteQuery.gql | 3 +- .../DatabaseDataModel/IDatabaseDataOptions.ts | 1 + .../src/SqlEditorTabService.ts | 1 + .../src/ISqlEditorTabState.ts | 8 +- .../plugin-sql-editor/src/QueryDataSource.ts | 1 + .../src/SqlEditor/SqlEditor.tsx | 15 +-- .../src/SqlEditor/useSqlEditor.ts | 9 +- .../OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts | 7 ++ .../OutputLogs/OUTPUT_LOGS_TAB_ID.ts | 1 + .../OutputLogs/OutputLogTypesFilterMenu.m.css | 8 +- .../OutputLogs/OutputLogsEventHandler.ts | 4 +- .../OutputLogs/OutputLogsPanel.tsx | 2 +- .../OutputLogs/OutputLogsResource.ts | 41 +++++++- .../OutputLogs/OutputLogsService.ts | 94 +++++++++++++------ .../OutputLogs/useOutputLogsPanelState.ts | 24 +++-- .../src/SqlResultTabs/SqlQueryService.ts | 6 ++ .../src/SqlResultTabs/SqlResultTabsService.ts | 9 +- 17 files changed, 162 insertions(+), 72 deletions(-) create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_TAB_ID.ts diff --git a/webapp/packages/core-sdk/src/queries/grid/asyncSqlExecuteQuery.gql b/webapp/packages/core-sdk/src/queries/grid/asyncSqlExecuteQuery.gql index 76936e0765..7aabbc989e 100644 --- a/webapp/packages/core-sdk/src/queries/grid/asyncSqlExecuteQuery.gql +++ b/webapp/packages/core-sdk/src/queries/grid/asyncSqlExecuteQuery.gql @@ -5,6 +5,7 @@ mutation asyncSqlExecuteQuery( $resultId: ID $filter: SQLDataFilter $dataFormat: ResultDataFormat + $readLogs: Boolean ) { taskInfo: asyncSqlExecuteQuery( connectionId: $connectionId @@ -13,7 +14,7 @@ mutation asyncSqlExecuteQuery( resultId: $resultId filter: $filter dataFormat: $dataFormat - readLogs: true + readLogs: $readLogs ) { ...AsyncTaskInfo } diff --git a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataOptions.ts b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataOptions.ts index 2b6c946d3a..50f56e43e0 100644 --- a/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataOptions.ts +++ b/webapp/packages/plugin-data-viewer/src/DatabaseDataModel/IDatabaseDataOptions.ts @@ -14,4 +14,5 @@ export interface IDatabaseDataOptions { catalog?: string; whereFilter: string; constraints: SqlDataFilterConstraint[]; + readLogs?: boolean; } diff --git a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorTabService.ts b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorTabService.ts index 400126f0e3..f1fd0fe203 100644 --- a/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorTabService.ts +++ b/webapp/packages/plugin-sql-editor-navigation-tab/src/SqlEditorTabService.ts @@ -309,6 +309,7 @@ export class SqlEditorTabService extends Bootstrap { tab.handlerState.resultTabs = observable([]); tab.handlerState.executionPlanTabs = observable([]); tab.handlerState.statisticsTabs = observable([]); + tab.handlerState.outputLogsTab = undefined; return true; } diff --git a/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts b/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts index ef02de7e4c..30115d8533 100644 --- a/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts +++ b/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts @@ -5,6 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import type { IOutputLogType } from './SqlResultTabs/OutputLogs/useOutputLogsPanelState'; export interface IResultTab { tabId: string; @@ -41,10 +42,9 @@ export interface IExecutionPlanTab { options?: Record; } -export interface IOutputLogsTab { - tabId: string; - order: number; -} +export type IOutputLogsTab = ISqlEditorResultTab & { + selectedLogTypes: IOutputLogType[]; +}; export interface ISqlEditorTabState { editorId: string; diff --git a/webapp/packages/plugin-sql-editor/src/QueryDataSource.ts b/webapp/packages/plugin-sql-editor/src/QueryDataSource.ts index 461544edba..95355bff36 100644 --- a/webapp/packages/plugin-sql-editor/src/QueryDataSource.ts +++ b/webapp/packages/plugin-sql-editor/src/QueryDataSource.ts @@ -199,6 +199,7 @@ export class QueryDataSource(function SqlEditor({ state, c const sqlEditorModeService = useService(SqlEditorModeService); const data = useSqlEditor(state); const [modesState] = useState(() => new MetadataMap()); - useResource(SqlEditor, OutputLogsResource, undefined); useMemo(() => { modesState.sync(state.modeState); @@ -194,10 +185,6 @@ export const SqlEditor = observer(function SqlEditor({ state, c )} - {/*TODO update icon*/} - )} diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts b/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts index bc422eae2d..c49f58409c 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts @@ -25,6 +25,7 @@ import { SqlDialectInfoService } from '../SqlDialectInfoService'; import { SqlEditorService } from '../SqlEditorService'; import { ISQLScriptSegment, SQLParser } from '../SQLParser'; import { SqlExecutionPlanService } from '../SqlResultTabs/ExecutionPlan/SqlExecutionPlanService'; +import { OUTPUT_LOGS_TAB_ID } from '../SqlResultTabs/OutputLogs/OUTPUT_LOGS_TAB_ID'; import { OutputLogsService } from '../SqlResultTabs/OutputLogs/OutputLogsService'; import { SqlQueryService } from '../SqlResultTabs/SqlQueryService'; import { SqlResultTabsService } from '../SqlResultTabs/SqlResultTabsService'; @@ -316,9 +317,11 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { } if (this.state.tabs.length) { + const processableTabs = this.state.tabs.filter(tab => tab.id !== OUTPUT_LOGS_TAB_ID); + const result = await this.commonDialogService.open(ConfirmationDialog, { title: 'sql_editor_close_result_tabs_dialog_title', - message: `Do you want to close ${this.state.tabs.length} tabs before executing script?`, + message: `Do you want to close ${processableTabs.length} tabs before executing script?`, confirmActionText: 'ui_yes', extraStatus: 'no', }); @@ -329,8 +332,8 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { if (!state) { return; } - - this.sqlResultTabsService.removeResultTabs(this.state); + + this.sqlResultTabsService.removeResultTabs(this.state, [OUTPUT_LOGS_TAB_ID]); } else if (result === DialogueStateResult.Rejected) { return; } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts new file mode 100644 index 0000000000..17dc79f899 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts @@ -0,0 +1,7 @@ +import { createAction } from '@cloudbeaver/core-view'; + +export const ACTION_SHOW_OUTPUT_LOGS = createAction('action-show_output_logs', { + label: 'core_view_action_edit_label', + icon: 'table-icon', + tooltip: 'core_view_action_edit_tooltip', +}); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_TAB_ID.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_TAB_ID.ts new file mode 100644 index 0000000000..b88237948f --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_TAB_ID.ts @@ -0,0 +1 @@ +export const OUTPUT_LOGS_TAB_ID = 'output_logs'; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.m.css b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.m.css index 1000b127c5..83bd17790b 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.m.css +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.m.css @@ -1,10 +1,14 @@ .contextMenu { - height: 100%; padding: 0; + height: 24px; + width: 24px; + display: flex; + box-sizing: border-box; + align-items: center; + justify-content: center; & .icon { width: 16px; height: 100%; - padding: 0 8px; } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts index 8c37f52adf..e800c4a631 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsEventHandler.ts @@ -7,7 +7,7 @@ */ import { injectable } from '@cloudbeaver/core-di'; import { ISessionEvent, SessionEventSource, SessionEventTopic, TopicEventHandler } from '@cloudbeaver/core-root'; -import type { CbSessionLogEvent as ISessionLogEvent } from '@cloudbeaver/core-sdk'; +import type { CbDatabaseOutputLogEvent, CbSessionLogEvent as ISessionLogEvent } from '@cloudbeaver/core-sdk'; export { type ISessionLogEvent }; @@ -17,7 +17,7 @@ export class OutputLogsEventHandler extends TopicEventHandler(function SqlOutputLogsPanel({ sql const { data } = useResource(SqlOutputLogsPanel, OutputLogsResource, undefined); const outputLogs = outputLogsService.getOutputLogs(data, sqlEditorTabState); - const state = useOutputLogsPanelState(outputLogs); + const state = useOutputLogsPanelState(outputLogs, sqlEditorTabState); return (
diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts index 90455e0839..efd42e23b0 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts @@ -5,28 +5,59 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ +import { ConnectionExecutionContextResource } from '@cloudbeaver/core-connections'; import { injectable } from '@cloudbeaver/core-di'; import { ServerEventId } from '@cloudbeaver/core-root'; -import { CachedDataResource, CbDatabaseOutputLogEvent, GraphQLService } from '@cloudbeaver/core-sdk'; +import { CachedDataResource, CbDatabaseOutputLogEvent } from '@cloudbeaver/core-sdk'; import { OutputLogsEventHandler } from './OutputLogsEventHandler'; +export interface IOutputLog { + message: string; + severity: string; + contextId: string; + timestamp: number; +} + @injectable() -export class OutputLogsResource extends CachedDataResource { - constructor(sqlOutputLogsEventHandler: OutputLogsEventHandler, private readonly graphQLService: GraphQLService) { +export class OutputLogsResource extends CachedDataResource { + constructor( + sqlOutputLogsEventHandler: OutputLogsEventHandler, + private readonly connectionExecutionContextResource: ConnectionExecutionContextResource, + ) { super(() => []); sqlOutputLogsEventHandler.onEvent( ServerEventId.CbDatabaseOutputLogUpdated, (event: CbDatabaseOutputLogEvent) => { - this.setData((this.data || []).concat(event)); + this.collectMessagesFromEvent(event); }, undefined, this, ); + + // hack, we need to call this.use() to initialize resource at startup + this.use(undefined); + + this.connectionExecutionContextResource.onItemDelete.addHandler(key => { + this.setData(this.data.filter(log => log.contextId !== key)); + }); + } + + private collectMessagesFromEvent(event: CbDatabaseOutputLogEvent) { + const newLogs = event.messages.map(message => ({ + message: message.message, + severity: message.severity, + contextId: event.contextId, + timestamp: event.eventTimestamp, + })) as IOutputLog[]; + + const updatedData: IOutputLog[] = (this.data || []).concat(newLogs); + + this.setData(updatedData); } - protected async loader(): Promise { + protected async loader(): Promise { return this.data; } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts index 746be69314..85a477c3a2 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts @@ -6,62 +6,98 @@ * you may not use this file except in compliance with the License. */ import { injectable } from '@cloudbeaver/core-di'; -import type { CbDatabaseOutputLogEvent } from '@cloudbeaver/core-sdk'; +import { ActionService, MenuService } from '@cloudbeaver/core-view'; +import { DATA_CONTEXT_SQL_EDITOR_STATE } from '../../DATA_CONTEXT_SQL_EDITOR_STATE'; import type { ISqlEditorTabState } from '../../ISqlEditorTabState'; +import { ESqlDataSourceFeatures } from '../../SqlDataSource/ESqlDataSourceFeatures'; import { SqlDataSourceService } from '../../SqlDataSource/SqlDataSourceService'; +import { SQL_EDITOR_ACTIONS_MENU } from '../../SqlEditor/SQL_EDITOR_ACTIONS_MENU'; +import { ACTION_SHOW_OUTPUT_LOGS } from './ACTION_SHOW_OUTPUT_LOGS'; +import { OUTPUT_LOGS_TAB_ID } from './OUTPUT_LOGS_TAB_ID'; +import type { IOutputLog } from './OutputLogsResource'; +import { OUTPUT_LOG_TYPES } from './useOutputLogsPanelState'; @injectable() export class OutputLogsService { - constructor(private readonly sqlDataSourceService: SqlDataSourceService) {} + constructor( + private readonly sqlDataSourceService: SqlDataSourceService, + private readonly actionService: ActionService, + private readonly menuService: MenuService, + ) { + this.registerOutputLogsAction(); + } + + private registerOutputLogsAction() { + this.actionService.addHandler({ + id: 'output-logs-handler', + isActionApplicable: (context, action): boolean => { + const state = context.tryGet(DATA_CONTEXT_SQL_EDITOR_STATE); + + if (state && action === ACTION_SHOW_OUTPUT_LOGS) { + const sqlDataSource = this.sqlDataSourceService.get(state.editorId); + const isQuery = sqlDataSource?.hasFeature(ESqlDataSourceFeatures.query); + const isExecutable = sqlDataSource?.hasFeature(ESqlDataSourceFeatures.executable); + + if (isQuery && isExecutable) { + return true; + } + } + + return false; + }, + + handler: async (context, action) => { + const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE); + + if (action === ACTION_SHOW_OUTPUT_LOGS) { + this.showOutputLogs(state); + } + }, + }); + + this.menuService.addCreator({ + menus: [SQL_EDITOR_ACTIONS_MENU], + getItems: (context, items) => [...items, ACTION_SHOW_OUTPUT_LOGS], + }); + } async showOutputLogs(editorState: ISqlEditorTabState): Promise { - const tabId = this.createOutputLogsTab(editorState); - editorState.currentTabId = tabId; + this.createOutputLogsTab(editorState); + editorState.currentTabId = OUTPUT_LOGS_TAB_ID; } removeOutputLogsTab(state: ISqlEditorTabState, tabId: string): void { - const outputLogsTab = state.tabs.find(outputLogsTab => outputLogsTab.id === tabId); - - if (outputLogsTab) { - state.tabs.splice(state.tabs.indexOf(outputLogsTab), 1); + if (tabId === OUTPUT_LOGS_TAB_ID) { + state.outputLogsTab = undefined; } } private createOutputLogsTab(state: ISqlEditorTabState) { - const dataSource = this.sqlDataSourceService.get(state.editorId); - if (!dataSource) { - throw new Error('SQL Data Source is not provided'); - } - - const id = 'output-logs'; const order = Math.max(0, ...state.tabs.map(tab => tab.order + 1)); - if (state.tabs.find(tab => tab.id === id)) { + if (state.tabs.find(tab => tab.id === OUTPUT_LOGS_TAB_ID)) { return; } - state.outputLogsTab = { - tabId: id, - order, - }; + if (state.outputLogsTab) { + return; + } - state.tabs.push({ - id, + const tab = { + id: OUTPUT_LOGS_TAB_ID, name: 'Output', - icon: 'execution-plan-tab', // todo change icon + icon: 'table-icon', order, - }); + }; - return id; + state.outputLogsTab = { ...tab, selectedLogTypes: [...OUTPUT_LOG_TYPES] }; + state.tabs.push({ ...tab }); } - getOutputLogs(events: CbDatabaseOutputLogEvent[], editorState: ISqlEditorTabState) { + getOutputLogs(events: IOutputLog[], editorState: ISqlEditorTabState) { const dataSource = this.sqlDataSourceService.get(editorState.editorId); - return events - .filter(event => event.contextId === dataSource?.executionContext?.id) - .map(event => event.messages) - .flat(); + return events.filter(event => event.contextId === dataSource?.executionContext?.id); } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts index c5fdd5c65b..bb5c15a151 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts @@ -10,33 +10,39 @@ import { action, computed, observable } from 'mobx'; import { useObservableRef } from '@cloudbeaver/core-blocks'; import type { WsOutputLogInfo } from '@cloudbeaver/core-sdk'; +import type { ISqlEditorTabState } from '../../ISqlEditorTabState'; + export interface SqlOutputLogsPanelState { searchValue: string; setSearchValue: (value: string) => void; logMessages: WsOutputLogInfo['message'][]; - selectedLogTypes: OutputLogType[]; + selectedLogTypes: IOutputLogType[]; readonly resultValue: string; - setSelectedLogTypes: (value: OutputLogType[]) => void; + setSelectedLogTypes: (value: IOutputLogType[]) => void; readonly filteredLogs: WsOutputLogInfo[]; } export const OUTPUT_LOG_TYPES = ['Debug', 'Log', 'Info', 'Notice', 'Warning', 'Error'] as const; -export type OutputLogType = (typeof OUTPUT_LOG_TYPES)[number]; +export type IOutputLogType = (typeof OUTPUT_LOG_TYPES)[number]; -export const useOutputLogsPanelState = (outputLogs: WsOutputLogInfo[]) => +export const useOutputLogsPanelState = (outputLogs: WsOutputLogInfo[], sqlEditorTabState: ISqlEditorTabState) => useObservableRef( () => ({ searchValue: '', - selectedLogTypes: [...OUTPUT_LOG_TYPES], + get selectedLogTypes() { + return sqlEditorTabState.outputLogsTab?.selectedLogTypes || []; + }, setSearchValue(value: string) { this.searchValue = value; }, - setSelectedLogTypes(value: OutputLogType[]) { - this.selectedLogTypes = value; + setSelectedLogTypes(value: IOutputLogType[]) { + if (sqlEditorTabState.outputLogsTab) { + sqlEditorTabState.outputLogsTab.selectedLogTypes = value; + } }, get filteredLogs() { return outputLogs.filter(log => { - if (this.selectedLogTypes.length > 0 && !this.selectedLogTypes.includes(log?.severity as OutputLogType)) { + if (this.selectedLogTypes.length > 0 && !this.selectedLogTypes.includes(log?.severity as IOutputLogType)) { return false; } if (this.searchValue.length > 0 && !log?.message?.includes(this.searchValue)) { @@ -51,7 +57,7 @@ export const useOutputLogsPanelState = (outputLogs: WsOutputLogInfo[]) => }), { searchValue: observable.ref, - selectedLogTypes: observable.ref, + selectedLogTypes: computed, setSearchValue: action.bound, setSelectedLogTypes: action.bound, filteredLogs: computed, diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlQueryService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlQueryService.ts index 58ca739f4e..5599760742 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlQueryService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlQueryService.ts @@ -144,6 +144,8 @@ export class SqlQueryService { } const editable = this.dataViewerService.isDataEditable(connectionInfo); + const isOutputLogsTabOpened = !!editorState.outputLogsTab; + model .setAccess(editable ? DatabaseDataAccessMode.Default : DatabaseDataAccessMode.Readonly) .setOptions({ @@ -151,6 +153,7 @@ export class SqlQueryService { connectionKey, constraints: [], whereFilter: '', + readLogs: isOutputLogsTabOpened, }) .source.setExecutionContext(executionContext) .setSupportedDataFormats(connectionInfo.supportedDataFormats); @@ -218,6 +221,8 @@ export class SqlQueryService { statistics.modelId = model.id; const editable = this.dataViewerService.isDataEditable(connectionInfo); + const isOutputLogsTabOpened = !!editorState.outputLogsTab; + model .setAccess(editable ? DatabaseDataAccessMode.Default : DatabaseDataAccessMode.Readonly) .setOptions({ @@ -225,6 +230,7 @@ export class SqlQueryService { connectionKey, constraints: [], whereFilter: '', + readLogs: isOutputLogsTabOpened, }) .source.setExecutionContext(executionContext) .setSupportedDataFormats(connectionInfo.supportedDataFormats); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultTabsService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultTabsService.ts index 2c2a214b20..ea20a8f3fe 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultTabsService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultTabsService.ts @@ -11,6 +11,7 @@ import { injectable } from '@cloudbeaver/core-di'; import type { ISqlEditorResultTab, ISqlEditorTabState } from '../ISqlEditorTabState'; import { SqlExecutionPlanService } from './ExecutionPlan/SqlExecutionPlanService'; +import { OutputLogsService } from './OutputLogs/OutputLogsService'; import { SqlQueryResultService } from './SqlQueryResultService'; import { SqlQueryService } from './SqlQueryService'; @@ -20,6 +21,7 @@ export class SqlResultTabsService { private readonly sqlQueryService: SqlQueryService, private readonly sqlQueryResultService: SqlQueryResultService, private readonly sqlExecutionPlanService: SqlExecutionPlanService, + private readonly sqlOutputLogsService: OutputLogsService, ) { makeObservable(this, { removeResultTabs: action, @@ -62,8 +64,10 @@ export class SqlResultTabsService { return true; } - removeResultTabs(state: ISqlEditorTabState): void { - for (const tab of state.tabs.slice()) { + removeResultTabs(state: ISqlEditorTabState, excludedTabIds?: string[]): void { + const notExcludedTabs = state.tabs.filter(tab => !excludedTabIds?.includes(tab.id)); + + for (const tab of notExcludedTabs) { this.removeTab(state, tab); } } @@ -74,6 +78,7 @@ export class SqlResultTabsService { this.sqlQueryService.removeStatisticsTab(state, tab.id); this.sqlQueryResultService.removeResultTab(state, tab.id); this.sqlExecutionPlanService.removeExecutionPlanTab(state, tab.id); + this.sqlOutputLogsService.removeOutputLogsTab(state, tab.id); if (state.currentTabId === tab.id) { if (state.tabs.length > 0) { From b5a905be4635d712d47cb355c3b7ce120baf7be3 Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Fri, 15 Sep 2023 12:14:26 +0200 Subject: [PATCH 10/13] CB-3924: add output logs icon --- .../plugin-sql-editor/public/icons/sql_output_logs.svg | 1 + .../plugin-sql-editor/public/icons/sql_output_logs_m.svg | 1 + .../plugin-sql-editor/public/icons/sql_output_logs_sm.svg | 1 + .../src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts | 6 +++--- .../src/SqlResultTabs/OutputLogs/OutputLogsService.ts | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 webapp/packages/plugin-sql-editor/public/icons/sql_output_logs.svg create mode 100644 webapp/packages/plugin-sql-editor/public/icons/sql_output_logs_m.svg create mode 100644 webapp/packages/plugin-sql-editor/public/icons/sql_output_logs_sm.svg diff --git a/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs.svg b/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs.svg new file mode 100644 index 0000000000..bc9e4420c2 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs_m.svg b/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs_m.svg new file mode 100644 index 0000000000..d4d1f74ad4 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs_m.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs_sm.svg b/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs_sm.svg new file mode 100644 index 0000000000..bda167f39f --- /dev/null +++ b/webapp/packages/plugin-sql-editor/public/icons/sql_output_logs_sm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts index 17dc79f899..ffe85a38f9 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/ACTION_SHOW_OUTPUT_LOGS.ts @@ -1,7 +1,7 @@ import { createAction } from '@cloudbeaver/core-view'; export const ACTION_SHOW_OUTPUT_LOGS = createAction('action-show_output_logs', { - label: 'core_view_action_edit_label', - icon: 'table-icon', - tooltip: 'core_view_action_edit_tooltip', + label: 'sql_editor_output_logs_button_tooltip', + icon: '/icons/sql_output_logs.svg', + tooltip: 'sql_editor_output_logs_button_tooltip', }); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts index 85a477c3a2..e2e1e6e7c5 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts @@ -87,7 +87,7 @@ export class OutputLogsService { const tab = { id: OUTPUT_LOGS_TAB_ID, name: 'Output', - icon: 'table-icon', + icon: '/icons/sql_output_logs.svg', order, }; From 2f27c35921bc227b9469c92d9e2dc9274dcc4117 Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Fri, 15 Sep 2023 17:35:35 +0200 Subject: [PATCH 11/13] CB-3924: fixes after review --- .../src/FormControls/InputField.m.css | 9 ++ .../src/FormControls/InputField.tsx | 5 +- .../plugin-codemirror6/src/Editor.tsx | 37 +++--- .../src/useEditorDefaultExtensions.ts | 35 +++-- .../src/ISqlEditorTabState.ts | 6 +- .../plugin-sql-editor/src/MenuBootstrap.ts | 11 -- .../src/SqlEditor/ISQLEditorData.ts | 1 - .../src/SqlEditor/useSqlEditor.ts | 7 +- .../OutputLogs/IOutputLogTypes.ts | 2 + .../OutputLogs/OutputFilterMenuBootstrap.ts | 64 --------- .../OutputLogs/OutputLogsPanel.m.css | 13 -- .../OutputLogs/OutputLogsPanel.tsx | 12 +- .../OutputLogs/OutputLogsResource.ts | 3 +- .../OutputLogs/OutputLogsService.ts | 56 +------- .../OutputLogs/OutputLogsToolbar.m.css | 18 +-- .../OutputLogs/OutputLogsToolbar.tsx | 25 ++-- .../OutputLogs/OutputMenuBootstrap.ts | 123 ++++++++++++++++++ .../OutputLogs/useOutputLogsPanelState.ts | 29 ++--- .../src/SqlResultTabs/SqlResultTabsService.ts | 7 +- .../plugin-sql-editor/src/manifest.ts | 4 +- 20 files changed, 229 insertions(+), 238 deletions(-) create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/IOutputLogTypes.ts delete mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts delete mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.m.css create mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputMenuBootstrap.ts diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.m.css b/webapp/packages/core-blocks/src/FormControls/InputField.m.css index 76d9ae3b4f..772a6ac4d5 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.m.css +++ b/webapp/packages/core-blocks/src/FormControls/InputField.m.css @@ -29,6 +29,15 @@ height: 100%; } } + +.customIconContainer { + composes: iconContainer; + right: 4px; + width: 24px; + height: 24px; + cursor: auto; +} + .input[disabled] + .iconContainer { cursor: auto; opacity: 0.8; diff --git a/webapp/packages/core-blocks/src/FormControls/InputField.tsx b/webapp/packages/core-blocks/src/FormControls/InputField.tsx index a456043934..ccf5d516d5 100644 --- a/webapp/packages/core-blocks/src/FormControls/InputField.tsx +++ b/webapp/packages/core-blocks/src/FormControls/InputField.tsx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. */ import { observer } from 'mobx-react-lite'; -import { forwardRef, useCallback, useContext, useLayoutEffect, useRef, useState } from 'react'; +import React, { forwardRef, useCallback, useContext, useLayoutEffect, useRef, useState } from 'react'; import styled, { use } from 'reshadow'; import type { ComponentStyle } from '@cloudbeaver/core-theming'; @@ -41,6 +41,7 @@ type BaseProps = Omit, 'onChange' | style?: ComponentStyle; canShowPassword?: boolean; onCustomCopy?: () => void; + icon?: React.ReactElement; }; type ControlledProps = BaseProps & { @@ -90,6 +91,7 @@ export const InputField: InputFieldType = observer( canShowPassword = true, onChange, onCustomCopy, + icon, ...rest }: ControlledProps | ObjectProps, ref, @@ -195,6 +197,7 @@ export const InputField: InputFieldType = observer(
)} + {icon &&
{icon}
}
{(description || passwordType) && (
diff --git a/webapp/packages/plugin-codemirror6/src/Editor.tsx b/webapp/packages/plugin-codemirror6/src/Editor.tsx index 5dc732a7e2..10be8ade09 100644 --- a/webapp/packages/plugin-codemirror6/src/Editor.tsx +++ b/webapp/packages/plugin-codemirror6/src/Editor.tsx @@ -43,27 +43,24 @@ export const Editor = observer( ) { extensions = useCodemirrorExtensions(extensions); - const filteredDefaultExtensionsFlagsFromProps = Object.fromEntries( - Object.entries({ - lineNumbers, - tooltips, - highlightSpecialChars, - syntaxHighlighting, - bracketMatching, - dropCursor, - crosshairCursor, - foldGutter, - highlightActiveLineGutter, - highlightSelectionMatches, - highlightActiveLine, - indentOnInput, - rectangularSelection, - keymap, - lineWrapping, - }).filter(([, value]) => value !== undefined), - ); - const defaultExtensions = useEditorDefaultExtensions(filteredDefaultExtensionsFlagsFromProps); + const defaultExtensions = useEditorDefaultExtensions({ + lineNumbers, + tooltips, + highlightSpecialChars, + syntaxHighlighting, + bracketMatching, + dropCursor, + crosshairCursor, + foldGutter, + highlightActiveLineGutter, + highlightSelectionMatches, + highlightActiveLine, + indentOnInput, + rectangularSelection, + keymap, + lineWrapping, + }); extensions.set(...defaultExtensions); diff --git a/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts b/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts index 2df2369438..8830f64967 100644 --- a/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts +++ b/webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts @@ -22,9 +22,9 @@ import { tooltips, } from '@codemirror/view'; import { classHighlighter } from '@lezer/highlight'; -import { useMemo } from 'react'; +import { useRef } from 'react'; -import { clsx, GlobalConstants } from '@cloudbeaver/core-utils'; +import { clsx, GlobalConstants, isObjectsEqual } from '@cloudbeaver/core-utils'; // @TODO allow to configure bindings outside of the component const DEFAULT_KEY_MAP = defaultKeymap.filter(binding => binding.mac !== 'Ctrl-f' && binding.key !== 'Mod-Enter'); @@ -111,14 +111,25 @@ const DEFAULT_EXTENSIONS_COMPARTMENT = new Compartment(); /** Provides the necessary extensions to establish a basic editor */ export function useEditorDefaultExtensions(options?: IDefaultExtensions): [Compartment, Extension] { - return useMemo(() => { - const extensions = Object.entries({ ...defaultExtensionsFlags, ...options } || {}) - .filter(([, isEnabled]) => isEnabled) - .map(([key]) => { - const extensionFunction = extensionMap[key as keyof typeof extensionMap]; - return extensionFunction?.(); - }) - .filter(Boolean); - return [DEFAULT_EXTENSIONS_COMPARTMENT, extensions]; - }, [options]); + const previousOptions = useRef(options); + const isOptionsChanged = !isObjectsEqual(options, previousOptions.current); + const extensions = useRef<[Compartment, Extension] | null>(null); + + if (isOptionsChanged || extensions.current === null) { + previousOptions.current = options; + extensions.current = createExtensions(options); + } + + return extensions.current; +} + +function createExtensions(options?: IDefaultExtensions): [Compartment, Extension] { + const extensions = Object.entries(defaultExtensionsFlags) + .filter(([key, isEnabled]) => options?.[key as keyof typeof options] ?? isEnabled) + .map(([key]) => { + const extensionFunction = extensionMap[key as keyof typeof extensionMap]; + return extensionFunction?.(); + }) + .filter(Boolean); + return [DEFAULT_EXTENSIONS_COMPARTMENT, extensions]; } diff --git a/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts b/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts index 30115d8533..a117d81396 100644 --- a/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts +++ b/webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts @@ -5,7 +5,7 @@ * Licensed under the Apache License, Version 2.0. * you may not use this file except in compliance with the License. */ -import type { IOutputLogType } from './SqlResultTabs/OutputLogs/useOutputLogsPanelState'; +import type { IOutputLogType } from './SqlResultTabs/OutputLogs/IOutputLogTypes'; export interface IResultTab { tabId: string; @@ -42,9 +42,9 @@ export interface IExecutionPlanTab { options?: Record; } -export type IOutputLogsTab = ISqlEditorResultTab & { +export interface IOutputLogsTab extends ISqlEditorResultTab { selectedLogTypes: IOutputLogType[]; -}; +} export interface ISqlEditorTabState { editorId: string; diff --git a/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts index cb7c23f74a..a99f4a8511 100644 --- a/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts +++ b/webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts @@ -140,13 +140,6 @@ export class MenuBootstrap extends Bootstrap { handler: this.sqlEditorActionHandler.bind(this), }); - this.keyBindingService.addKeyBindingHandler({ - id: 'sql-editor-show-output', - binding: KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT, - isBindingApplicable: (contexts, action) => action === ACTION_SQL_EDITOR_SHOW_OUTPUT, - handler: this.sqlEditorActionHandler.bind(this), - }); - // this.menuService.addCreator({ // isApplicable: context => ( // context.tryGet(DATA_CONTEXT_SQL_EDITOR_DATA) !== undefined @@ -192,10 +185,6 @@ export class MenuBootstrap extends Bootstrap { case ACTION_SQL_EDITOR_SHOW_EXECUTION_PLAN: data.showExecutionPlan(); break; - case ACTION_SQL_EDITOR_SHOW_OUTPUT: - // TODO change it to show output - data.showOutputLogs(); - break; } } diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/ISQLEditorData.ts b/webapp/packages/plugin-sql-editor/src/SqlEditor/ISQLEditorData.ts index d8eeaf83f3..20b99daca7 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/ISQLEditorData.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/ISQLEditorData.ts @@ -56,7 +56,6 @@ export interface ISQLEditorData { executeQuery(): Promise; executeQueryNewTab(): Promise; showExecutionPlan(): Promise; - showOutputLogs(): Promise; executeScript(): Promise; switchEditing(): Promise; getHintProposals(position: number, simple: boolean): Promise; diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts b/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts index c49f58409c..7234ee2131 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlEditor/useSqlEditor.ts @@ -301,10 +301,6 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { } catch {} }, - async showOutputLogs(): Promise { - sqlOutputLogsService.showOutputLogs(this.state); - }, - async switchEditing(): Promise { this.dataSource?.setEditing(!this.dataSource.isEditing()); }, @@ -332,7 +328,7 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { if (!state) { return; } - + this.sqlResultTabsService.removeResultTabs(this.state, [OUTPUT_LOGS_TAB_ID]); } else if (result === DialogueStateResult.Rejected) { return; @@ -474,7 +470,6 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData { executeQuery: action.bound, executeQueryNewTab: action.bound, showExecutionPlan: action.bound, - showOutputLogs: action.bound, executeScript: action.bound, switchEditing: action.bound, dialect: computed, diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/IOutputLogTypes.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/IOutputLogTypes.ts new file mode 100644 index 0000000000..5078ee9ff3 --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/IOutputLogTypes.ts @@ -0,0 +1,2 @@ +export const OUTPUT_LOG_TYPES = ['Debug', 'Log', 'Info', 'Notice', 'Warning', 'Error'] as const; +export type IOutputLogType = (typeof OUTPUT_LOG_TYPES)[number]; diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts deleted file mode 100644 index c0922d428b..0000000000 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 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 { MenuCheckboxItem, MenuService } from '@cloudbeaver/core-view'; - -import { OUTPUT_LOGS_FILTER_MENU } from './OUTPUT_LOGS_FILTER_MENU'; -import { OUTPUT_LOGS_PANEL_STATE } from './OUTPUT_LOGS_PANEL_STATE'; -import { OUTPUT_LOG_TYPES } from './useOutputLogsPanelState'; - -@injectable() -export class OutputFilterMenuBootstrap extends Bootstrap { - constructor(private readonly menuService: MenuService) { - super(); - } - - register(): void | Promise { - this.menuService.addCreator({ - menus: [OUTPUT_LOGS_FILTER_MENU], - isApplicable: context => true, - getItems: (context, items) => [...items], - }); - - this.menuService.addCreator({ - menus: [OUTPUT_LOGS_FILTER_MENU], - getItems: context => { - const state = context.get(OUTPUT_LOGS_PANEL_STATE); - const items = []; - - for (const logType of OUTPUT_LOG_TYPES) { - items.push( - new MenuCheckboxItem( - { - id: logType, - label: logType, - tooltip: logType, - }, - { - onSelect: () => { - if (state.selectedLogTypes.includes(logType)) { - state.setSelectedLogTypes(state.selectedLogTypes.filter(type => type !== logType)); - return; - } - state.setSelectedLogTypes([...state.selectedLogTypes, logType]); - }, - }, - { - isChecked: () => state.selectedLogTypes.includes(logType), - }, - ), - ); - } - - return items; - }, - }); - } - - async load(): Promise {} -} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.m.css b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.m.css deleted file mode 100644 index 985fa8272d..0000000000 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.m.css +++ /dev/null @@ -1,13 +0,0 @@ -.container { - composes: theme-background-secondary from global; - height: 100%; - display: flex; - flex-direction: column; - width: 100%; -} - -.editorContainer { - padding: 8px; - overflow: auto; - height: 100%; -} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx index e17697b425..61fd377c2e 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsPanel.tsx @@ -7,12 +7,11 @@ */ import { observer } from 'mobx-react-lite'; -import { s, useResource, useS } from '@cloudbeaver/core-blocks'; +import { Container, Group, s, useResource, useS } from '@cloudbeaver/core-blocks'; import { useService } from '@cloudbeaver/core-di'; import { EditorLoader } from '@cloudbeaver/plugin-codemirror6'; import type { ISqlEditorTabState } from '../../ISqlEditorTabState'; -import style from './OutputLogsPanel.m.css'; import { OutputLogsResource } from './OutputLogsResource'; import { OutputLogsService } from './OutputLogsService'; import { OutputLogsToolbar } from './OutputLogsToolbar'; @@ -23,7 +22,6 @@ interface Props { } export const OutputLogsPanel = observer(function SqlOutputLogsPanel({ sqlEditorTabState }) { - const styles = useS(style); const outputLogsService = useService(OutputLogsService); const { data } = useResource(SqlOutputLogsPanel, OutputLogsResource, undefined); const outputLogs = outputLogsService.getOutputLogs(data, sqlEditorTabState); @@ -31,11 +29,11 @@ export const OutputLogsPanel = observer(function SqlOutputLogsPanel({ sql const state = useOutputLogsPanelState(outputLogs, sqlEditorTabState); return ( -
+ -
+ {data && } -
-
+ + ); }); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts index efd42e23b0..4a03614823 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsResource.ts @@ -10,11 +10,12 @@ import { injectable } from '@cloudbeaver/core-di'; import { ServerEventId } from '@cloudbeaver/core-root'; import { CachedDataResource, CbDatabaseOutputLogEvent } from '@cloudbeaver/core-sdk'; +import type { IOutputLogType } from './IOutputLogTypes'; import { OutputLogsEventHandler } from './OutputLogsEventHandler'; export interface IOutputLog { message: string; - severity: string; + severity: IOutputLogType; contextId: string; timestamp: number; } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts index e2e1e6e7c5..9918daaa0d 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts @@ -6,60 +6,20 @@ * you may not use this file except in compliance with the License. */ import { injectable } from '@cloudbeaver/core-di'; -import { ActionService, MenuService } from '@cloudbeaver/core-view'; -import { DATA_CONTEXT_SQL_EDITOR_STATE } from '../../DATA_CONTEXT_SQL_EDITOR_STATE'; import type { ISqlEditorTabState } from '../../ISqlEditorTabState'; -import { ESqlDataSourceFeatures } from '../../SqlDataSource/ESqlDataSourceFeatures'; import { SqlDataSourceService } from '../../SqlDataSource/SqlDataSourceService'; -import { SQL_EDITOR_ACTIONS_MENU } from '../../SqlEditor/SQL_EDITOR_ACTIONS_MENU'; -import { ACTION_SHOW_OUTPUT_LOGS } from './ACTION_SHOW_OUTPUT_LOGS'; +import { IOutputLogType, OUTPUT_LOG_TYPES } from './IOutputLogTypes'; import { OUTPUT_LOGS_TAB_ID } from './OUTPUT_LOGS_TAB_ID'; import type { IOutputLog } from './OutputLogsResource'; -import { OUTPUT_LOG_TYPES } from './useOutputLogsPanelState'; @injectable() export class OutputLogsService { - constructor( - private readonly sqlDataSourceService: SqlDataSourceService, - private readonly actionService: ActionService, - private readonly menuService: MenuService, - ) { - this.registerOutputLogsAction(); - } - - private registerOutputLogsAction() { - this.actionService.addHandler({ - id: 'output-logs-handler', - isActionApplicable: (context, action): boolean => { - const state = context.tryGet(DATA_CONTEXT_SQL_EDITOR_STATE); - - if (state && action === ACTION_SHOW_OUTPUT_LOGS) { - const sqlDataSource = this.sqlDataSourceService.get(state.editorId); - const isQuery = sqlDataSource?.hasFeature(ESqlDataSourceFeatures.query); - const isExecutable = sqlDataSource?.hasFeature(ESqlDataSourceFeatures.executable); - - if (isQuery && isExecutable) { - return true; - } - } - - return false; - }, - - handler: async (context, action) => { - const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE); - - if (action === ACTION_SHOW_OUTPUT_LOGS) { - this.showOutputLogs(state); - } - }, - }); - - this.menuService.addCreator({ - menus: [SQL_EDITOR_ACTIONS_MENU], - getItems: (context, items) => [...items, ACTION_SHOW_OUTPUT_LOGS], - }); + constructor(private readonly sqlDataSourceService: SqlDataSourceService) {} + setSelectedLogTypes(state: ISqlEditorTabState, logType: IOutputLogType) { + if (state.outputLogsTab) { + state.outputLogsTab.selectedLogTypes = state.outputLogsTab.selectedLogTypes.filter(type => type !== logType); + } } async showOutputLogs(editorState: ISqlEditorTabState): Promise { @@ -80,10 +40,6 @@ export class OutputLogsService { return; } - if (state.outputLogsTab) { - return; - } - const tab = { id: OUTPUT_LOGS_TAB_ID, name: 'Output', diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.m.css b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.m.css index c02dccdbb5..e5faba5c7a 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.m.css +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.m.css @@ -1,16 +1,6 @@ -.container { +.searchIcon { + width: 24px; + height: 24px; display: flex; - align-content: center; - justify-content: center; - align-items: center; - padding: 8px 8px 0 8px; - gap: 8px; - - & > .inlineEditor { - height: 24px; - } -} - -.inlineEditor { - composes: theme-background-surface theme-text-on-surface from global; + border-radius: var(--theme-menu-bar-small-action-radius); } diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx index f805071b97..c55048b365 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsToolbar.tsx @@ -8,8 +8,7 @@ import { observer } from 'mobx-react-lite'; import React from 'react'; -import { s, useS, useTranslate } from '@cloudbeaver/core-blocks'; -import { InlineEditor } from '@cloudbeaver/core-ui'; +import { Container, Icon, InputField, s, useS, useTranslate } from '@cloudbeaver/core-blocks'; import style from './OutputLogsToolbar.m.css'; import { OutputLogsFilterMenu } from './OutputLogTypesFilterMenu'; @@ -24,17 +23,21 @@ export const OutputLogsToolbar = observer(function SqlOutputLogsToolbar({ const translate = useTranslate(); return ( -
- + + +
+ } + fill + onChange={value => state.setSearchValue(value.toString())} /> - -
+ + + + ); }); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputMenuBootstrap.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputMenuBootstrap.ts new file mode 100644 index 0000000000..0f898e38dd --- /dev/null +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputMenuBootstrap.ts @@ -0,0 +1,123 @@ +/* + * CloudBeaver - Cloud Database Manager + * Copyright (C) 2020-2023 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 { ActionService, KeyBindingService, MenuCheckboxItem, MenuService } from '@cloudbeaver/core-view'; + +import { ACTION_SQL_EDITOR_SHOW_OUTPUT } from '../../actions/ACTION_SQL_EDITOR_SHOW_OUTPUT'; +import { KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT } from '../../actions/bindings/KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT'; +import { DATA_CONTEXT_SQL_EDITOR_STATE } from '../../DATA_CONTEXT_SQL_EDITOR_STATE'; +import { ESqlDataSourceFeatures } from '../../SqlDataSource/ESqlDataSourceFeatures'; +import { SqlDataSourceService } from '../../SqlDataSource/SqlDataSourceService'; +import { SQL_EDITOR_ACTIONS_MENU } from '../../SqlEditor/SQL_EDITOR_ACTIONS_MENU'; +import { ACTION_SHOW_OUTPUT_LOGS } from './ACTION_SHOW_OUTPUT_LOGS'; +import { OUTPUT_LOG_TYPES } from './IOutputLogTypes'; +import { OUTPUT_LOGS_FILTER_MENU } from './OUTPUT_LOGS_FILTER_MENU'; +import { OutputLogsService } from './OutputLogsService'; + +@injectable() +export class OutputMenuBootstrap extends Bootstrap { + constructor( + private readonly actionService: ActionService, + private readonly menuService: MenuService, + private readonly outputLogsService: OutputLogsService, + private readonly sqlDataSourceService: SqlDataSourceService, + private readonly keyBindingService: KeyBindingService, + ) { + super(); + } + + register(): void | Promise { + this.menuService.addCreator({ + menus: [OUTPUT_LOGS_FILTER_MENU], + getItems: context => { + const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE); + const outputLogsTabState = state.outputLogsTab; + const items = []; + + for (const logType of OUTPUT_LOG_TYPES) { + items.push( + new MenuCheckboxItem( + { + id: logType, + label: logType, + tooltip: logType, + }, + { + onSelect: () => { + if (outputLogsTabState?.selectedLogTypes) { + if (outputLogsTabState.selectedLogTypes.includes(logType)) { + outputLogsTabState.selectedLogTypes = outputLogsTabState.selectedLogTypes.filter(type => type !== logType); + return; + } + outputLogsTabState.selectedLogTypes = [...outputLogsTabState.selectedLogTypes, logType]; + } + }, + }, + { + isChecked: () => !!outputLogsTabState?.selectedLogTypes.includes(logType), + }, + ), + ); + } + + return items; + }, + }); + + this.registerOutputLogsAction(); + } + + private registerOutputLogsAction() { + this.actionService.addHandler({ + id: 'output-logs-handler', + isActionApplicable: (context, action): boolean => { + const state = context.tryGet(DATA_CONTEXT_SQL_EDITOR_STATE); + + if (state && action === ACTION_SHOW_OUTPUT_LOGS) { + const sqlDataSource = this.sqlDataSourceService.get(state.editorId); + const isQuery = sqlDataSource?.hasFeature(ESqlDataSourceFeatures.query); + const isExecutable = sqlDataSource?.hasFeature(ESqlDataSourceFeatures.executable); + + if (isQuery && isExecutable) { + return true; + } + } + + return false; + }, + + handler: async (context, action) => { + const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE); + + if (action === ACTION_SHOW_OUTPUT_LOGS) { + this.outputLogsService.showOutputLogs(state); + } + }, + }); + + this.menuService.addCreator({ + menus: [SQL_EDITOR_ACTIONS_MENU], + getItems: (context, items) => [...items, ACTION_SHOW_OUTPUT_LOGS], + }); + + this.keyBindingService.addKeyBindingHandler({ + id: 'sql-editor-show-output', + binding: KEY_BINDING_SQL_EDITOR_SHOW_OUTPUT, + isBindingApplicable: (contexts, action) => action === ACTION_SQL_EDITOR_SHOW_OUTPUT, + handler: (context, action) => { + const state = context.get(DATA_CONTEXT_SQL_EDITOR_STATE); + + if (action === ACTION_SQL_EDITOR_SHOW_OUTPUT) { + this.outputLogsService.showOutputLogs(state); + } + }, + }); + } + + async load(): Promise {} +} diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts index bb5c15a151..f2cfa2e591 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/useOutputLogsPanelState.ts @@ -11,41 +11,34 @@ import { useObservableRef } from '@cloudbeaver/core-blocks'; import type { WsOutputLogInfo } from '@cloudbeaver/core-sdk'; import type { ISqlEditorTabState } from '../../ISqlEditorTabState'; +import type { IOutputLog } from './OutputLogsResource'; export interface SqlOutputLogsPanelState { searchValue: string; setSearchValue: (value: string) => void; logMessages: WsOutputLogInfo['message'][]; - selectedLogTypes: IOutputLogType[]; readonly resultValue: string; - setSelectedLogTypes: (value: IOutputLogType[]) => void; readonly filteredLogs: WsOutputLogInfo[]; } - -export const OUTPUT_LOG_TYPES = ['Debug', 'Log', 'Info', 'Notice', 'Warning', 'Error'] as const; -export type IOutputLogType = (typeof OUTPUT_LOG_TYPES)[number]; - -export const useOutputLogsPanelState = (outputLogs: WsOutputLogInfo[], sqlEditorTabState: ISqlEditorTabState) => +export const useOutputLogsPanelState = (outputLogs: IOutputLog[], sqlEditorTabState: ISqlEditorTabState) => useObservableRef( () => ({ searchValue: '', - get selectedLogTypes() { - return sqlEditorTabState.outputLogsTab?.selectedLogTypes || []; - }, setSearchValue(value: string) { this.searchValue = value; }, - setSelectedLogTypes(value: IOutputLogType[]) { - if (sqlEditorTabState.outputLogsTab) { - sqlEditorTabState.outputLogsTab.selectedLogTypes = value; - } - }, get filteredLogs() { + const selectedLogTypes = sqlEditorTabState.outputLogsTab?.selectedLogTypes; + + if (!selectedLogTypes?.length) { + return []; + } + return outputLogs.filter(log => { - if (this.selectedLogTypes.length > 0 && !this.selectedLogTypes.includes(log?.severity as IOutputLogType)) { + if (!selectedLogTypes.includes(log.severity)) { return false; } - if (this.searchValue.length > 0 && !log?.message?.includes(this.searchValue)) { + if (this.searchValue.length > 0 && !log.message?.includes(this.searchValue)) { return false; } return true; @@ -57,9 +50,7 @@ export const useOutputLogsPanelState = (outputLogs: WsOutputLogInfo[], sqlEditor }), { searchValue: observable.ref, - selectedLogTypes: computed, setSearchValue: action.bound, - setSelectedLogTypes: action.bound, filteredLogs: computed, resultValue: computed, }, diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultTabsService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultTabsService.ts index ea20a8f3fe..138c7f9806 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultTabsService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/SqlResultTabsService.ts @@ -65,9 +65,10 @@ export class SqlResultTabsService { } removeResultTabs(state: ISqlEditorTabState, excludedTabIds?: string[]): void { - const notExcludedTabs = state.tabs.filter(tab => !excludedTabIds?.includes(tab.id)); - - for (const tab of notExcludedTabs) { + for (const tab of state.tabs) { + if (excludedTabIds?.includes(tab.id)) { + continue; + } this.removeTab(state, tab); } } diff --git a/webapp/packages/plugin-sql-editor/src/manifest.ts b/webapp/packages/plugin-sql-editor/src/manifest.ts index 6b47f50f91..25de7423c0 100644 --- a/webapp/packages/plugin-sql-editor/src/manifest.ts +++ b/webapp/packages/plugin-sql-editor/src/manifest.ts @@ -17,7 +17,7 @@ import { SqlEditorService } from './SqlEditorService'; import { SqlEditorSettingsService } from './SqlEditorSettingsService'; import { SqlEditorView } from './SqlEditorView'; import { SqlExecutionPlanService } from './SqlResultTabs/ExecutionPlan/SqlExecutionPlanService'; -import { OutputFilterMenuBootstrap } from './SqlResultTabs/OutputLogs/OutputFilterMenuBootstrap'; +import { OutputMenuBootstrap } from './SqlResultTabs/OutputLogs/OutputMenuBootstrap'; import { OutputLogsEventHandler } from './SqlResultTabs/OutputLogs/OutputLogsEventHandler'; import { OutputLogsResource } from './SqlResultTabs/OutputLogs/OutputLogsResource'; import { OutputLogsService } from './SqlResultTabs/OutputLogs/OutputLogsService'; @@ -47,6 +47,6 @@ export const sqlEditorPluginManifest: PluginManifest = { OutputLogsEventHandler, OutputLogsResource, OutputLogsService, - OutputFilterMenuBootstrap, + OutputMenuBootstrap, ], }; From 1921ad31059e8a5afde7a246819ef867ea1695ab Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Fri, 15 Sep 2023 17:46:55 +0200 Subject: [PATCH 12/13] CB-3924: fixes after review --- .../OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts | 12 ------------ .../OutputLogs/OutputLogTypesFilterMenu.tsx | 2 -- 2 files changed, 14 deletions(-) delete mode 100644 webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts deleted file mode 100644 index 40309fa33c..0000000000 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OUTPUT_LOGS_PANEL_STATE.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * CloudBeaver - Cloud Database Manager - * Copyright (C) 2020-2023 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 { SqlOutputLogsPanelState } from './useOutputLogsPanelState'; - -export const OUTPUT_LOGS_PANEL_STATE = createDataContext('output-logs-panel-state'); diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx index 2175be6a73..f36865afee 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogTypesFilterMenu.tsx @@ -12,7 +12,6 @@ import { ContextMenu } from '@cloudbeaver/core-ui'; import { useMenu } from '@cloudbeaver/core-view'; import { OUTPUT_LOGS_FILTER_MENU } from './OUTPUT_LOGS_FILTER_MENU'; -import { OUTPUT_LOGS_PANEL_STATE } from './OUTPUT_LOGS_PANEL_STATE'; import style from './OutputLogTypesFilterMenu.m.css'; import type { SqlOutputLogsPanelState } from './useOutputLogsPanelState'; @@ -25,7 +24,6 @@ export const OutputLogsFilterMenu = observer(function OutputLogTypesFilte const menu = useMenu({ menu: OUTPUT_LOGS_FILTER_MENU, }); - menu.context.set(OUTPUT_LOGS_PANEL_STATE, state); return ( From b59484795f77eccd50cd9fa3a5014b57672dd75f Mon Sep 17 00:00:00 2001 From: Dmitry Osipov Date: Fri, 15 Sep 2023 18:03:33 +0200 Subject: [PATCH 13/13] CB-3924: fixes after review --- .../src/SqlResultTabs/OutputLogs/OutputLogsService.ts | 7 +------ webapp/packages/plugin-sql-editor/src/locales/en.ts | 1 + webapp/packages/plugin-sql-editor/src/locales/it.ts | 1 + webapp/packages/plugin-sql-editor/src/locales/ru.ts | 1 + webapp/packages/plugin-sql-editor/src/locales/zh.ts | 1 + 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts index 9918daaa0d..f518517bf7 100644 --- a/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts +++ b/webapp/packages/plugin-sql-editor/src/SqlResultTabs/OutputLogs/OutputLogsService.ts @@ -9,18 +9,13 @@ import { injectable } from '@cloudbeaver/core-di'; import type { ISqlEditorTabState } from '../../ISqlEditorTabState'; import { SqlDataSourceService } from '../../SqlDataSource/SqlDataSourceService'; -import { IOutputLogType, OUTPUT_LOG_TYPES } from './IOutputLogTypes'; +import { OUTPUT_LOG_TYPES } from './IOutputLogTypes'; import { OUTPUT_LOGS_TAB_ID } from './OUTPUT_LOGS_TAB_ID'; import type { IOutputLog } from './OutputLogsResource'; @injectable() export class OutputLogsService { constructor(private readonly sqlDataSourceService: SqlDataSourceService) {} - setSelectedLogTypes(state: ISqlEditorTabState, logType: IOutputLogType) { - if (state.outputLogsTab) { - state.outputLogsTab.selectedLogTypes = state.outputLogsTab.selectedLogTypes.filter(type => type !== logType); - } - } async showOutputLogs(editorState: ISqlEditorTabState): Promise { this.createOutputLogsTab(editorState); diff --git a/webapp/packages/plugin-sql-editor/src/locales/en.ts b/webapp/packages/plugin-sql-editor/src/locales/en.ts index 1cdf95433a..54308fd446 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/en.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/en.ts @@ -8,6 +8,7 @@ export default [ ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', 'Explain execution plan (Shift + Ctrl + E)'], ['sql_editor_output_logs_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_tab_title', 'Output'], ['sql_editor_output_logs_input_placeholder', 'Enter a part of a message to search for here'], ['sql_editor_sql_execution_button_tooltip', 'Execute SQL Statement (Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', 'Execute SQL Statement in new tab (Ctrl + \\)(Shift + Ctrl + Enter)'], diff --git a/webapp/packages/plugin-sql-editor/src/locales/it.ts b/webapp/packages/plugin-sql-editor/src/locales/it.ts index 4f9b26d165..8071d17e7e 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/it.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/it.ts @@ -8,6 +8,7 @@ export default [ ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', 'Mostra il piano di esecuzione (Shift + Ctrl + E)'], ['sql_editor_output_logs_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_tab_title', 'Output'], ['sql_editor_output_logs_input_placeholder', 'Enter a part of a message to search for here'], ['sql_editor_sql_execution_button_tooltip', "Esegui l'istruzione SQL (Ctrl + Enter)"], ['sql_editor_sql_execution_new_tab_button_tooltip', "Esegui l'istruzione SQL in una nuova tab (Ctrl + \\)(Shift + Ctrl + Enter)"], diff --git a/webapp/packages/plugin-sql-editor/src/locales/ru.ts b/webapp/packages/plugin-sql-editor/src/locales/ru.ts index 97058038e2..f639337962 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/ru.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/ru.ts @@ -8,6 +8,7 @@ export default [ ['sql_editor_hint_empty', 'Нет авто-дополнений...'], ['sql_editor_execution_plan_button_tooltip', 'Посмотреть информацию о плане выполнения запроса (Shift + Ctrl + E)'], ['sql_editor_output_logs_button_tooltip', 'Показать вывод сервера (Shift + Ctrl + O)'], + ['sql_editor_output_logs_tab_title', 'Вывод логов'], ['sql_editor_output_logs_input_placeholder', 'Введите часть сообщения для поиска'], ['sql_editor_sql_execution_button_tooltip', 'Выполнить SQL Выражение (Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', 'Выполнить SQL Выражение в новой вкладке (Ctrl + \\)(Shift + Ctrl + Enter)'], diff --git a/webapp/packages/plugin-sql-editor/src/locales/zh.ts b/webapp/packages/plugin-sql-editor/src/locales/zh.ts index 7cecf67b40..3c6d9ac298 100644 --- a/webapp/packages/plugin-sql-editor/src/locales/zh.ts +++ b/webapp/packages/plugin-sql-editor/src/locales/zh.ts @@ -8,6 +8,7 @@ export default [ ['sql_editor_hint_empty', 'There is no proposals...'], ['sql_editor_execution_plan_button_tooltip', '解释执行计划(Shift + Ctrl + E)'], ['sql_editor_output_logs_button_tooltip', 'Show server output (Shift + Ctrl + O)'], + ['sql_editor_output_logs_tab_title', 'Output'], ['sql_editor_output_logs_input_placeholder', 'Enter a part of a message to search for here'], ['sql_editor_sql_execution_button_tooltip', '执行SQL语句(Ctrl + Enter)'], ['sql_editor_sql_execution_new_tab_button_tooltip', '在新选项卡中执行SQL语句(Ctrl + \\)(Shift + Ctrl + Enter)'],