command enabling refactor

This commit is contained in:
Jan Prochazka 2021-03-15 19:33:37 +01:00
parent dfa8ca6797
commit 3b3e81e3f7
13 changed files with 207 additions and 140 deletions

View File

@ -10,7 +10,7 @@
showDisabled: true,
icon: 'icon menu',
onClick: () => visibleCommandPalette.set(true),
enabledStore: derived(visibleCommandPalette, $visibleCommandPalette => !$visibleCommandPalette),
testEnabled: () => !getVisibleCommandPalette(),
});
</script>
@ -20,7 +20,7 @@
import _ from 'lodash';
import { derived } from 'svelte/store';
import { onMount } from 'svelte';
import { commands, visibleCommandPalette } from '../stores';
import { commands, getVisibleCommandPalette, visibleCommandPalette } from '../stores';
import clickOutside from '../utility/clickOutside';
import keycodes from '../utility/keycodes';
import registerCommand from './registerCommand';

View File

@ -0,0 +1,30 @@
import { tick } from 'svelte';
import { commands } from '../stores';
let isInvalidated = false;
export default async function invalidateCommands() {
if (isInvalidated) return;
isInvalidated = true;
await tick();
isInvalidated = false;
commands.update(dct => {
let res = null;
for (const key of Object.keys(dct)) {
const command = dct[key];
const { testEnabled } = command;
let enabled = command.enabled;
if (testEnabled) enabled = testEnabled();
if (enabled != command.enabled) {
if (!res) res = { ...dct };
res[key] = {
...command,
enabled,
};
}
}
return res || dct;
});
}

View File

@ -13,7 +13,8 @@ export interface GlobalCommand {
keyText?: string;
getSubCommands?: () => SubCommand[];
onClick?: Function;
enabledStore?: any;
testEnabled?: () => boolean;
// enabledStore?: any;
icon?: string;
toolbar?: boolean;
enabled?: boolean;
@ -24,24 +25,24 @@ export interface GlobalCommand {
}
export default function registerCommand(command: GlobalCommand) {
const { enabledStore } = command;
const { testEnabled } = command;
commands.update(x => ({
...x,
[command.id]: {
text: `${command.category}: ${command.name}`,
...command,
enabled: !enabledStore,
enabled: !testEnabled,
},
}));
if (enabledStore) {
enabledStore.subscribe(value => {
commands.update(x => ({
...x,
[command.id]: {
...x[command.id],
enabled: value,
},
}));
});
}
// if (enabledStore) {
// enabledStore.subscribe(value => {
// commands.update(x => ({
// ...x,
// [command.id]: {
// ...x[command.id],
// enabled: value,
// },
// }));
// });
// }
}

View File

@ -1,4 +1,4 @@
import { currentTheme, extensions, visibleToolbar } from '../stores';
import { currentTheme, extensions, getVisibleToolbar, visibleToolbar } from '../stores';
import registerCommand from './registerCommand';
import { derived, get } from 'svelte/store';
import { ThemeDefinition } from 'dbgate-types';
@ -34,7 +34,7 @@ registerCommand({
category: 'Toolbar',
name: 'Show',
onClick: () => visibleToolbar.set(1),
enabledStore: derived(visibleToolbar, $visibleToolbar => !$visibleToolbar),
testEnabled: () => !getVisibleToolbar(),
});
registerCommand({
@ -42,7 +42,7 @@ registerCommand({
category: 'Toolbar',
name: 'Hide',
onClick: () => visibleToolbar.set(0),
enabledStore: derived(visibleToolbar, $visibleToolbar => $visibleToolbar),
testEnabled: () => getVisibleToolbar(),
});
registerCommand({
@ -112,8 +112,7 @@ registerCommand({
export function registerFileCommands({
idPrefix,
category,
editorStore,
editorStatusStore = undefined,
getCurrentEditor,
folder,
format,
fileExtension,
@ -128,16 +127,16 @@ export function registerFileCommands({
keyText: 'Ctrl+S',
icon: 'icon save',
toolbar: true,
enabledStore: saveTabEnabledStore(editorStore),
onClick: () => saveTabFile(editorStore, false, folder, format, fileExtension),
testEnabled: () => getCurrentEditor() != null,
onClick: () => saveTabFile(getCurrentEditor(), false, folder, format, fileExtension),
});
registerCommand({
id: idPrefix + '.saveAs',
category,
name: 'Save As',
keyText: 'Ctrl+Shift+S',
enabledStore: saveTabEnabledStore(editorStore),
onClick: () => saveTabFile(editorStore, true, folder, format, fileExtension),
testEnabled: () => getCurrentEditor() != null,
onClick: () => saveTabFile(getCurrentEditor(), true, folder, format, fileExtension),
});
if (execute) {
@ -148,11 +147,8 @@ export function registerFileCommands({
icon: 'icon run',
toolbar: true,
keyText: 'F5 | Ctrl+Enter',
enabledStore: derived(
[editorStore, editorStatusStore],
([editor, status]) => editor != null && !(status as any).busy
),
onClick: () => (get(editorStore) as any).execute(),
testEnabled: () => getCurrentEditor() != null && !getCurrentEditor()?.isBusy(),
onClick: () => getCurrentEditor().execute(),
});
registerCommand({
id: idPrefix + '.kill',
@ -160,11 +156,8 @@ export function registerFileCommands({
name: 'Kill',
icon: 'icon close',
toolbar: true,
enabledStore: derived(
[editorStore, editorStatusStore],
([query, status]) => query != null && status && (status as any).canKill
),
onClick: () => (get(editorStore) as any).kill(),
testEnabled: () => getCurrentEditor() != null && getCurrentEditor()?.canKill(),
onClick: () => getCurrentEditor().kill(),
});
}
@ -175,8 +168,8 @@ export function registerFileCommands({
name: 'Toggle comment',
keyText: 'Ctrl+/',
disableHandleKeyText: 'Ctrl+/',
enabledStore: derived(editorStore, query => query != null),
onClick: () => (get(editorStore) as any).toggleComment(),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().toggleComment(),
});
}
@ -186,16 +179,16 @@ export function registerFileCommands({
category,
name: 'Find',
keyText: 'Ctrl+F',
enabledStore: derived(editorStore, query => query != null),
onClick: () => (get(editorStore) as any).find(),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().find(),
});
registerCommand({
id: idPrefix + '.replace',
category,
keyText: 'Ctrl+H',
name: 'Replace',
enabledStore: derived(editorStore, query => query != null),
onClick: () => (get(editorStore) as any).replace(),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().replace(),
});
}
}

View File

@ -1,10 +1,7 @@
<script lang="ts" context="module">
const lastFocusedDataGrid = writable(null);
const currentDataGrid = derived([lastFocusedDataGrid, activeTabId], ([grid, tabid]) =>
grid?.getTabId && grid?.getTabId() == tabid ? grid : null
);
const currentDataGridChangeSet = memberStore(currentDataGrid, grid => grid?.getChangeSetStore() || nullStore);
let lastFocusedDataGrid = null;
const getCurrentDataGrid = () =>
lastFocusedDataGrid?.getTabId && lastFocusedDataGrid?.getTabId() == getActiveTabId() ? lastFocusedDataGrid : null;
registerCommand({
id: 'dataGrid.refresh',
@ -13,8 +10,8 @@
keyText: 'F5',
toolbar: true,
icon: 'icon reload',
enabledStore: derived(currentDataGrid, grid => grid?.getDisplay()?.supportsReload),
onClick: () => get(currentDataGrid).refresh(),
testEnabled: () => getCurrentDataGrid()?.getDisplay()?.supportsReload,
onClick: () => getCurrentDataGrid().refresh(),
});
registerCommand({
@ -24,11 +21,8 @@
keyText: 'Ctrl+S',
toolbar: true,
icon: 'icon save',
enabledStore: derived(
[currentDataGrid, currentDataGridChangeSet],
([grid, changeSet]) => grid?.getGeneralAllowSave() || changeSetContainsChanges((changeSet as any)?.value)
),
onClick: () => get(currentDataGrid).save(),
testEnabled: () => getCurrentDataGrid()?.getGrider()?.allowSave,
onClick: () => getCurrentDataGrid().save(),
});
registerCommand({
@ -36,16 +30,16 @@
category: 'Data grid',
name: 'Revert row changes',
keyText: 'Ctrl+R',
enabledStore: derived(currentDataGridChangeSet, (changeSet: any) => changeSetContainsChanges(changeSet?.value)),
onClick: () => get(currentDataGrid).revertRowChanges(),
testEnabled: () => getCurrentDataGrid()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataGrid().revertRowChanges(),
});
registerCommand({
id: 'dataGrid.revertAllChanges',
category: 'Data grid',
name: 'Revert all changes',
enabledStore: derived(currentDataGridChangeSet, (changeSet: any) => changeSetContainsChanges(changeSet?.value)),
onClick: () => get(currentDataGrid).revertAllChanges(),
testEnabled: () => getCurrentDataGrid()?.getGrider()?.containsChanges,
onClick: () => getCurrentDataGrid().revertAllChanges(),
});
registerCommand({
@ -53,8 +47,8 @@
category: 'Data grid',
name: 'Delete selected rows',
keyText: 'Ctrl+Delete',
enabledStore: derived(currentDataGrid, grid => grid?.getGrider()?.editable),
onClick: () => get(currentDataGrid).deleteSelectedRows(),
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
onClick: () => getCurrentDataGrid().deleteSelectedRows(),
});
registerCommand({
@ -62,8 +56,8 @@
category: 'Data grid',
name: 'Insert new row',
keyText: 'Insert',
enabledStore: derived(currentDataGrid, grid => grid?.getGrider()?.editable),
onClick: () => get(currentDataGrid).insertNewRow(),
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
onClick: () => getCurrentDataGrid().insertNewRow(),
});
registerCommand({
@ -71,8 +65,8 @@
category: 'Data grid',
name: 'Set NULL',
keyText: 'Ctrl+0',
enabledStore: derived(currentDataGrid, grid => grid?.getGrider()?.editable),
onClick: () => get(currentDataGrid).setNull(),
testEnabled: () => getCurrentDataGrid()?.getGrider()?.editable,
onClick: () => getCurrentDataGrid().setNull(),
});
registerCommand({
@ -82,8 +76,8 @@
keyText: 'Ctrl+Z',
icon: 'icon undo',
toolbar: true,
enabledStore: derived(currentDataGridChangeSet, (changeSet: any) => changeSet?.canUndo),
onClick: () => get(currentDataGrid).undo(),
testEnabled: () => getCurrentDataGrid()?.getGrider()?.canUndo,
onClick: () => getCurrentDataGrid().undo(),
});
registerCommand({
@ -91,16 +85,16 @@
category: 'Data grid',
name: 'Redo',
keyText: 'Ctrl+Y',
enabledStore: derived(currentDataGridChangeSet, (changeSet: any) => changeSet?.canRedo),
onClick: () => get(currentDataGrid).redo(),
testEnabled: () => getCurrentDataGrid()?.getGrider()?.canRedo,
onClick: () => getCurrentDataGrid().redo(),
});
registerCommand({
id: 'dataGrid.reconnect',
category: 'Data grid',
name: 'Reconnect',
enabledStore: derived(currentDataGrid, grid => grid != null),
onClick: () => get(currentDataGrid).reconnect(),
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().reconnect(),
});
registerCommand({
@ -108,8 +102,8 @@
category: 'Data grid',
name: 'Copy to clipboard',
keyText: 'Ctrl+C',
enabledStore: derived(currentDataGrid, grid => grid != null),
onClick: () => get(currentDataGrid).copyToClipboard(),
testEnabled: () => getCurrentDataGrid() != null,
onClick: () => getCurrentDataGrid().copyToClipboard(),
});
registerCommand({
@ -117,8 +111,8 @@
category: 'Data grid',
name: 'Export',
keyText: 'Ctrl+E',
enabledStore: derived(currentDataGrid, grid => grid != null && grid.exportEnabled()),
onClick: () => get(currentDataGrid).exportGrid(),
testEnabled: () => getCurrentDataGrid()?.exportEnabled(),
onClick: () => getCurrentDataGrid().exportGrid(),
});
function getRowCountInfo(selectedCells, grider, realColumnUniqueNames, selectedRowData, allRowCount) {
@ -175,10 +169,11 @@
import DataFilterControl from './DataFilterControl.svelte';
import createReducer from '../utility/createReducer';
import keycodes from '../utility/keycodes';
import { activeTabId, nullStore } from '../stores';
import { activeTabId, getActiveTabId, nullStore } from '../stores';
import memberStore from '../utility/memberStore';
import axiosInstance from '../utility/axiosInstance';
import { copyTextToClipboard } from '../utility/clipboard';
import invalidateCommands from '../commands/invalidateCommands';
export let onLoadNextData = undefined;
export let grider = undefined;
@ -198,7 +193,7 @@
export let isLoadedAll;
export let loadedTime;
export let changeSetStore;
export let generalAllowSave = false;
// export let generalAllowSave = false;
const wheelRowCount = 5;
const instance = get_current_component();
@ -330,9 +325,9 @@
}
}
export function getGeneralAllowSave() {
return generalAllowSave;
}
// export function getGeneralAllowSave() {
// return generalAllowSave;
// }
$: autofillMarkerCell =
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
@ -891,7 +886,8 @@
bind:this={domFocusField}
on:keydown={handleGridKeyDown}
on:focus={() => {
lastFocusedDataGrid.set(instance);
lastFocusedDataGrid = instance;
invalidateCommands();
}}
on:paste={handlePaste}
/>

View File

@ -1,5 +1,6 @@
import { writable, derived, readable } from 'svelte/store';
import { ExtensionsDirectory } from 'dbgate-types';
import invalidateCommands from './commands/invalidateCommands';
interface TabDefinition {
title: string;
@ -34,6 +35,7 @@ export const visibleCommandPalette = writable(false);
export const commands = writable({});
export const currentTheme = writableWithStorage('theme-light', 'currentTheme');
export const activeTabId = derived([openedTabs], ([$openedTabs]) => $openedTabs.find(x => x.selected)?.tabid);
export const visibleToolbar = writableWithStorage(1, 'visibleToolbar');
export const leftPanelWidth = writable(300);
export const currentDropDownMenu = writable(null);
@ -45,3 +47,31 @@ export const isFileDragActive = writable(false);
subscribeCssVariable(selectedWidget, x => (x ? 1 : 0), '--dim-visible-left-panel');
subscribeCssVariable(visibleToolbar, x => (x ? 1 : 0), '--dim-visible-toolbar');
subscribeCssVariable(leftPanelWidth, x => `${x}px`, '--dim-left-panel-width');
let activeTabIdValue = null;
activeTabId.subscribe(value => {
activeTabIdValue = value;
invalidateCommands();
});
export const getActiveTabId = () => activeTabIdValue;
let visibleCommandPaletteValue = null;
visibleCommandPalette.subscribe(value => {
visibleCommandPaletteValue = value;
invalidateCommands();
});
export const getVisibleCommandPalette = () => visibleCommandPaletteValue;
let visibleToolbarValue = null;
visibleToolbar.subscribe(value => {
visibleToolbarValue = value;
invalidateCommands();
});
export const getVisibleToolbar = () => visibleToolbarValue;
let openedTabsValue = null;
openedTabs.subscribe(value => {
openedTabsValue = value;
invalidateCommands();
});
export const getOpenedTabs = () => openedTabsValue;

View File

@ -65,7 +65,6 @@
modelState={$modelState}
{dispatchModel}
onSave={handleSave}
generalAllowSave
focusOnVisible
/>
{/if}

View File

@ -1,13 +1,12 @@
<script lang="ts" context="module">
const lastFocusedEditor = writable(null);
const currentEditor = derived([lastFocusedEditor, activeTabId], ([editor, tabid]) =>
editor?.getTabId && editor?.getTabId() == tabid ? editor : null
);
let lastFocusedEditor = null;
const getCurrentEditor = () =>
lastFocusedEditor?.getTabId && lastFocusedEditor?.getTabId() == getActiveTabId() ? lastFocusedEditor : null;
registerFileCommands({
idPrefix: 'markdown',
category: 'Markdown',
editorStore: currentEditor,
getCurrentEditor,
folder: 'markdown',
format: 'text',
fileExtension: 'md',
@ -23,8 +22,8 @@
icon: 'icon run',
toolbar: true,
keyText: 'F5 | Ctrl+Enter',
enabledStore: derived(currentEditor, query => query != null),
onClick: () => (get(currentEditor) as any).preview(),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().preview(),
});
</script>
@ -39,11 +38,12 @@
import AceEditor from '../query/AceEditor.svelte';
import RunnerOutputPane from '../query/RunnerOutputPane.svelte';
import useEditorData from '../query/useEditorData';
import { activeTabId, nullStore } from '../stores';
import { activeTabId, getActiveTabId, nullStore } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import memberStore from '../utility/memberStore';
import socket from '../utility/socket';
import useEffect from '../utility/useEffect';
import invalidateCommands from '../commands/invalidateCommands';
export let tabid;
@ -100,7 +100,10 @@
value={$editorState.value || ''}
menu={createMenu()}
on:input={e => setEditorData(e.detail)}
on:focus={() => lastFocusedEditor.set(instance)}
on:focus={() => {
lastFocusedEditor = instance;
invalidateCommands();
}}
bind:this={domEditor}
mode="markdown"
/>

View File

@ -1,22 +1,19 @@
<script lang="ts" context="module">
const lastFocusedEditor = writable(null);
const currentEditor = derived([lastFocusedEditor, activeTabId], ([editor, tabid]) =>
editor?.getTabId && editor?.getTabId() == tabid ? editor : null
);
const currentEditorStatus = memberStore(currentEditor, editor => editor?.getStatus() || nullStore);
let lastFocusedEditor = null;
const getCurrentEditor = () =>
lastFocusedEditor?.getTabId && lastFocusedEditor?.getTabId() == getActiveTabId() ? lastFocusedEditor : null;
registerCommand({
id: 'query.formatCode',
category: 'Query',
name: 'Format code',
enabledStore: derived(currentEditor, query => query != null),
onClick: () => get(currentEditor).formatCode(),
testEnabled: () => getCurrentEditor() != null,
onClick: () => getCurrentEditor().formatCode(),
});
registerFileCommands({
idPrefix: 'query',
category: 'Query',
editorStore: currentEditor,
editorStatusStore: currentEditorStatus,
getCurrentEditor,
folder: 'sql',
format: 'text',
fileExtension: 'sql',
@ -38,7 +35,7 @@
import VerticalSplitter from '../elements/VerticalSplitter.svelte';
import SqlEditor from '../query/SqlEditor.svelte';
import useEditorData from '../query/useEditorData';
import { activeTabId, extensions, nullStore } from '../stores';
import { activeTabId, extensions, getActiveTabId, nullStore } from '../stores';
import applySqlTemplate from '../utility/applySqlTemplate';
import axiosInstance from '../utility/axiosInstance';
import { changeTab } from '../utility/common';
@ -49,6 +46,7 @@
import useEffect from '../utility/useEffect';
import ResultTabs from '../query/ResultTabs.svelte';
import { registerFileCommands } from '../commands/stdCommands';
import invalidateCommands from '../commands/invalidateCommands';
export let tabid;
export let conid;
@ -65,11 +63,6 @@
let domEditor;
const status = writable({
busy,
canKill: false,
});
$: connection = useConnectionInfo({ conid });
$: effect = useEffect(() => {
@ -91,16 +84,23 @@
}
$: {
status.set({
busy,
canKill: !!sessionId,
});
busy;
sessionId;
invalidateCommands();
}
$: if ($tabVisible && domEditor) {
domEditor?.getEditor()?.focus();
}
export function canKill() {
return !!sessionId;
}
export function isBusy() {
return busy;
}
export function getTabId() {
return tabid;
}
@ -137,9 +137,9 @@
// timerLabel.stop();
}
export function getStatus() {
return status;
}
// export function getStatus() {
// return status;
// }
export function getData() {
return $editorState.value || '';
@ -207,7 +207,7 @@
value={$editorState.value || ''}
menu={createMenu()}
on:input={e => setEditorData(e.detail)}
on:focus={() => lastFocusedEditor.set(instance)}
on:focus={() => {lastFocusedEditor = instance; invalidateCommands(); }}
bind:this={domEditor}
/>
</svelte:fragment>

View File

@ -1,15 +1,12 @@
<script lang="ts" context="module">
const lastFocusedEditor = writable(null);
const currentEditor = derived([lastFocusedEditor, activeTabId], ([editor, tabid]) =>
editor?.getTabId && editor?.getTabId() == tabid ? editor : null
);
const currentEditorStatus = memberStore(currentEditor, editor => editor?.getStatus() || nullStore);
let lastFocusedEditor = null;
const getCurrentEditor = () =>
lastFocusedEditor?.getTabId && lastFocusedEditor?.getTabId() == getActiveTabId() ? lastFocusedEditor : null;
registerFileCommands({
idPrefix: 'shell',
category: 'Shell',
editorStore: currentEditor,
editorStatusStore: currentEditorStatus,
getCurrentEditor,
folder: 'shell',
format: 'text',
fileExtension: 'js',
@ -28,6 +25,7 @@
import { getContext, get_current_component } from 'svelte/internal';
import { derived, writable } from 'svelte/store';
import invalidateCommands from '../commands/invalidateCommands';
import registerCommand from '../commands/registerCommand';
import { registerFileCommands } from '../commands/stdCommands';
@ -35,7 +33,7 @@
import AceEditor from '../query/AceEditor.svelte';
import RunnerOutputPane from '../query/RunnerOutputPane.svelte';
import useEditorData from '../query/useEditorData';
import { activeTabId, nullStore } from '../stores';
import { activeTabId, getActiveTabId, nullStore } from '../stores';
import axiosInstance from '../utility/axiosInstance';
import memberStore from '../utility/memberStore';
import socket from '../utility/socket';
@ -54,16 +52,21 @@
let domEditor;
const status = writable({
busy,
canKill: false,
});
// const status = writable({
// busy,
// canKill: false,
// });
// $: {
// status.set({
// busy,
// canKill: busy,
// });
// }
$: {
status.set({
busy,
canKill: busy,
});
busy;
invalidateCommands();
}
$: if ($tabVisible && domEditor) {
@ -90,9 +93,9 @@
// timerLabel.stop();
}
export function getStatus() {
return status;
}
// export function getStatus() {
// return status;
// }
export function getData() {
return $editorState.value || '';
@ -114,6 +117,10 @@
return tabid;
}
export function isBusy() {
return busy;
}
export async function execute() {
if (busy) return;
executeNumber += 1;
@ -165,7 +172,10 @@
value={$editorState.value || ''}
menu={createMenu()}
on:input={e => setEditorData(e.detail)}
on:focus={() => lastFocusedEditor.set(instance)}
on:focus={() => {
lastFocusedEditor = instance;
invalidateCommands();
}}
bind:this={domEditor}
mode="javascript"
/>

View File

@ -17,6 +17,7 @@
import { findEngineDriver } from 'dbgate-tools';
import { writable } from 'svelte/store';
import createUndoReducer from '../utility/createUndoReducer';
import invalidateCommands from '../commands/invalidateCommands';
export let tabid;
export let conid;
@ -28,6 +29,11 @@
const cache = writable(createGridCache());
const [changeSetStore, dispatchChangeSet] = createUndoReducer(createChangeSet());
$: {
$changeSetStore;
invalidateCommands();
}
</script>
<TableDataGrid

View File

@ -6,12 +6,11 @@ import { changeTab } from './common';
import SaveFileModal from '../modals/SaveFileModal.svelte';
import registerCommand from '../commands/registerCommand';
export function saveTabEnabledStore(editorStore) {
return derived(editorStore, editor => editor != null);
}
// export function saveTabEnabledStore(editorStore) {
// return derived(editorStore, editor => editor != null);
// }
export default function saveTabFile(editorStore, saveAs, folder, format, fileExtension) {
const editor: any = get(editorStore);
export default function saveTabFile(editor, saveAs, folder, format, fileExtension) {
const tabs = get(openedTabs);
const tabid = editor.getTabId();
const data = editor.getData();

View File

@ -23,7 +23,7 @@
category: 'Tabs',
name: 'Next tab',
keyText: 'Ctrl+Tab',
enabledStore: derived(openedTabs, tabs => tabs.filter(x => !x.closedTime).length >= 2),
testEnabled: () => getOpenedTabs().filter(x => !x.closedTime).length >= 2,
onClick: () => {
const tabs = get(openedTabs).filter(x => x.closedTime == null);
if (tabs.length >= 2) setSelectedTab(tabs[tabs.length - 2].tabid);
@ -37,7 +37,7 @@
import registerCommand from '../commands/registerCommand';
import FontIcon from '../icons/FontIcon.svelte';
import { currentDatabase, openedTabs } from '../stores';
import { currentDatabase, getOpenedTabs, openedTabs } from '../stores';
import { setSelectedTab } from '../utility/common';
import contextMenu from '../utility/contextMenu';