mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
fix(editor): implement missing methods, fix cursor position clearing (#38603)
This commit is contained in:
committed by
GitHub
parent
f5383263bc
commit
1867336907
@@ -369,6 +369,28 @@ export interface EditorProps {
|
||||
theme?: SupersetTheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* A single text change expressed as an offset-based replacement.
|
||||
*/
|
||||
export interface ContentChange {
|
||||
/** Character offset in the document where the replaced range starts */
|
||||
rangeOffset: number;
|
||||
/** Length in characters of the replaced range (0 for pure insertions) */
|
||||
rangeLength: number;
|
||||
/** Text inserted at rangeOffset (empty string for pure deletions) */
|
||||
text: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payload delivered to `onDidChangeContent` listeners.
|
||||
*/
|
||||
export interface ContentChangeEvent {
|
||||
/** Returns the full current content of the editor */
|
||||
getValue(): string;
|
||||
/** The individual changes that occurred in this event */
|
||||
changes: ReadonlyArray<ContentChange>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imperative API for controlling the editor programmatically.
|
||||
*
|
||||
@@ -492,6 +514,27 @@ export interface EditorHandle {
|
||||
* - CodeMirror: editor.requestMeasure()
|
||||
*/
|
||||
resize(): void;
|
||||
|
||||
/**
|
||||
* Subscribe to content changes in the editor.
|
||||
*
|
||||
* The listener receives a {@link ContentChangeEvent} with:
|
||||
* - `getValue()` — lazy accessor for the full content (call only when needed
|
||||
* to avoid unnecessary O(n) string allocation on every keystroke)
|
||||
* - `changes` — the individual edits that occurred, as offset-based replacements
|
||||
*
|
||||
* @param listener Called with a ContentChangeEvent on every change
|
||||
* @param thisArgs Optional `this` context for the listener
|
||||
* @returns A Disposable that unsubscribes the listener when disposed
|
||||
*
|
||||
* @example
|
||||
* const disposable = editor.onDidChangeContent(e => {
|
||||
* setStatements(parseStatements(e.getValue()));
|
||||
* });
|
||||
* // Later, to unsubscribe:
|
||||
* disposable.dispose();
|
||||
*/
|
||||
onDidChangeContent: Event<ContentChangeEvent>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -252,6 +252,22 @@ export interface QueryResult {
|
||||
*/
|
||||
export declare const getActivePanel: () => Panel;
|
||||
|
||||
/**
|
||||
* Switches the active panel in the SQL Lab south pane.
|
||||
* Built-in panel IDs are 'Results' and 'History'.
|
||||
* Pinned table panels use the table's ID as their panel ID.
|
||||
*
|
||||
* @param panelId The ID of the panel to activate
|
||||
* @returns Promise that resolves when the panel is activated
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Focus the Results panel after running a query
|
||||
* await setActivePanel('Results');
|
||||
* ```
|
||||
*/
|
||||
export declare function setActivePanel(panelId: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Gets the currently active tab in SQL Lab.
|
||||
*
|
||||
|
||||
@@ -55,6 +55,8 @@ type Range = editors.Range;
|
||||
type Selection = editors.Selection;
|
||||
type EditorAnnotation = editors.EditorAnnotation;
|
||||
type CompletionProvider = editors.CompletionProvider;
|
||||
type ContentChange = editors.ContentChange;
|
||||
type ContentChangeEvent = editors.ContentChangeEvent;
|
||||
|
||||
/**
|
||||
* Maps EditorLanguage to the corresponding Ace editor component.
|
||||
@@ -117,10 +119,14 @@ const createAceEditorHandle = (
|
||||
},
|
||||
|
||||
moveCursorToPosition: (position: Position) => {
|
||||
aceEditorRef.current?.editor?.moveCursorToPosition({
|
||||
row: position.line,
|
||||
column: position.column,
|
||||
});
|
||||
const editor = aceEditorRef.current?.editor;
|
||||
if (editor) {
|
||||
editor.clearSelection();
|
||||
editor.moveCursorToPosition({
|
||||
row: position.line,
|
||||
column: position.column,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
getSelections: (): Selection[] => {
|
||||
@@ -186,6 +192,33 @@ const createAceEditorHandle = (
|
||||
resize: () => {
|
||||
aceEditorRef.current?.editor?.resize();
|
||||
},
|
||||
|
||||
onDidChangeContent: (listener, thisArgs?) => {
|
||||
const editor = aceEditorRef.current?.editor;
|
||||
if (!editor) return new Disposable(() => {});
|
||||
const bound = (thisArgs ? listener.bind(thisArgs) : listener) as (
|
||||
e: ContentChangeEvent,
|
||||
) => void;
|
||||
const handler = (delta: {
|
||||
action: 'insert' | 'remove';
|
||||
start: { row: number; column: number };
|
||||
lines: string[];
|
||||
}) => {
|
||||
const rangeOffset = editor.session.doc.positionToIndex(delta.start);
|
||||
const changeText = delta.lines.join(
|
||||
editor.session.doc.getNewLineCharacter(),
|
||||
);
|
||||
const change: ContentChange =
|
||||
delta.action === 'insert'
|
||||
? { rangeOffset, rangeLength: 0, text: changeText }
|
||||
: { rangeOffset, rangeLength: changeText.length, text: '' };
|
||||
bound({ getValue: () => editor.getValue(), changes: [change] });
|
||||
};
|
||||
editor.session.on('change', handler);
|
||||
return new Disposable(() => {
|
||||
editor.session.off('change', handler);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
@@ -694,6 +694,12 @@ const setSchema: typeof sqlLabApi.setSchema = async (schema: string | null) => {
|
||||
store.dispatch(queryEditorSetSchema(queryEditor ?? null, schema));
|
||||
};
|
||||
|
||||
const setActivePanel: typeof sqlLabApi.setActivePanel = async (
|
||||
panelId: string,
|
||||
) => {
|
||||
store.dispatch({ type: SET_ACTIVE_SOUTHPANE_TAB, tabId: panelId });
|
||||
};
|
||||
|
||||
export const sqlLab: typeof sqlLabApi = {
|
||||
CTASMethod,
|
||||
getActivePanel,
|
||||
@@ -719,6 +725,7 @@ export const sqlLab: typeof sqlLabApi = {
|
||||
setDatabase,
|
||||
setCatalog,
|
||||
setSchema,
|
||||
setActivePanel,
|
||||
};
|
||||
|
||||
// Export all models
|
||||
|
||||
Reference in New Issue
Block a user