diff --git a/packages/web/src/commands/invalidateCommands.ts b/packages/web/src/commands/invalidateCommands.ts index 6d0568f8c..f6fcd6301 100644 --- a/packages/web/src/commands/invalidateCommands.ts +++ b/packages/web/src/commands/invalidateCommands.ts @@ -30,11 +30,38 @@ export default async function invalidateCommands() { if (!command.isGroupCommand) continue; const groupSources = values.filter(x => x.group == command.group && !x.isGroupCommand && x.enabled); command.enabled = groupSources.length > 0; - for(const source of groupSources) { - source.keyTextFromGroup = command.keyText; - } + // for (const source of groupSources) { + // source.keyTextFromGroup = command.keyText; + // } } } return res || dct; }); } + +let isInvalidatedDefinitions = false; + +export async function invalidateCommandDefinitions() { + if (isInvalidatedDefinitions) return; + isInvalidatedDefinitions = true; + await tick(); + + isInvalidatedDefinitions = false; + + commands.update(dct => { + let res = { ...dct }; + const values = Object.values(res) as GlobalCommand[]; + // test enabled for group commands + for (const command of values) { + if (!command.isGroupCommand) continue; + const groupSources = values.filter(x => x.group == command.group && !x.isGroupCommand); + + for (const source of groupSources) { + source.keyTextFromGroup = command.keyText; + } + } + return res; + }); + + invalidateCommands(); +} diff --git a/packages/web/src/commands/registerCommand.ts b/packages/web/src/commands/registerCommand.ts index 49ed8026a..9425ab0fc 100644 --- a/packages/web/src/commands/registerCommand.ts +++ b/packages/web/src/commands/registerCommand.ts @@ -1,5 +1,5 @@ import { commands } from '../stores'; -import invalidateCommands from './invalidateCommands'; +import { invalidateCommandDefinitions } from './invalidateCommands'; export interface SubCommand { text: string; @@ -39,16 +39,5 @@ export default function registerCommand(command: GlobalCommand) { enabled: !testEnabled, }, })); - invalidateCommands(); - // if (enabledStore) { - // enabledStore.subscribe(value => { - // commands.update(x => ({ - // ...x, - // [command.id]: { - // ...x[command.id], - // enabled: value, - // }, - // })); - // }); - // } + invalidateCommandDefinitions(); } diff --git a/packages/web/src/commands/stdCommands.ts b/packages/web/src/commands/stdCommands.ts index 4a090084f..4504f774e 100644 --- a/packages/web/src/commands/stdCommands.ts +++ b/packages/web/src/commands/stdCommands.ts @@ -142,6 +142,24 @@ registerCommand({ group: 'saveAs', }); +registerCommand({ + id: 'group.undo', + category: null, + isGroupCommand: true, + name: 'Undo', + keyText: 'Ctrl+Z', + group: 'undo', +}); + +registerCommand({ + id: 'group.redo', + category: null, + isGroupCommand: true, + name: 'Redo', + keyText: 'Ctrl+Y', + group: 'redo', +}); + if (electron) { registerCommand({ id: 'file.open', @@ -175,6 +193,7 @@ export function registerFileCommands({ execute = false, toggleComment = false, findReplace = false, + undoRedo = false, }) { registerCommand({ id: idPrefix + '.save', @@ -248,4 +267,22 @@ export function registerFileCommands({ onClick: () => getCurrentEditor().replace(), }); } + if (undoRedo) { + registerCommand({ + id: idPrefix + '.undo', + category, + name: 'Undo', + group: 'undo', + testEnabled: () => getCurrentEditor()?.canUndo(), + onClick: () => getCurrentEditor().undo(), + }); + registerCommand({ + id: idPrefix + '.redo', + category, + group: 'redo', + name: 'Replace', + testEnabled: () => getCurrentEditor()?.canRedo(), + onClick: () => getCurrentEditor().redo(), + }); + } } diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index 66b5e7c6b..ca1ff6068 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -74,7 +74,7 @@ id: 'dataGrid.undo', category: 'Data grid', name: 'Undo', - keyText: 'Ctrl+Z', + group: 'undo', icon: 'icon undo', toolbar: true, testEnabled: () => getCurrentDataGrid()?.getGrider()?.canUndo, @@ -85,7 +85,7 @@ id: 'dataGrid.redo', category: 'Data grid', name: 'Redo', - keyText: 'Ctrl+Y', + group: 'redo', icon: 'icon redo', toolbar: true, testEnabled: () => getCurrentDataGrid()?.getGrider()?.canRedo, diff --git a/packages/web/src/designer/Designer.svelte b/packages/web/src/designer/Designer.svelte index 243ca5d78..fa51475d5 100644 --- a/packages/web/src/designer/Designer.svelte +++ b/packages/web/src/designer/Designer.svelte @@ -18,7 +18,7 @@ export let onChange; export let conid; export let database; - // export let menu; + export let menu; let domCanvas; @@ -286,7 +286,7 @@ } -
+
{#if !(tables?.length > 0)}
Drag & drop tables or views from left panel here
{/if} diff --git a/packages/web/src/modals/DropDownMenu.svelte b/packages/web/src/modals/DropDownMenu.svelte index 84832d871..84729542b 100644 --- a/packages/web/src/modals/DropDownMenu.svelte +++ b/packages/web/src/modals/DropDownMenu.svelte @@ -58,6 +58,7 @@ const dispatch = createEventDispatcher(); function handleClick(item) { + if (item.disabled) return; dispatch('close'); if (item.onClick) item.onClick(); } diff --git a/packages/web/src/tabs/QueryDesignTab.svelte b/packages/web/src/tabs/QueryDesignTab.svelte index 04c390003..2b32b5702 100644 --- a/packages/web/src/tabs/QueryDesignTab.svelte +++ b/packages/web/src/tabs/QueryDesignTab.svelte @@ -12,6 +12,7 @@ fileExtension: 'qdesign', execute: true, + undoRedo: true, }); @@ -86,6 +87,7 @@ $: { busy; sessionId; + $editorState; invalidateCommands(); } @@ -142,6 +144,22 @@ return $editorState.value || ''; } + export function canUndo() { + return $modelState.canUndo; + } + + export function undo() { + dispatchModel({ type: 'undo' }); + } + + export function canRedo() { + return $modelState.canRedo; + } + + export function redo() { + dispatchModel({ type: 'redo' }); + } + const generatePreview = (value, engine) => { if (!engine || !value) return; const sql = generateDesignedQuery(value, engine); @@ -181,6 +199,18 @@ // /> // // )} + function createMenu() { + return [ + { command: 'designer.execute' }, + { command: 'designer.kill' }, + { divider: true }, + { command: 'designer.save' }, + { command: 'designer.saveAs' }, + { divider: true }, + { command: 'designer.undo' }, + { command: 'designer.redo' }, + ]; + } @@ -191,6 +221,7 @@ {database} engine={$connection && $connection.engine} onChange={handleChange} + menu={createMenu} /> diff --git a/packages/web/src/utility/contextMenu.ts b/packages/web/src/utility/contextMenu.ts index f77bbee9f..5538e28cf 100644 --- a/packages/web/src/utility/contextMenu.ts +++ b/packages/web/src/utility/contextMenu.ts @@ -4,6 +4,7 @@ import { currentDropDownMenu } from '../stores'; export default function contextMenu(node, items) { const handleContextMenu = e => { e.preventDefault(); + e.stopPropagation(); const left = e.pageX; const top = e.pageY; currentDropDownMenu.set({ left, top, items: _.isFunction(items) ? items() : items });