mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-4005 add wrap mode (#2081)
* CB-4005 add wrap mode * CB-4005 save wrap state in user settings * CB-4005 add tooltips * CB-4005 review fixes --------- Co-authored-by: EvgeniaBzzz <139753579+EvgeniaBzzz@users.noreply.github.com>
This commit is contained in:
@@ -105,6 +105,7 @@ export default [
|
||||
['ui_upload_files', 'Upload files'],
|
||||
['ui_upload_files_duplicate_error', 'Files with the same name already exist'],
|
||||
['ui_upload_file_fail', 'Failed to upload file'],
|
||||
['ui_filter', 'Filter'],
|
||||
|
||||
['root_permission_denied', "You don't have permissions"],
|
||||
['root_permission_no_permission', "You don't have permission for this action"],
|
||||
|
||||
@@ -89,6 +89,7 @@ export default [
|
||||
['ui_upload_files', 'Upload files'],
|
||||
['ui_upload_files_duplicate_error', 'Files with the same name already exist'],
|
||||
['ui_upload_file_fail', 'Failed to upload file'],
|
||||
['ui_filter', 'Filter'],
|
||||
|
||||
['root_permission_denied', 'Non hai i permessi'],
|
||||
['app_root_session_expire_warning_title', 'La sessione sta per scadere'],
|
||||
|
||||
@@ -101,6 +101,7 @@ export default [
|
||||
['ui_upload_files', 'Загрузить файлы'],
|
||||
['ui_upload_files_duplicate_error', 'Файлы с такими именами уже существуют'],
|
||||
['ui_upload_file_fail', 'Не удалось загрузить файл'],
|
||||
['ui_filter', 'Фильтр'],
|
||||
|
||||
['root_permission_denied', 'Отказано в доступе'],
|
||||
['root_permission_no_permission', 'У вас нет разрешения на это действие'],
|
||||
|
||||
@@ -102,6 +102,7 @@ export default [
|
||||
['ui_upload_files', 'Upload files'],
|
||||
['ui_upload_files_duplicate_error', 'Files with the same name already exist'],
|
||||
['ui_upload_file_fail', 'Failed to upload file'],
|
||||
['ui_filter', 'Filter'],
|
||||
|
||||
['root_permission_denied', '您没有权限'],
|
||||
['root_permission_no_permission', '您没有权限执行此操作'],
|
||||
|
||||
@@ -35,29 +35,23 @@ export const MenuBarItem = observer<Props, HTMLButtonElement>(
|
||||
const title = translate(rest.title);
|
||||
return (
|
||||
<button ref={ref} className={s(styles, { menuBarItem: true, hidden }, className)} {...rest} title={title} aria-label={title}>
|
||||
<div className={s(styles, { menuBarItemBox: true }, className)}>
|
||||
<div className={s(styles, { menuBarItemBox: true })}>
|
||||
{loading ? (
|
||||
<div className={s(styles, { menuBarItemIcon: true }, className)}>
|
||||
<Loader className={s(styles, { loader: true }, className)} small fullSize />
|
||||
<div className={s(styles, { menuBarItemIcon: true })}>
|
||||
<Loader className={s(styles, { loader: true })} small fullSize />
|
||||
</div>
|
||||
) : (
|
||||
icon && (
|
||||
<div className={s(styles, { menuBarItemIcon: true }, className)}>
|
||||
<Loader className={s(styles, { loader: true }, className)} suspense small fullSize>
|
||||
{typeof icon === 'string' ? (
|
||||
<IconOrImage className={s(styles, { iconOrImage: true }, className)} icon={icon} viewBox={viewBox} />
|
||||
) : (
|
||||
icon
|
||||
)}
|
||||
<div className={s(styles, { menuBarItemIcon: true })}>
|
||||
<Loader className={s(styles, { loader: true })} suspense small fullSize>
|
||||
{typeof icon === 'string' ? <IconOrImage className={s(styles, { iconOrImage: true })} icon={icon} viewBox={viewBox} /> : icon}
|
||||
</Loader>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
{label && displayLabel && (
|
||||
<div className={s(styles, { menuBarItemLabel: true }, className)}>{translate(label)}</div>
|
||||
)}
|
||||
{label && displayLabel && <div className={s(styles, { menuBarItemLabel: true })}>{translate(label)}</div>}
|
||||
{displaySubmenuMark && (
|
||||
<div className={s(styles, { menuBarItemMark: true }, className)}>
|
||||
<div className={s(styles, { menuBarItemMark: true })}>
|
||||
<Icon className={s(styles, { icon: true }, className)} name="angle" viewBox="0 0 15 8" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
+7
@@ -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 { createAction } from '@cloudbeaver/core-view';
|
||||
|
||||
export const ACTION_SHOW_OUTPUT_LOGS = createAction('action-show_output_logs', {
|
||||
|
||||
@@ -1,2 +1,9 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
export const OUTPUT_LOG_TYPES = ['Debug', 'Log', 'Info', 'Notice', 'Warning', 'Error'] as const;
|
||||
export type IOutputLogType = (typeof OUTPUT_LOG_TYPES)[number];
|
||||
|
||||
+1
-1
@@ -7,4 +7,4 @@
|
||||
*/
|
||||
import { createMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
export const OUTPUT_LOGS_FILTER_MENU = createMenu('output_logs_filter_menu', 'Output Logs');
|
||||
export const OUTPUT_LOGS_FILTER_MENU = createMenu('output_logs_filter_menu', '', 'filter', 'ui_filter');
|
||||
|
||||
@@ -0,0 +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_MENU = createMenu('output_logs_menu', 'Output Logs');
|
||||
+10
@@ -0,0 +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_SETTINGS_MENU = createMenu('output_logs_settings_menu', '', '/icons/settings_cog_sm.svg', 'ui_settings');
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
.contextMenu {
|
||||
padding: 0;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
& .icon {
|
||||
width: 16px;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
.menuBar {
|
||||
align-items: center;
|
||||
}
|
||||
+11
-10
@@ -8,23 +8,22 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { Icon, s, useS } from '@cloudbeaver/core-blocks';
|
||||
import { ContextMenu } from '@cloudbeaver/core-ui';
|
||||
import { s } from '@cloudbeaver/core-blocks';
|
||||
import { MenuBar, MenuBarItemStyles } from '@cloudbeaver/core-ui';
|
||||
import { useMenu } from '@cloudbeaver/core-view';
|
||||
|
||||
import { DATA_CONTEXT_SQL_EDITOR_STATE } from '../../DATA_CONTEXT_SQL_EDITOR_STATE';
|
||||
import type { ISqlEditorTabState } from '../../ISqlEditorTabState';
|
||||
import { OUTPUT_LOGS_FILTER_MENU } from './OUTPUT_LOGS_FILTER_MENU';
|
||||
import style from './OutputLogTypesFilterMenu.m.css';
|
||||
import { OUTPUT_LOGS_MENU } from './OUTPUT_LOGS_MENU';
|
||||
import styles from './OutputLogsMenu.m.css';
|
||||
|
||||
interface Props {
|
||||
sqlEditorTabState: ISqlEditorTabState;
|
||||
}
|
||||
|
||||
export const OutputLogsFilterMenu = observer<Props>(function OutputLogTypesFilterMenu({ sqlEditorTabState }) {
|
||||
const styles = useS(style);
|
||||
export const OutputLogsMenu = observer<Props>(function OutputLogsMenu({ sqlEditorTabState }) {
|
||||
const menu = useMenu({
|
||||
menu: OUTPUT_LOGS_FILTER_MENU,
|
||||
menu: OUTPUT_LOGS_MENU,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -32,8 +31,10 @@ export const OutputLogsFilterMenu = observer<Props>(function OutputLogTypesFilte
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ContextMenu className={s(styles, { contextMenu: true })} menu={menu} placement="bottom-end" modal>
|
||||
<Icon className={s(styles, { icon: true })} name="filter" viewBox="0 0 16 16" />
|
||||
</ContextMenu>
|
||||
<MenuBar
|
||||
menu={menu}
|
||||
nestedMenuSettings={{ modal: true, placement: 'top-start' }}
|
||||
className={s(styles, { menuBar: true }, MenuBarItemStyles.floating)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import { Container, Group, s, useResource, useS } from '@cloudbeaver/core-blocks';
|
||||
import { Container, useResource } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { EditorLoader } from '@cloudbeaver/plugin-codemirror6';
|
||||
|
||||
@@ -29,11 +29,19 @@ export const OutputLogsPanel = observer<Props>(function SqlOutputLogsPanel({ sql
|
||||
const state = useOutputLogsPanelState(outputLogs, sqlEditorTabState);
|
||||
|
||||
return (
|
||||
<Container className="theme-background-secondary" parent vertical gap dense>
|
||||
<OutputLogsToolbar state={state} sqlEditorTabState={sqlEditorTabState}/>
|
||||
<Group overflow box>
|
||||
{data && <EditorLoader value={state.resultValue} foldGutter={false} highlightActiveLine={false} lineWrapping readonly />}
|
||||
</Group>
|
||||
<Container className="theme-background-secondary" overflow vertical noWrap dense parent gap>
|
||||
<OutputLogsToolbar state={state} sqlEditorTabState={sqlEditorTabState} />
|
||||
{data && (
|
||||
<Container overflow>
|
||||
<EditorLoader
|
||||
value={state.resultValue}
|
||||
foldGutter={false}
|
||||
lineWrapping={outputLogsService.settings.wrapMode}
|
||||
highlightActiveLine={false}
|
||||
readonly
|
||||
/>
|
||||
</Container>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
});
|
||||
|
||||
+22
-1
@@ -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 { UserDataService } from '@cloudbeaver/core-authentication';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
|
||||
import type { ISqlEditorTabState } from '../../ISqlEditorTabState';
|
||||
@@ -13,9 +14,19 @@ import { OUTPUT_LOG_TYPES } from './IOutputLogTypes';
|
||||
import { OUTPUT_LOGS_TAB_ID } from './OUTPUT_LOGS_TAB_ID';
|
||||
import type { IOutputLog } from './OutputLogsResource';
|
||||
|
||||
const OUTPUT_LOGS_KEY = 'output_logs';
|
||||
|
||||
interface ISettings {
|
||||
wrapMode: boolean;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class OutputLogsService {
|
||||
constructor(private readonly sqlDataSourceService: SqlDataSourceService) {}
|
||||
get settings() {
|
||||
return this.userDataService.getUserData(OUTPUT_LOGS_KEY, getOutputLogsDefaultSettings);
|
||||
}
|
||||
|
||||
constructor(private readonly sqlDataSourceService: SqlDataSourceService, private readonly userDataService: UserDataService) {}
|
||||
|
||||
async showOutputLogs(editorState: ISqlEditorTabState): Promise<void> {
|
||||
this.createOutputLogsTab(editorState);
|
||||
@@ -28,6 +39,10 @@ export class OutputLogsService {
|
||||
}
|
||||
}
|
||||
|
||||
toggleWrapMode() {
|
||||
this.settings.wrapMode = !this.settings.wrapMode;
|
||||
}
|
||||
|
||||
private createOutputLogsTab(state: ISqlEditorTabState) {
|
||||
const order = Math.max(0, ...state.tabs.map(tab => tab.order + 1));
|
||||
|
||||
@@ -52,3 +67,9 @@ export class OutputLogsService {
|
||||
return events.filter(event => event.contextId === dataSource?.executionContext?.id);
|
||||
}
|
||||
}
|
||||
|
||||
function getOutputLogsDefaultSettings(): ISettings {
|
||||
return {
|
||||
wrapMode: true,
|
||||
};
|
||||
}
|
||||
|
||||
+3
-3
@@ -11,8 +11,8 @@ import React from 'react';
|
||||
import { Container, Icon, InputField, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
|
||||
import type { ISqlEditorTabState } from '../../ISqlEditorTabState';
|
||||
import { OutputLogsMenu } from './OutputLogsMenu';
|
||||
import style from './OutputLogsToolbar.m.css';
|
||||
import { OutputLogsFilterMenu } from './OutputLogTypesFilterMenu';
|
||||
import type { SqlOutputLogsPanelState } from './useOutputLogsPanelState';
|
||||
|
||||
interface Props {
|
||||
@@ -20,7 +20,7 @@ interface Props {
|
||||
sqlEditorTabState: ISqlEditorTabState;
|
||||
}
|
||||
|
||||
export const OutputLogsToolbar = observer<Props>(function SqlOutputLogsToolbar({ state, sqlEditorTabState }) {
|
||||
export const OutputLogsToolbar = observer<Props>(function OutputLogsToolbar({ state, sqlEditorTabState }) {
|
||||
const styles = useS(style);
|
||||
const translate = useTranslate();
|
||||
|
||||
@@ -38,7 +38,7 @@ export const OutputLogsToolbar = observer<Props>(function SqlOutputLogsToolbar({
|
||||
onChange={value => state.setSearchValue(value.toString())}
|
||||
/>
|
||||
<Container keepSize>
|
||||
<OutputLogsFilterMenu sqlEditorTabState={sqlEditorTabState} />
|
||||
<OutputLogsMenu sqlEditorTabState={sqlEditorTabState} />
|
||||
</Container>
|
||||
</Container>
|
||||
);
|
||||
|
||||
+43
-5
@@ -6,7 +6,7 @@
|
||||
* 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 { ActionService, DATA_CONTEXT_MENU, 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';
|
||||
@@ -17,6 +17,8 @@ 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 { OUTPUT_LOGS_MENU } from './OUTPUT_LOGS_MENU';
|
||||
import { OUTPUT_LOGS_SETTINGS_MENU } from './OUTPUT_LOGS_SETTINGS_MENU';
|
||||
import { OutputLogsService } from './OutputLogsService';
|
||||
|
||||
@injectable()
|
||||
@@ -32,9 +34,16 @@ export class OutputMenuBootstrap extends Bootstrap {
|
||||
}
|
||||
|
||||
register(): void | Promise<void> {
|
||||
this.menuService.addCreator({
|
||||
isApplicable: context => context.get(DATA_CONTEXT_MENU) === OUTPUT_LOGS_MENU,
|
||||
getItems(context, items) {
|
||||
return [...items, OUTPUT_LOGS_FILTER_MENU, OUTPUT_LOGS_SETTINGS_MENU];
|
||||
},
|
||||
});
|
||||
|
||||
this.menuService.addCreator({
|
||||
menus: [OUTPUT_LOGS_FILTER_MENU],
|
||||
getItems: context => {
|
||||
getItems: (context, items) => {
|
||||
const state = context.tryGet(DATA_CONTEXT_SQL_EDITOR_STATE);
|
||||
|
||||
if (!state) {
|
||||
@@ -42,10 +51,10 @@ export class OutputMenuBootstrap extends Bootstrap {
|
||||
}
|
||||
|
||||
const outputLogsTabState = state?.outputLogsTab;
|
||||
const items = [];
|
||||
const result = [];
|
||||
|
||||
for (const logType of OUTPUT_LOG_TYPES) {
|
||||
items.push(
|
||||
result.push(
|
||||
new MenuCheckboxItem(
|
||||
{
|
||||
id: logType,
|
||||
@@ -70,7 +79,36 @@ export class OutputMenuBootstrap extends Bootstrap {
|
||||
);
|
||||
}
|
||||
|
||||
return items;
|
||||
return [...items, ...result];
|
||||
},
|
||||
});
|
||||
|
||||
this.menuService.addCreator({
|
||||
menus: [OUTPUT_LOGS_SETTINGS_MENU],
|
||||
getItems: (context, items) => {
|
||||
const state = context.tryGet(DATA_CONTEXT_SQL_EDITOR_STATE);
|
||||
|
||||
if (!state) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const wrapMode = new MenuCheckboxItem(
|
||||
{
|
||||
id: 'wrap-mode',
|
||||
label: 'sql_editor_output_logs_wrap_mode',
|
||||
tooltip: 'sql_editor_output_logs_wrap_mode',
|
||||
},
|
||||
{
|
||||
onSelect: () => {
|
||||
this.outputLogsService.toggleWrapMode();
|
||||
},
|
||||
},
|
||||
{
|
||||
isChecked: () => this.outputLogsService.settings.wrapMode,
|
||||
},
|
||||
);
|
||||
|
||||
return [...items, wrapMode];
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ export default [
|
||||
['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_output_logs_wrap_mode', 'Wrap mode'],
|
||||
['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)'],
|
||||
|
||||
@@ -10,6 +10,7 @@ export default [
|
||||
['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_output_logs_wrap_mode', 'Wrap mode'],
|
||||
['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)'],
|
||||
|
||||
@@ -10,6 +10,7 @@ export default [
|
||||
['sql_editor_output_logs_button_tooltip', 'Показать вывод сервера (Shift + Ctrl + O)'],
|
||||
['sql_editor_output_logs_tab_title', 'Вывод логов'],
|
||||
['sql_editor_output_logs_input_placeholder', 'Введите часть сообщения для поиска'],
|
||||
['sql_editor_output_logs_wrap_mode', 'Перенос строк'],
|
||||
['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)'],
|
||||
|
||||
@@ -10,6 +10,7 @@ export default [
|
||||
['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_output_logs_wrap_mode', 'Wrap mode'],
|
||||
['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)'],
|
||||
|
||||
Reference in New Issue
Block a user