Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CB-4134 adjust cursor position #2299

Merged
merged 8 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions webapp/packages/core-blocks/src/FormControls/Textarea.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 { useCallback, useContext } from 'react';
import { useCallback, useContext, useEffect, useRef } from 'react';

import { filterLayoutFakeProps, getLayoutProps } from '../Containers/filterLayoutFakeProps';
import type { ILayoutSizeProps } from '../Containers/ILayoutSizeProps';
Expand All @@ -23,6 +23,7 @@ type BaseProps = Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChan
description?: string;
labelTooltip?: string;
embedded?: boolean;
cursorInitiallyAtEnd?: boolean;
};

type ControlledProps = BaseProps & {
Expand Down Expand Up @@ -54,9 +55,11 @@ export const Textarea: TextareaType = observer(function Textarea({
description,
labelTooltip,
embedded,
cursorInitiallyAtEnd,
onChange = () => {},
...rest
}: ControlledProps | ObjectProps<any, any>) {
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
const layoutProps = getLayoutProps(rest);
rest = filterLayoutFakeProps(rest);
const styles = useS(textareaStyle);
Expand All @@ -79,13 +82,21 @@ export const Textarea: TextareaType = observer(function Textarea({

const value = state ? state[name] : controlledValue;

useEffect(() => {
if (cursorInitiallyAtEnd && typeof value === 'string') {
const position = value.trim().length;
textareaRef.current?.setSelectionRange(position, position);
}
}, []);
Wroud marked this conversation as resolved.
Show resolved Hide resolved

return (
<Field {...layoutProps} className={s(styles, { field: true, embedded }, className)}>
<FieldLabel className={s(styles, { fieldLabel: true })} title={labelTooltip || rest.title} required={required}>
<FieldLabel className={s(styles, { fieldLabel: true })} title={labelTooltip || rest.title} required={required}>
{children}
</FieldLabel>
<textarea
{...rest}
ref={textareaRef}
required={required}
className={s(styles, { textarea: true })}
value={value ?? ''}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,64 @@ export const SQLCodeEditorPanel: TabContainerPanelComponent<ISqlEditorModeProps>
],
});

useExecutor({
executor: data.onFormat,
Wroud marked this conversation as resolved.
Show resolved Hide resolved
handlers: [
function setCursor([script, formatted]) {
const view = editorRef?.view;

if (!view) {
return;
}

const selection = view.state.selection.main;

setTimeout(() => {
view.dispatch({
selection: {
anchor: selection.from,
head: selection.from,
},
});
});
},
],
});
Wroud marked this conversation as resolved.
Show resolved Hide resolved

useExecutor({
executor: data.dataSource?.onSetScript,
postHandlers: [
function setScript({ script, source }) {
if (source === 'insert') {
// Note: Use setTimeout to ensure this runs after the current transaction is fully processed
Wroud marked this conversation as resolved.
Show resolved Hide resolved
setTimeout(() => {
const view = editorRef?.view;

if (!view) {
return;
}

const currentContent = view.state.doc.toString();
const startPos = currentContent.lastIndexOf(script);

if (startPos === -1) {
return;
}

const endPos = startPos + script.length;

view.dispatch({
selection: {
anchor: endPos,
head: endPos,
},
});
});
}
},
],
});

function applyIncoming() {
data.dataSource?.applyIncoming();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ import type { IDatabaseDataModel, IDatabaseResultSet } from '@cloudbeaver/plugin

import type { IDataQueryOptions } from '../QueryDataSource';
import { ESqlDataSourceFeatures } from './ESqlDataSourceFeatures';
import type { ISetScriptData, ISqlDataSource, ISqlDataSourceKey } from './ISqlDataSource';
import type { ISetScriptData, ISqlDataSource, ISqlDataSourceKey, ScriptDataSourceType } from './ISqlDataSource';
import type { ISqlDataSourceHistory } from './SqlDataSourceHistory/ISqlDataSourceHistory';
import { SqlDataSourceHistory } from './SqlDataSourceHistory/SqlDataSourceHistory';

const SOURCE_HISTORY = 'history';

@staticImplements<ISqlDataSourceKey>()
export abstract class BaseSqlDataSource implements ISqlDataSource {
static key = 'base';
Expand Down Expand Up @@ -96,13 +94,13 @@ export abstract class BaseSqlDataSource implements ISqlDataSource {
this.onDatabaseModelUpdate.setInitialDataGetter(() => this.databaseModels);
this.onSetScript.next(this.onUpdate);
this.onSetScript.addHandler(({ script, source }) => {
if (source === SOURCE_HISTORY) {
if (source === 'history') {
return;
}
this.history.add(script);
});

this.history.onNavigate.addHandler(value => this.setScript(value, SOURCE_HISTORY));
this.history.onNavigate.addHandler(value => this.setScript(value, 'history'));

makeObservable<this, 'outdated' | 'editing'>(this, {
isSaved: computed,
Expand Down Expand Up @@ -132,7 +130,7 @@ export abstract class BaseSqlDataSource implements ISqlDataSource {
});
}

setScript(script: string, source?: string): void {
setScript(script: string, source?: ScriptDataSourceType): void {
this.onSetScript.execute({ script, source });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ export interface ISqlDataSourceKey {
readonly key: string;
}

export type ScriptDataSourceType = 'history' | 'insert';
Wroud marked this conversation as resolved.
Show resolved Hide resolved

export interface ISetScriptData {
script: string;
source?: string;
source?: ScriptDataSourceType;
}

export interface ISqlDataSource extends ILoadableState {
Expand Down Expand Up @@ -54,7 +56,7 @@ export interface ISqlDataSource extends ILoadableState {
canRename(name: string | null): boolean;
setName(name: string | null): void;
setProject(projectId: string | null): void;
setScript(script: string, source?: string): void;
setScript(script: string, source?: ScriptDataSourceType): void;
setEditing(state: boolean): void;
setExecutionContext(executionContext?: IConnectionExecutionContextInfo): void;
setIncomingExecutionContext(executionContext?: IConnectionExecutionContextInfo): void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { IConnectionExecutionContextInfo } from '@cloudbeaver/core-connecti

import { BaseSqlDataSource } from '../BaseSqlDataSource';
import { ESqlDataSourceFeatures } from '../ESqlDataSourceFeatures';
import type { ScriptDataSourceType } from '../ISqlDataSource';
import type { ILocalStorageSqlDataSourceState } from './ILocalStorageSqlDataSourceState';

export class LocalStorageSqlDataSource extends BaseSqlDataSource {
Expand Down Expand Up @@ -75,9 +76,9 @@ export class LocalStorageSqlDataSource extends BaseSqlDataSource {
return true;
}

setScript(script: string): void {
setScript(script: string, source?: ScriptDataSourceType): void {
this.state.script = script;
super.setScript(script);
super.setScript(script, source);
}

setExecutionContext(executionContext?: IConnectionExecutionContextInfo): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,8 @@ export function useSqlEditor(state: ISqlEditorTabState): ISQLEditorData {
this.readonlyState = true;
const formatted = await this.sqlDialectInfoService.formatScript(this.dataSource.executionContext, script.query);

this.onFormat.execute([script, formatted]);
this.setScript(query.substring(0, script.begin) + formatted + query.substring(script.end));
this.onFormat.execute([script, formatted]);
Wroud marked this conversation as resolved.
Show resolved Hide resolved
} finally {
this.readonlyState = false;
}
Expand Down
Loading