mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-06 06:48:21 +00:00
Fix: shortcut can be used throughtout the editor and added custom hook in codeeditor for query panel shortcuts.
This commit is contained in:
parent
191348efdc
commit
f234384f25
5 changed files with 103 additions and 31 deletions
|
|
@ -21,6 +21,7 @@ import useStore from '@/AppBuilder/_stores/store';
|
|||
import { shallow } from 'zustand/shallow';
|
||||
import { search, searchKeymap, searchPanelOpen } from '@codemirror/search';
|
||||
import { handleSearchPanel, SearchBtn } from './SearchBox';
|
||||
import { useQueryPanelKeyHooks } from './useQueryPanelKeyHooks';
|
||||
|
||||
const langSupport = Object.freeze({
|
||||
javascript: javascript(),
|
||||
|
|
@ -64,6 +65,8 @@ const MultiLineCodeEditor = (props) => {
|
|||
|
||||
const [editorView, setEditorView] = React.useState(null);
|
||||
|
||||
const { queryPanelKeybindings } = useQueryPanelKeyHooks(onChange, currentValueRef, 'multiline');
|
||||
|
||||
const handleOnBlur = () => {
|
||||
if (!delayOnChange) return onChange(currentValueRef.current);
|
||||
setTimeout(() => {
|
||||
|
|
@ -85,6 +88,7 @@ const MultiLineCodeEditor = (props) => {
|
|||
highlightActiveLine: false,
|
||||
autocompletion: hideSuggestion ?? true,
|
||||
highlightActiveLineGutter: false,
|
||||
defaultKeymap: false,
|
||||
completionKeymap: true,
|
||||
searchKeymap: false,
|
||||
};
|
||||
|
|
@ -187,7 +191,12 @@ const MultiLineCodeEditor = (props) => {
|
|||
};
|
||||
}
|
||||
|
||||
const customKeyMaps = [...defaultKeymap, ...completionKeymap, ...searchKeymap];
|
||||
const customKeyMaps = [
|
||||
...defaultKeymap.filter((keyBinding) => keyBinding.key !== 'Mod-Enter'), // Remove default keybinding for Mod-Enter
|
||||
...completionKeymap,
|
||||
...searchKeymap,
|
||||
];
|
||||
|
||||
const customTabKeymap = keymap.of([
|
||||
{
|
||||
key: 'Tab',
|
||||
|
|
@ -208,6 +217,7 @@ const MultiLineCodeEditor = (props) => {
|
|||
return true;
|
||||
},
|
||||
},
|
||||
...queryPanelKeybindings,
|
||||
]);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import CodeHinter from './CodeHinter';
|
|||
import { removeNestedDoubleCurlyBraces } from '@/_helpers/utils';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { useQueryPanelKeyHooks } from './useQueryPanelKeyHooks';
|
||||
|
||||
const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...restProps }) => {
|
||||
const { initialValue, onChange, enablePreview = true, portalProps } = restProps;
|
||||
|
|
@ -170,6 +171,8 @@ const EditorInput = ({
|
|||
onInputChange,
|
||||
}) => {
|
||||
const getSuggestions = useStore((state) => state.getSuggestions, shallow);
|
||||
const { queryPanelKeybindings } = useQueryPanelKeyHooks(onBlurUpdate, currentValue, 'singleline');
|
||||
|
||||
function autoCompleteExtensionConfig(context) {
|
||||
const hints = getSuggestions();
|
||||
let word = context.matchBefore(/\w*/);
|
||||
|
|
@ -229,7 +232,10 @@ const EditorInput = ({
|
|||
maxRenderedOptions: 10,
|
||||
});
|
||||
|
||||
const customKeyMaps = [...defaultKeymap, ...completionKeymap];
|
||||
const customKeyMaps = [
|
||||
...defaultKeymap.filter((keyBinding) => keyBinding.key !== 'Mod-Enter'), // Remove default keybinding for Mod-Enter
|
||||
...completionKeymap,
|
||||
];
|
||||
const customTabKeymap = keymap.of([
|
||||
{
|
||||
key: 'Tab',
|
||||
|
|
@ -251,6 +257,7 @@ const EditorInput = ({
|
|||
}
|
||||
},
|
||||
},
|
||||
...queryPanelKeybindings,
|
||||
]);
|
||||
|
||||
const handleOnChange = React.useCallback((val) => {
|
||||
|
|
@ -395,6 +402,7 @@ const EditorInput = ({
|
|||
foldGutter: false,
|
||||
highlightActiveLine: false,
|
||||
autocompletion: true,
|
||||
defaultKeymap: false,
|
||||
completionKeymap: true,
|
||||
searchKeymap: false,
|
||||
}}
|
||||
|
|
|
|||
58
frontend/src/AppBuilder/CodeEditor/useQueryPanelKeyHooks.js
Normal file
58
frontend/src/AppBuilder/CodeEditor/useQueryPanelKeyHooks.js
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import { useModuleId } from '@/AppBuilder/_contexts/ModuleContext';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
export const useQueryPanelKeyHooks = (onChange, value, type) => {
|
||||
const queryPanelHeight = useStore((state) => state.queryPanel.queryPanelHeight);
|
||||
const runQueryOnShortcut = useStore((state) => state.queryPanel.runQueryOnShortcut);
|
||||
const previewQueryOnShortcut = useStore((state) => state.queryPanel.previewQueryOnShortcut);
|
||||
const moduleId = useModuleId();
|
||||
const location = useLocation();
|
||||
const { pathname } = location;
|
||||
|
||||
const [queryPanelKeybindings, setQueryPanelKeybindings] = useState([]);
|
||||
|
||||
const handleRunQuery = useCallback(
|
||||
(view) => {
|
||||
const isEditor = pathname.includes('/apps/');
|
||||
if (queryPanelHeight !== 0 && isEditor) {
|
||||
onChange(type === 'multiline' ? value.current : value);
|
||||
runQueryOnShortcut();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[queryPanelHeight, onChange, runQueryOnShortcut, value]
|
||||
);
|
||||
|
||||
const handlePreviewQuery = useCallback(
|
||||
(view) => {
|
||||
const isEditor = pathname.includes('/apps/');
|
||||
if (queryPanelHeight !== 0 && isEditor) {
|
||||
onChange(type === 'multiline' ? value.current : value);
|
||||
previewQueryOnShortcut(moduleId);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[queryPanelHeight, moduleId, onChange, previewQueryOnShortcut, value]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setQueryPanelKeybindings([
|
||||
{
|
||||
key: 'Mod-Enter',
|
||||
preventDefault: true,
|
||||
run: handleRunQuery,
|
||||
},
|
||||
{
|
||||
key: 'Mod-Shift-Enter',
|
||||
preventDefault: true,
|
||||
run: handlePreviewQuery,
|
||||
},
|
||||
]);
|
||||
}, [handleRunQuery, handlePreviewQuery]);
|
||||
|
||||
return {
|
||||
queryPanelKeybindings,
|
||||
};
|
||||
};
|
||||
|
|
@ -4,45 +4,23 @@ import { useHotkeys } from 'react-hotkeys-hook';
|
|||
import { useModuleId } from '@/AppBuilder/_contexts/ModuleContext';
|
||||
|
||||
const QueryKeyHooks = ({ children, isExpanded }) => {
|
||||
const runQuery = useStore((state) => state.queryPanel.runQuery);
|
||||
const selectedQuery = useStore((state) => state.queryPanel.selectedQuery);
|
||||
const runQueryOnShortcut = useStore((state) => state.queryPanel.runQueryOnShortcut);
|
||||
const previewQueryOnShortcut = useStore((state) => state.queryPanel.previewQueryOnShortcut);
|
||||
const moduleId = useModuleId();
|
||||
const previewQuery = useStore((state) => state.queryPanel.previewQuery);
|
||||
const selectedDataSource = useStore((state) => state.queryPanel.selectedDataSource);
|
||||
const queryName = selectedQuery?.name ?? '';
|
||||
|
||||
const previewButtonOnClick = () => {
|
||||
const _options = { ...selectedQuery.options };
|
||||
const query = {
|
||||
data_source_id: selectedDataSource.id === 'null' ? null : selectedDataSource.id,
|
||||
pluginId: selectedDataSource.pluginId,
|
||||
options: _options,
|
||||
kind: selectedDataSource.kind,
|
||||
name: queryName,
|
||||
id: selectedQuery?.id,
|
||||
};
|
||||
previewQuery(query, false, undefined, moduleId).catch(({ error, data }) => {
|
||||
console.log(error, data);
|
||||
});
|
||||
};
|
||||
|
||||
const shortcutRef = useHotkeys(
|
||||
useHotkeys(
|
||||
['mod+enter', 'mod+shift+enter'],
|
||||
(event, handler) => {
|
||||
if (handler.mod && handler.keys[0] === 'enter') {
|
||||
if (handler.shift) {
|
||||
previewButtonOnClick();
|
||||
} else runQuery(selectedQuery?.id, selectedQuery?.name, undefined, 'edit', {}, true);
|
||||
previewQueryOnShortcut(moduleId);
|
||||
} else runQueryOnShortcut();
|
||||
}
|
||||
},
|
||||
{ enabled: isExpanded }
|
||||
{ enabled: isExpanded, enableOnFormTags: ['input'] }
|
||||
);
|
||||
|
||||
return (
|
||||
<div ref={shortcutRef} tabIndex={-1} className="row main-row">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
return <div className="row main-row">{children}</div>;
|
||||
};
|
||||
|
||||
export default QueryKeyHooks;
|
||||
|
|
|
|||
|
|
@ -1028,5 +1028,23 @@ export const createQueryPanelSlice = (set, get) => ({
|
|||
isQuerySelected: (queryId) => {
|
||||
return get().queryPanel.selectedQuery?.id === queryId;
|
||||
},
|
||||
runQueryOnShortcut: () => {
|
||||
const { queryPanel } = get();
|
||||
const { runQuery, selectedQuery } = queryPanel;
|
||||
runQuery(selectedQuery?.id, selectedQuery?.name, undefined, 'edit', {}, true);
|
||||
},
|
||||
previewQueryOnShortcut: (moduleId = 'canvas') => {
|
||||
const { queryPanel } = get();
|
||||
const { previewQuery, selectedQuery, selectedDataSource } = queryPanel;
|
||||
const query = {
|
||||
data_source_id: selectedDataSource.id === 'null' ? null : selectedDataSource.id,
|
||||
pluginId: selectedDataSource.pluginId,
|
||||
options: { ...selectedQuery?.options },
|
||||
kind: selectedDataSource.kind,
|
||||
name: selectedQuery?.name ?? '',
|
||||
id: selectedQuery?.id,
|
||||
};
|
||||
previewQuery(query, false, undefined, moduleId);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue