Skip to content

Commit

Permalink
Merge pull request #1995 from dbeaver/CB-3924
Browse files Browse the repository at this point in the history
Cb 3924
  • Loading branch information
DenisSinelnikov authored Sep 18, 2023
2 parents 241e01e + ada9eea commit 222ff29
Show file tree
Hide file tree
Showing 41 changed files with 724 additions and 49 deletions.
9 changes: 9 additions & 0 deletions webapp/packages/core-blocks/src/FormControls/InputField.m.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion webapp/packages/core-blocks/src/FormControls/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -41,6 +41,7 @@ type BaseProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' |
style?: ComponentStyle;
canShowPassword?: boolean;
onCustomCopy?: () => void;
icon?: React.ReactElement;
};

type ControlledProps = BaseProps & {
Expand Down Expand Up @@ -90,6 +91,7 @@ export const InputField: InputFieldType = observer(
canShowPassword = true,
onChange,
onCustomCopy,
icon,
...rest
}: ControlledProps | ObjectProps<any, any>,
ref,
Expand Down Expand Up @@ -196,6 +198,7 @@ export const InputField: InputFieldType = observer(
<Icon name="copy" viewBox="0 0 32 32" className={styles.icon} />
</div>
)}
{icon && <div data-testid="icon-container" className={styles.customIconContainer}>{icon}</div>}
</div>
{(description || passwordType) && (
<div data-testid="field-description" className={s(styles, { fieldDescription: true, valid: !error, invalid: error })}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mutation asyncSqlExecuteQuery(
$resultId: ID
$filter: SQLDataFilter
$dataFormat: ResultDataFormat
$readLogs: Boolean
) {
taskInfo: asyncSqlExecuteQuery(
connectionId: $connectionId
Expand All @@ -13,6 +14,7 @@ mutation asyncSqlExecuteQuery(
resultId: $resultId
filter: $filter
dataFormat: $dataFormat
readLogs: $readLogs
) {
...AsyncTaskInfo
}
Expand Down
44 changes: 42 additions & 2 deletions webapp/packages/plugin-codemirror6/src/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,49 @@ import { useCodemirrorExtensions } from './useCodemirrorExtensions';
import { type IDefaultExtensions, useEditorDefaultExtensions } from './useEditorDefaultExtensions';

export const Editor = observer<IEditorProps & IDefaultExtensions, IEditorRef>(
forwardRef(function Editor({ lineNumbers, extensions, ...rest }, ref) {
forwardRef(function Editor(
{
extensions,
lineNumbers,
tooltips,
highlightSpecialChars,
syntaxHighlighting,
bracketMatching,
dropCursor,
crosshairCursor,
foldGutter,
highlightActiveLineGutter,
highlightSelectionMatches,
highlightActiveLine,
indentOnInput,
rectangularSelection,
keymap,
lineWrapping,
...rest
},
ref,
) {
extensions = useCodemirrorExtensions(extensions);
const defaultExtensions = useEditorDefaultExtensions({ lineNumbers });


const defaultExtensions = useEditorDefaultExtensions({
lineNumbers,
tooltips,
highlightSpecialChars,
syntaxHighlighting,
bracketMatching,
dropCursor,
crosshairCursor,
foldGutter,
highlightActiveLineGutter,
highlightSelectionMatches,
highlightActiveLine,
indentOnInput,
rectangularSelection,
keymap,
lineWrapping,
});

extensions.set(...defaultExtensions);

return styled(EDITOR_BASE_STYLES)(
Expand Down
131 changes: 89 additions & 42 deletions webapp/packages/plugin-codemirror6/src/useEditorDefaultExtensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Compartment, Extension } from '@codemirror/state';
import {
crosshairCursor,
dropCursor,
EditorView,
highlightActiveLine,
highlightActiveLineGutter,
highlightSpecialChars,
Expand All @@ -21,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');
Expand All @@ -34,55 +35,101 @@ 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;
highlightSpecialChars?: boolean;
syntaxHighlighting?: boolean;
bracketMatching?: boolean;
dropCursor?: boolean;
crosshairCursor?: boolean;
foldGutter?: boolean;
highlightActiveLineGutter?: boolean;
highlightSelectionMatches?: boolean;
highlightActiveLine?: boolean;
indentOnInput?: boolean;
rectangularSelection?: boolean;
keymap?: boolean;
lineWrapping?: boolean;
}

const extensionMap = {
lineNumbers,
tooltips: () => tooltips({ parent: document.body }),
highlightSpecialChars,
syntaxHighlighting: () => syntaxHighlighting(classHighlighter),
bracketMatching,
dropCursor,
highlightSelectionMatches,
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%';

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');

return element;
},
}),
highlightActiveLineGutter,
highlightActiveLine,
indentOnInput,
rectangularSelection,
keymap: () => keymap.of(DEFAULT_KEY_MAP),
lineWrapping: () => EditorView.lineWrapping,
};

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 previousOptions = useRef(options);
const isOptionsChanged = !isObjectsEqual(options, previousOptions.current);
const extensions = useRef<[Compartment, Extension] | null>(null);

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%';
if (isOptionsChanged || extensions.current === null) {
previousOptions.current = options;
extensions.current = createExtensions(options);
}

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');

return element;
},
}),
highlightActiveLineGutter(),
highlightActiveLine(),
indentOnInput(),
rectangularSelection(),
keymap.of(DEFAULT_KEY_MAP),
);
return extensions.current;
}

return [DEFAULT_EXTENSIONS_COMPARTMENT, extensions];
}, [options?.lineNumbers]);
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];
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export interface IDatabaseDataOptions {
catalog?: string;
whereFilter: string;
constraints: SqlDataFilterConstraint[];
readLogs?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions webapp/packages/plugin-sql-editor/src/ISqlEditorTabState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/IOutputLogTypes';

export interface IResultTab {
tabId: string;
Expand Down Expand Up @@ -41,6 +42,10 @@ export interface IExecutionPlanTab {
options?: Record<string, any>;
}

export interface IOutputLogsTab extends ISqlEditorResultTab {
selectedLogTypes: IOutputLogType[];
}

export interface ISqlEditorTabState {
editorId: string;
datasourceKey: string;
Expand All @@ -54,6 +59,7 @@ export interface ISqlEditorTabState {
resultTabs: IResultTab[];
statisticsTabs: IStatisticsTab[];
executionPlanTabs: IExecutionPlanTab[];
outputLogsTab?: IOutputLogsTab;

// mode
currentModeId?: string;
Expand Down
5 changes: 5 additions & 0 deletions webapp/packages/plugin-sql-editor/src/MenuBootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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)
Expand All @@ -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),
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/plugin-sql-editor/src/QueryDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ export class QueryDataSource<TOptions extends IDataQueryOptions = IDataQueryOpti
where: options.whereFilter || undefined,
},
dataFormat: this.dataFormat,
readLogs: options.readLogs,
});

return taskInfo;
Expand Down
Loading

0 comments on commit 222ff29

Please sign in to comment.