From d619e0f9614e31e3601cab0ade70283176ed62ae Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 19 Nov 2024 14:10:41 +0100 Subject: [PATCH 01/25] tab preview mode - basic concept #767 --- .../src/appobj/DatabaseObjectAppObject.svelte | 14 +++++++++----- packages/web/src/stores.ts | 1 + packages/web/src/tabpanel/TabsPanel.svelte | 16 ++++++++++++++++ packages/web/src/utility/common.ts | 6 ++++-- packages/web/src/utility/openNewTab.ts | 11 +++++++++-- 5 files changed, 39 insertions(+), 9 deletions(-) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index f0de19506..0465b5f35 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -701,7 +701,8 @@ forceNewTab?, initialData?, icon?, - appObjectData? + appObjectData?, + preventPreviewMode? ) { const connection = await getConnectionInfo({ conid }); const tooltip = `${getConnectionLabel(connection)}\n${database}\n${fullDisplayName({ @@ -717,6 +718,7 @@ tabComponent: scriptTemplate ? 'QueryTab' : tabComponent, appObject: 'DatabaseObjectAppObject', appObjectData, + tabPreviewMode: !preventPreviewMode, props: { schemaName, pureName, @@ -731,7 +733,7 @@ ); } - export function handleDatabaseObjectClick(data, forceNewTab = false) { + export function handleDatabaseObjectClick(data, forceNewTab = false, preventPreviewMode = false) { const { schemaName, pureName, conid, database, objectTypeField } = data; const driver = findEngineDriver(data, getExtensions()); @@ -755,7 +757,8 @@ forceNewTab, null, null, - data + data, + preventPreviewMode ); } @@ -881,8 +884,8 @@ export let data; export let passProps; - function handleClick(forceNewTab = false) { - handleDatabaseObjectClick(data, forceNewTab); + function handleClick(forceNewTab = false, preventPreviewMode = false) { + handleDatabaseObjectClick(data, forceNewTab, preventPreviewMode); } function createMenu() { @@ -917,6 +920,7 @@ extInfo={getExtInfo(data)} on:click={() => handleClick()} on:middleclick={() => handleClick(true)} + on:dblclick={() => handleClick(false, true)} on:expand on:dragstart on:dragenter diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index 9d2ca81f6..cb2d8fabb 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -22,6 +22,7 @@ export interface TabDefinition { tabOrder?: number; multiTabIndex?: number; unsaved?: boolean; + tabPreviewMode?: boolean; } export function writableWithStorage(defaultValue: T, storageName) { diff --git a/packages/web/src/tabpanel/TabsPanel.svelte b/packages/web/src/tabpanel/TabsPanel.svelte index 2ab5a20be..684e7c3af 100644 --- a/packages/web/src/tabpanel/TabsPanel.svelte +++ b/packages/web/src/tabpanel/TabsPanel.svelte @@ -349,6 +349,17 @@ } }; + const handleDoubleClick = (e, tabid) => { + e.preventDefault(); + + openedTabs.update(tabs => + tabs.map(x => ({ + ...x, + tabPreviewMode: x.tabid == tabid ? false : x.tabPreviewMode, + })) + ); + }; + const getContextMenu = tab => () => { const { tabid, props, tabComponent, appObject, appObjectData } = tab; @@ -568,9 +579,11 @@ class:selected={$draggingTab || $draggingDbGroup ? tab.tabid == $draggingTabTarget?.tabid : tab.tabid == shownTab?.tabid} + class:preview={!!tab.tabPreviewMode} on:click={e => handleTabClick(e, tab.tabid)} on:mousedown={e => handleMouseDown(e, tab.tabid)} on:mouseup={e => handleMouseUp(e, tab.tabid)} + on:dblclick={e => handleDoubleClick(e, tab.tabid)} use:contextMenu={getContextMenu(tab)} draggable={true} on:dragstart={async e => { @@ -714,6 +727,9 @@ .file-tab-item.selected { background-color: var(--theme-bg-0); } + .file-tab-item.preview { + font-style: italic; + } .file-name { margin-left: 5px; white-space: nowrap; diff --git a/packages/web/src/utility/common.ts b/packages/web/src/utility/common.ts index 1d3cb7af8..08f61ca36 100644 --- a/packages/web/src/utility/common.ts +++ b/packages/web/src/utility/common.ts @@ -30,10 +30,12 @@ export function markTabSaved(tabid) { openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? { ...tab, unsaved: false } : tab))); } -export function setSelectedTabFunc(files, tabid) { +export function setSelectedTabFunc(files, tabid, previewModeValue = undefined) { return [ ...(files || []).filter(x => x.tabid != tabid).map(x => ({ ...x, selected: false })), - ...(files || []).filter(x => x.tabid == tabid).map(x => ({ ...x, selected: true })), + ...(files || []) + .filter(x => x.tabid == tabid) + .map(x => ({ ...x, selected: true, tabPreviewMode: previewModeValue ?? x.tabPreviewMode })), ]; } diff --git a/packages/web/src/utility/openNewTab.ts b/packages/web/src/utility/openNewTab.ts index fd40141e9..7581ac7f9 100644 --- a/packages/web/src/utility/openNewTab.ts +++ b/packages/web/src/utility/openNewTab.ts @@ -22,6 +22,7 @@ export default async function openNewTab(newTab, initialData: any = undefined, o let existing = null; const { savedFile, savedFolder, savedFilePath } = newTab.props || {}; + const { tabPreviewMode } = newTab; if (savedFile || savedFilePath) { existing = oldTabs.find( x => @@ -49,7 +50,7 @@ export default async function openNewTab(newTab, initialData: any = undefined, o } if (existing) { - openedTabs.update(tabs => setSelectedTabFunc(tabs, existing.tabid)); + openedTabs.update(tabs => setSelectedTabFunc(tabs, existing.tabid, !tabPreviewMode ? false : undefined)); return; } @@ -92,8 +93,14 @@ export default async function openNewTab(newTab, initialData: any = undefined, o items.push(newItem); } + const filesFiltered = tabPreviewMode ? (files || []).filter(x => !x.tabPreviewMode) : files; + return [ - ...(files || []).map(x => ({ ...x, selected: false, tabOrder: _.findIndex(items, y => y.tabid == x.tabid) })), + ...(filesFiltered || []).map(x => ({ + ...x, + selected: false, + tabOrder: _.findIndex(items, y => y.tabid == x.tabid), + })), { ...newTab, tabid, From 90946c582d883b8487ab3ba76b0c2b3ca4019b73 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 19 Nov 2024 14:13:58 +0100 Subject: [PATCH 02/25] don't focus in tabs --- packages/web/src/tabs/ArchiveFileTab.svelte | 1 - packages/web/src/tabs/CollectionDataTab.svelte | 1 - packages/web/src/tabs/QueryDataTab.svelte | 2 +- packages/web/src/tabs/TableDataTab.svelte | 1 - packages/web/src/tabs/ViewDataTab.svelte | 1 - 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/web/src/tabs/ArchiveFileTab.svelte b/packages/web/src/tabs/ArchiveFileTab.svelte index 74e6d1579..ed48ba5f1 100644 --- a/packages/web/src/tabs/ArchiveFileTab.svelte +++ b/packages/web/src/tabs/ArchiveFileTab.svelte @@ -170,7 +170,6 @@ supportsReload allowChangeChangeSetStructure changeSetState={$changeSetStore} - focusOnVisible {changeSetStore} {dispatchChangeSet} {infoLoadCounter} diff --git a/packages/web/src/tabs/CollectionDataTab.svelte b/packages/web/src/tabs/CollectionDataTab.svelte index 03f9fa85d..e0ecfe592 100644 --- a/packages/web/src/tabs/CollectionDataTab.svelte +++ b/packages/web/src/tabs/CollectionDataTab.svelte @@ -191,7 +191,6 @@ cache={$cache} setCache={cache.update} changeSetState={$changeSetStore} - focusOnVisible {display} {changeSetStore} {dispatchChangeSet} diff --git a/packages/web/src/tabs/QueryDataTab.svelte b/packages/web/src/tabs/QueryDataTab.svelte index 227414ec6..6b3544694 100644 --- a/packages/web/src/tabs/QueryDataTab.svelte +++ b/packages/web/src/tabs/QueryDataTab.svelte @@ -100,7 +100,7 @@ {#if jslid} - + {:else} {/if} diff --git a/packages/web/src/tabs/TableDataTab.svelte b/packages/web/src/tabs/TableDataTab.svelte index 83a6f13df..45609a852 100644 --- a/packages/web/src/tabs/TableDataTab.svelte +++ b/packages/web/src/tabs/TableDataTab.svelte @@ -255,7 +255,6 @@ cache={$cache} setCache={cache.update} changeSetState={$changeSetStore} - focusOnVisible {changeSetStore} {dispatchChangeSet} /> diff --git a/packages/web/src/tabs/ViewDataTab.svelte b/packages/web/src/tabs/ViewDataTab.svelte index a5fb401db..95d04e72a 100644 --- a/packages/web/src/tabs/ViewDataTab.svelte +++ b/packages/web/src/tabs/ViewDataTab.svelte @@ -68,7 +68,6 @@ setConfig={config.update} cache={$cache} setCache={cache.update} - focusOnVisible hasMultiColumnFilter gridCoreComponent={SqlDataGridCore} formViewComponent={SqlFormView} From af17eceb27d346e929fece47303ac242c78a2bd1 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 19 Nov 2024 15:54:18 +0100 Subject: [PATCH 03/25] table keyboard navigation WIP --- packages/web/src/appobj/AppObjectCore.svelte | 6 +++ .../web/src/appobj/DatabaseAppObject.svelte | 6 +-- .../src/appobj/DatabaseObjectAppObject.svelte | 4 ++ packages/web/src/appobj/appObjectMatchers.ts | 9 ++++ packages/web/src/stores.ts | 8 ++++ .../src/widgets/AppObjectListHandler.svelte | 37 +++++++++++++++ packages/web/src/widgets/SqlObjectList.svelte | 46 +++++++++++++------ 7 files changed, 98 insertions(+), 18 deletions(-) create mode 100644 packages/web/src/appobj/appObjectMatchers.ts create mode 100644 packages/web/src/widgets/AppObjectListHandler.svelte diff --git a/packages/web/src/appobj/AppObjectCore.svelte b/packages/web/src/appobj/AppObjectCore.svelte index 02ed23eaa..c008f0e20 100644 --- a/packages/web/src/appobj/AppObjectCore.svelte +++ b/packages/web/src/appobj/AppObjectCore.svelte @@ -66,6 +66,11 @@ } // $: console.log(title, indentLevel); + let domDiv; + + $: if (isBold && domDiv) { + domDiv.scrollIntoView({ block: 'nearest', inline: 'nearest' }); + }
{#if checkedObjectsStore} switchCurrentDatabase(data)} on:dragstart on:dragenter diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index 0465b5f35..59d287a13 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -853,6 +853,7 @@ getExtensions, openedConnections, pinnedTables, + selectedDatabaseObjectAppObject, } from '../stores'; import openNewTab from '../utility/openNewTab'; import { @@ -880,11 +881,13 @@ import { getDefaultFileFormat } from '../plugins/fileformats'; import hasPermission from '../utility/hasPermission'; import { openImportExportTab } from '../utility/importExportTools'; + import { matchDatabaseObjectAppObject } from './appObjectMatchers'; export let data; export let passProps; function handleClick(forceNewTab = false, preventPreviewMode = false) { + $selectedDatabaseObjectAppObject = data; handleDatabaseObjectClick(data, forceNewTab, preventPreviewMode); } @@ -918,6 +921,7 @@ onPin={isPinned ? null : () => pinnedTables.update(list => [...list, data])} onUnpin={isPinned ? () => pinnedTables.update(list => list.filter(x => !testEqual(x, data))) : null} extInfo={getExtInfo(data)} + isBold={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)} on:click={() => handleClick()} on:middleclick={() => handleClick(true)} on:dblclick={() => handleClick(false, true)} diff --git a/packages/web/src/appobj/appObjectMatchers.ts b/packages/web/src/appobj/appObjectMatchers.ts new file mode 100644 index 000000000..12daa26d8 --- /dev/null +++ b/packages/web/src/appobj/appObjectMatchers.ts @@ -0,0 +1,9 @@ +export function matchDatabaseObjectAppObject(obj1, obj2) { + return ( + obj1?.objectTypeField == obj2?.objectTypeField && + obj1?.conid == obj2?.conid && + obj1?.database == obj2?.database && + obj1?.pureName == obj2?.pureName && + obj1?.schemaName == obj2?.schemaName + ); +} diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index cb2d8fabb..847b6168c 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -153,6 +153,8 @@ export const activeDbKeysStore = writableWithStorage({}, 'activeDbKeysStore'); export const appliedCurrentSchema = writable(null); export const loadingSchemaLists = writable({}); // dict [`${conid}::${database}`]: true +export const selectedDatabaseObjectAppObject = writable(null); + export const currentThemeDefinition = derived([currentTheme, extensions], ([$currentTheme, $extensions]) => $extensions.themes.find(x => x.themeClassName == $currentTheme) ); @@ -321,3 +323,9 @@ appliedCurrentSchema.subscribe(value => { appliedCurrentSchemaValue = value; }); export const getAppliedCurrentSchema = () => appliedCurrentSchemaValue; + +let selectedDatabaseObjectAppObjectValue = null; +selectedDatabaseObjectAppObject.subscribe(value => { + selectedDatabaseObjectAppObjectValue = value; +}); +export const getSelectedDatabaseObjectAppObject = () => selectedDatabaseObjectAppObjectValue; \ No newline at end of file diff --git a/packages/web/src/widgets/AppObjectListHandler.svelte b/packages/web/src/widgets/AppObjectListHandler.svelte new file mode 100644 index 000000000..555f5679b --- /dev/null +++ b/packages/web/src/widgets/AppObjectListHandler.svelte @@ -0,0 +1,37 @@ + + +
+ +
+ + diff --git a/packages/web/src/widgets/SqlObjectList.svelte b/packages/web/src/widgets/SqlObjectList.svelte index 8704e94b7..59a9a030a 100644 --- a/packages/web/src/widgets/SqlObjectList.svelte +++ b/packages/web/src/widgets/SqlObjectList.svelte @@ -36,13 +36,20 @@ import FontIcon from '../icons/FontIcon.svelte'; import CloseSearchButton from '../buttons/CloseSearchButton.svelte'; import { findEngineDriver } from 'dbgate-tools'; - import { currentDatabase, extensions } from '../stores'; + import { + currentDatabase, + extensions, + getSelectedDatabaseObjectAppObject, + selectedDatabaseObjectAppObject, + } from '../stores'; import newQuery from '../query/newQuery'; import runCommand from '../commands/runCommand'; import { apiCall } from '../utility/api'; import { filterAppsForDatabase } from '../utility/appTools'; import SchemaSelector from './SchemaSelector.svelte'; import { appliedCurrentSchema } from '../stores'; + import AppObjectListHandler from './AppObjectListHandler.svelte'; + import { matchDatabaseObjectAppObject } from '../appobj/appObjectMatchers'; export let conid; export let database; @@ -172,23 +179,32 @@ {#if ($status && ($status.name == 'pending' || $status.name == 'checkStructure' || $status.name == 'loadStructure') && $objects) || !$objects} {:else} - ($appliedCurrentSchema ? x.schemaName == $appliedCurrentSchema : true)) .map(x => ({ ...x, conid, database }))} - module={databaseObjectAppObject} - groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)} - subItemsComponent={SubColumnParamList} - isExpandable={data => - data.objectTypeField == 'tables' || data.objectTypeField == 'views' || data.objectTypeField == 'matviews'} - expandIconFunc={chevronExpandIcon} - {filter} - passProps={{ - showPinnedInsteadOfUnpin: true, - connection: $connection, - hideSchemaName: !!$appliedCurrentSchema, - }} - /> + selectedObjectStore={selectedDatabaseObjectAppObject} + getSelectedObject={getSelectedDatabaseObjectAppObject} + selectedObjectMatcher={matchDatabaseObjectAppObject} + > + ($appliedCurrentSchema ? x.schemaName == $appliedCurrentSchema : true)) + .map(x => ({ ...x, conid, database }))} + module={databaseObjectAppObject} + groupFunc={data => getObjectTypeFieldLabel(data.objectTypeField, driver)} + subItemsComponent={SubColumnParamList} + isExpandable={data => + data.objectTypeField == 'tables' || data.objectTypeField == 'views' || data.objectTypeField == 'matviews'} + expandIconFunc={chevronExpandIcon} + {filter} + passProps={{ + showPinnedInsteadOfUnpin: true, + connection: $connection, + hideSchemaName: !!$appliedCurrentSchema, + }} + /> + {/if} {/if} From 598674a7e08e033171709b9817d3abf5950dbeb6 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Tue, 19 Nov 2024 16:35:55 +0100 Subject: [PATCH 04/25] show focus in data grid --- packages/web/src/datagrid/ColumnManager.svelte | 7 +++++++ packages/web/src/datagrid/ColumnManagerRow.svelte | 7 +++++++ packages/web/src/datagrid/DataGridCell.svelte | 3 +++ packages/web/src/datagrid/DataGridCore.svelte | 10 ++++++++-- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/web/src/datagrid/ColumnManager.svelte b/packages/web/src/datagrid/ColumnManager.svelte index d6ff99ecd..ee889e90e 100644 --- a/packages/web/src/datagrid/ColumnManager.svelte +++ b/packages/web/src/datagrid/ColumnManager.svelte @@ -142,6 +142,8 @@ }, }); } + + let isColumnManagerFocused = false; {#if allowChangeChangeSetStructure} @@ -207,9 +209,13 @@ bind:this={domFocusField} on:keydown={handleKeyDown} on:focus={() => { + isColumnManagerFocused = true; // activator.activate(); // invalidateCommands(); }} + on:blur={() => { + isColumnManagerFocused = false; + }} on:copy={copyToClipboard} /> @@ -224,6 +230,7 @@ {database} {tableInfo} {setTableInfo} + {isColumnManagerFocused} columnInfo={tableInfo?.columns?.[columnIndex]} {columnIndex} {allowChangeChangeSetStructure} diff --git a/packages/web/src/datagrid/ColumnManagerRow.svelte b/packages/web/src/datagrid/ColumnManagerRow.svelte index 5ec95caf2..864f6c60d 100644 --- a/packages/web/src/datagrid/ColumnManagerRow.svelte +++ b/packages/web/src/datagrid/ColumnManagerRow.svelte @@ -22,6 +22,8 @@ export let columnInfo = null; export let columnIndex = -1; + export let isColumnManagerFocused = false; + export let allowChangeChangeSetStructure = false; $: addDataCommand = allowChangeChangeSetStructure; @@ -49,6 +51,7 @@ else display.focusColumns([column.uniqueName]); }} class:isSelected + class:isFocused={isColumnManagerFocused} on:click on:mousedown on:mousemove @@ -123,6 +126,10 @@ } .row.isSelected { + background: var(--theme-bg-3); + } + + .row.isSelected.isFocused { background: var(--theme-bg-selected); } diff --git a/packages/web/src/datagrid/DataGridCell.svelte b/packages/web/src/datagrid/DataGridCell.svelte index 657d9f39b..12100ddbb 100644 --- a/packages/web/src/datagrid/DataGridCell.svelte +++ b/packages/web/src/datagrid/DataGridCell.svelte @@ -173,6 +173,9 @@ background: var(--theme-bg-volcano); } td.isSelected { + background: var(--theme-bg-3); + } + :global(.data-grid-focused) td.isSelected { background: var(--theme-bg-selected); } td.isDeleted { diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index d5b54d698..3010f74db 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -492,6 +492,8 @@ let autofillSelectedCells = emptyCellArray; const domFilterControlsRef = createRef({}); + let isGridFocused=false; + const tabid = getContext('tabid'); let unsubscribeDbRefresh; @@ -1041,7 +1043,6 @@ return !hideGridLeftColumn; } - $: autofillMarkerCell = selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1 ? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))] @@ -1863,6 +1864,7 @@ {:else}
{ activator.activate(); invalidateCommands(); + isGridFocused = true; }} + on:blur on:paste={handlePaste} on:copy={copyToClipboard} - on:blur={handleBlur} + on:blur={() => { + isGridFocused = false; + }} /> Date: Wed, 20 Nov 2024 08:16:13 +0100 Subject: [PATCH 05/25] dbappobj highlight --- packages/web/src/appobj/AppObjectCore.svelte | 12 ++++++++++++ .../web/src/appobj/DatabaseObjectAppObject.svelte | 2 +- .../web/src/widgets/AppObjectListHandler.svelte | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/web/src/appobj/AppObjectCore.svelte b/packages/web/src/appobj/AppObjectCore.svelte index c008f0e20..de91a73e2 100644 --- a/packages/web/src/appobj/AppObjectCore.svelte +++ b/packages/web/src/appobj/AppObjectCore.svelte @@ -14,6 +14,7 @@ export let module = null; export let isBold = false; + export let isChoosed = false; export let isBusy = false; export let statusIcon = undefined; export let statusIconBefore = undefined; @@ -71,11 +72,16 @@ $: if (isBold && domDiv) { domDiv.scrollIntoView({ block: 'nearest', inline: 'nearest' }); } + + $: if (isChoosed && domDiv) { + domDiv.scrollIntoView({ block: 'nearest', inline: 'nearest' }); + }
pinnedTables.update(list => [...list, data])} onUnpin={isPinned ? () => pinnedTables.update(list => list.filter(x => !testEqual(x, data))) : null} extInfo={getExtInfo(data)} - isBold={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)} + isChoosed={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)} on:click={() => handleClick()} on:middleclick={() => handleClick(true)} on:dblclick={() => handleClick(false, true)} diff --git a/packages/web/src/widgets/AppObjectListHandler.svelte b/packages/web/src/widgets/AppObjectListHandler.svelte index 555f5679b..398940997 100644 --- a/packages/web/src/widgets/AppObjectListHandler.svelte +++ b/packages/web/src/widgets/AppObjectListHandler.svelte @@ -7,6 +7,8 @@ export let getSelectedObject; export let selectedObjectMatcher; + let isListFocused = false; + function handleKeyDown(ev) { function selectByDiff(diff) { const selected = getSelectedObject(); @@ -26,7 +28,18 @@ } -
+
{ + isListFocused = true; + }} + on:blur={() => { + isListFocused = false; + }} +>
From 794f43d9ae22bd10b0d94a86dc012fbecdba2662 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 20 Nov 2024 11:25:07 +0100 Subject: [PATCH 06/25] call click when changing table by arrow --- packages/web/src/appobj/DatabaseObjectAppObject.svelte | 4 ++++ packages/web/src/widgets/AppObjectListHandler.svelte | 2 ++ packages/web/src/widgets/SqlObjectList.svelte | 1 + 3 files changed, 7 insertions(+) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index bb1e9c65f..765c874f4 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -841,6 +841,10 @@ export function createAppObjectMenu(data) { return createDatabaseObjectMenu(data); } + + export function handleObjectClick(data, forceNewTab = false, preventPreviewMode = false) { + return handleDatabaseObjectClick(data, forceNewTab, preventPreviewMode); + } + + + +{#await applyScriptTemplate(scriptTemplate, $extensions, appObjectData)} + +{:then sql} + { + activator.activate(); + domToolStrip?.activate(); + invalidateCommands(); + }} + bind:this={domEditor} + mode={driver?.editorMode || 'sql'} + /> +{/await} diff --git a/packages/web/src/tabs/index.js b/packages/web/src/tabs/index.js index 2e35ac00e..7ae3b90aa 100644 --- a/packages/web/src/tabs/index.js +++ b/packages/web/src/tabs/index.js @@ -28,6 +28,7 @@ import * as ServerSummaryTab from './ServerSummaryTab.svelte'; import * as ProfilerTab from './ProfilerTab.svelte'; import * as DataDuplicatorTab from './DataDuplicatorTab.svelte'; import * as ImportExportTab from './ImportExportTab.svelte'; +import * as SqlObjectTab from './SqlObjectTab.svelte'; import protabs from './index-pro'; @@ -62,5 +63,6 @@ export default { ProfilerTab, DataDuplicatorTab, ImportExportTab, + SqlObjectTab, ...protabs, }; From aeb81bd97f64f53ae0377385e83005bf05259826 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 20 Nov 2024 14:33:05 +0100 Subject: [PATCH 09/25] sql object tab - ability to show template --- packages/web/src/tabs/SqlObjectTab.svelte | 53 ++++++++++++++++------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/packages/web/src/tabs/SqlObjectTab.svelte b/packages/web/src/tabs/SqlObjectTab.svelte index 8c17026cc..cbb03c674 100644 --- a/packages/web/src/tabs/SqlObjectTab.svelte +++ b/packages/web/src/tabs/SqlObjectTab.svelte @@ -24,11 +24,15 @@ import registerCommand from '../commands/registerCommand'; import applyScriptTemplate, { getSupportedScriptTemplates } from '../utility/applyScriptTemplate'; import LoadingInfo from '../elements/LoadingInfo.svelte'; + import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte'; + import SelectField from '../forms/SelectField.svelte'; export let tabid; export let appObjectData; + export let initialScriptTemplate; - let scriptTemplate = getSupportedScriptTemplates(appObjectData.objectTypeField)?.[0]?.scriptTemplate; + let scriptTemplate = + initialScriptTemplate ?? getSupportedScriptTemplates(appObjectData.objectTypeField)?.[0]?.scriptTemplate; $: connection = useConnectionInfo({ conid: appObjectData.conid }); $: driver = findEngineDriver($connection, $extensions); @@ -53,18 +57,35 @@ } -{#await applyScriptTemplate(scriptTemplate, $extensions, appObjectData)} - -{:then sql} - { - activator.activate(); - domToolStrip?.activate(); - invalidateCommands(); - }} - bind:this={domEditor} - mode={driver?.editorMode || 'sql'} - /> -{/await} + + {#await applyScriptTemplate(scriptTemplate, $extensions, appObjectData)} + + {:then sql} + { + activator.activate(); + domToolStrip?.activate(); + invalidateCommands(); + }} + bind:this={domEditor} + mode={driver?.editorMode || 'sql'} + /> + {/await} + + + + ({ + label: x.label, + value: x.scriptTemplate, + }))} + on:change={e => { + scriptTemplate = e.detail; + }} + /> + + From 18de37c4e4d2d21f0564cf9d9a47318f76f4d911 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 20 Nov 2024 14:53:06 +0100 Subject: [PATCH 10/25] sql object tab --- packages/web/src/tabs/SqlObjectTab.svelte | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/web/src/tabs/SqlObjectTab.svelte b/packages/web/src/tabs/SqlObjectTab.svelte index cbb03c674..57cffea99 100644 --- a/packages/web/src/tabs/SqlObjectTab.svelte +++ b/packages/web/src/tabs/SqlObjectTab.svelte @@ -26,13 +26,13 @@ import LoadingInfo from '../elements/LoadingInfo.svelte'; import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte'; import SelectField from '../forms/SelectField.svelte'; + import { changeTab } from '../utility/common'; export let tabid; export let appObjectData; - export let initialScriptTemplate; + export let scriptTemplate; - let scriptTemplate = - initialScriptTemplate ?? getSupportedScriptTemplates(appObjectData.objectTypeField)?.[0]?.scriptTemplate; + $: defaultScriptTemplate = getSupportedScriptTemplates(appObjectData.objectTypeField)?.[0]?.scriptTemplate; $: connection = useConnectionInfo({ conid: appObjectData.conid }); $: driver = findEngineDriver($connection, $extensions); @@ -58,11 +58,12 @@ - {#await applyScriptTemplate(scriptTemplate, $extensions, appObjectData)} + {#await applyScriptTemplate(scriptTemplate ?? defaultScriptTemplate, $extensions, appObjectData)} {:then sql} { activator.activate(); @@ -75,16 +76,21 @@ {/await} - ({ label: x.label, value: x.scriptTemplate, }))} on:change={e => { - scriptTemplate = e.detail; + changeTab(tabid, tab => ({ + ...tab, + props: { + ...tab.props, + scriptTemplate: e.detail, + }, + })); }} /> From 788ea70d3228703f02956d90a7275fb509e7a566 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 20 Nov 2024 15:30:47 +0100 Subject: [PATCH 11/25] db app objc refactors --- .../src/appobj/DatabaseObjectAppObject.svelte | 178 ++++++++++-------- .../src/widgets/AppObjectListHandler.svelte | 2 +- 2 files changed, 104 insertions(+), 76 deletions(-) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index 27268236b..3e31c2ec8 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -38,10 +38,7 @@ }; } - function createMenusCore( - objectTypeField, - driver - ): { + interface DbObjMenuItem { label?: string; tab?: string; forceNewTab?: boolean; @@ -66,7 +63,10 @@ isDropCollection?: boolean; isRenameCollection?: boolean; isDuplicateCollection?: boolean; - }[] { + submenu?: DbObjMenuItem[]; + } + + function createMenusCore(objectTypeField, driver): DbObjMenuItem[] { switch (objectTypeField) { case 'tables': return [ @@ -159,25 +159,30 @@ }, createScriptTemplatesSubmenu('tables'), { - label: 'SQL Generator: CREATE TABLE', - sqlGeneratorProps: { - createTables: true, - createIndexes: true, - createForeignKeys: true, - }, - }, - { - label: 'SQL Generator: DROP TABLE', - sqlGeneratorProps: { - dropTables: true, - dropReferences: true, - }, - }, - { - label: 'SQL Generator: INSERT', - sqlGeneratorProps: { - insert: true, - }, + label: 'SQL generator', + submenu: [ + { + label: 'CREATE TABLE', + sqlGeneratorProps: { + createTables: true, + createIndexes: true, + createForeignKeys: true, + }, + }, + { + label: 'DROP TABLE', + sqlGeneratorProps: { + dropTables: true, + dropReferences: true, + }, + }, + { + label: 'INSERT', + sqlGeneratorProps: { + insert: true, + }, + }, + ], }, ]; case 'views': @@ -233,16 +238,21 @@ }, createScriptTemplatesSubmenu('views'), { - label: 'SQL Generator: CREATE VIEW', - sqlGeneratorProps: { - createViews: true, - }, - }, - { - label: 'SQL Generator: DROP VIEW', - sqlGeneratorProps: { - dropViews: true, - }, + label: 'SQL generator', + submenu: [ + { + label: 'CREATE VIEW', + sqlGeneratorProps: { + createViews: true, + }, + }, + { + label: 'DROP VIEW', + sqlGeneratorProps: { + dropViews: true, + }, + }, + ], }, ]; case 'matviews': @@ -291,16 +301,21 @@ }, createScriptTemplatesSubmenu('matviews'), { - label: 'SQL Generator: CREATE MATERIALIZED VIEW', - sqlGeneratorProps: { - createMatviews: true, - }, - }, - { - label: 'SQL Generator: DROP MATERIALIZED VIEW', - sqlGeneratorProps: { - dropMatviews: true, - }, + label: 'SQL generator', + submenu: [ + { + label: 'CREATE MATERIALIZED VIEW', + sqlGeneratorProps: { + createMatviews: true, + }, + }, + { + label: 'DROP MATERIALIZED VIEW', + sqlGeneratorProps: { + dropMatviews: true, + }, + }, + ], }, ]; case 'queries': @@ -329,16 +344,21 @@ }, createScriptTemplatesSubmenu('procedures'), { - label: 'SQL Generator: CREATE PROCEDURE', - sqlGeneratorProps: { - createProcedures: true, - }, - }, - { - label: 'SQL Generator: DROP PROCEDURE', - sqlGeneratorProps: { - dropProcedures: true, - }, + label: 'SQL generator', + submenu: [ + { + label: 'CREATE PROCEDURE', + sqlGeneratorProps: { + createProcedures: true, + }, + }, + { + label: 'DROP PROCEDURE', + sqlGeneratorProps: { + dropProcedures: true, + }, + }, + ], }, ]; case 'functions': @@ -359,16 +379,21 @@ }, createScriptTemplatesSubmenu('functions'), { - label: 'SQL Generator: CREATE FUNCTION', - sqlGeneratorProps: { - createFunctions: true, - }, - }, - { - label: 'SQL Generator: DROP FUNCTION', - sqlGeneratorProps: { - dropFunctions: true, - }, + label: 'SQL generator', + submenu: [ + { + label: 'CREATE FUNCTION', + sqlGeneratorProps: { + createFunctions: true, + }, + }, + { + label: 'DROP FUNCTION', + sqlGeneratorProps: { + dropFunctions: true, + }, + }, + ], }, ]; case 'collections': @@ -687,7 +712,7 @@ initialData?, icon?, appObjectData?, - preventPreviewMode? + tabPreviewMode? ) { const connection = await getConnectionInfo({ conid }); const tooltip = `${getConnectionLabel(connection)}\n${database}\n${fullDisplayName({ @@ -703,7 +728,7 @@ tabComponent: scriptTemplate ? 'QueryTab' : tabComponent, appObject: 'DatabaseObjectAppObject', appObjectData, - tabPreviewMode: !preventPreviewMode, + tabPreviewMode, props: { schemaName, pureName, @@ -718,10 +743,12 @@ ); } - export function handleDatabaseObjectClick(data, forceNewTab = false, preventPreviewMode = false) { + export function handleDatabaseObjectClick(data, { forceNewTab = false, tabPreviewMode = false } = {}) { const { schemaName, pureName, conid, database, objectTypeField } = data; const driver = findEngineDriver(data, getExtensions()); + const activeTab = getActiveTab(); + const configuredAction = getCurrentSettings()[`defaultAction.dbObjectClick.${objectTypeField}`]; const overrideMenu = createMenus(objectTypeField, driver).find(x => x.label && x.label == configuredAction); if (overrideMenu) { @@ -743,7 +770,7 @@ null, null, data, - preventPreviewMode + tabPreviewMode ); } @@ -837,8 +864,8 @@ return createDatabaseObjectMenu(data); } - export function handleObjectClick(data, forceNewTab = false, preventPreviewMode = false) { - return handleDatabaseObjectClick(data, forceNewTab, preventPreviewMode); + export function handleObjectClick(data, { forceNewTab = false, tabPreviewMode = false }) { + return handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode }); } @@ -848,6 +875,7 @@ import { currentDatabase, extensions, + getActiveTab, getCurrentSettings, getExtensions, openedConnections, @@ -886,9 +914,9 @@ export let data; export let passProps; - function handleClick(forceNewTab = false, preventPreviewMode = false) { + function handleClick({ forceNewTab = false, tabPreviewMode = false } = {}) { $selectedDatabaseObjectAppObject = data; - handleDatabaseObjectClick(data, forceNewTab, preventPreviewMode); + handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode }); } function createMenu() { @@ -922,9 +950,9 @@ onUnpin={isPinned ? () => pinnedTables.update(list => list.filter(x => !testEqual(x, data))) : null} extInfo={getExtInfo(data)} isChoosed={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)} - on:click={() => handleClick()} - on:middleclick={() => handleClick(true)} - on:dblclick={() => handleClick(false, true)} + on:click={() => handleClick({ tabPreviewMode: true })} + on:middleclick={() => handleClick({ forceNewTab: true })} + on:dblclick={() => handleClick({})} on:expand on:dragstart on:dragenter diff --git a/packages/web/src/widgets/AppObjectListHandler.svelte b/packages/web/src/widgets/AppObjectListHandler.svelte index ad5799349..26c607104 100644 --- a/packages/web/src/widgets/AppObjectListHandler.svelte +++ b/packages/web/src/widgets/AppObjectListHandler.svelte @@ -16,7 +16,7 @@ const index = _.findIndex(list, x => selectedObjectMatcher(x, selected)); if (index >= 0 && list[index + diff]) { selectedObjectStore.set(list[index + diff]); - module.handleObjectClick(list[index + diff]); + module.handleObjectClick(list[index + diff], { tabPreviewMode: true }); } } if (ev.keyCode == keycodes.upArrow) { From 1216bcf9bf77479e726aa370b1281c455e3166a0 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 20 Nov 2024 15:37:01 +0100 Subject: [PATCH 12/25] sql object tab refactor --- .../src/appobj/DatabaseObjectAppObject.svelte | 8 +++++--- packages/web/src/tabs/SqlObjectTab.svelte | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index 3e31c2ec8..536212989 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -664,9 +664,11 @@ tabComponent: 'SqlObjectTab', tabPreviewMode: true, props: { - appObjectData: data, conid: data.conid, database: data.database, + schemaName: data.schemaName, + pureName: data.pureName, + objectTypeField: data.objectTypeField, }, }); } else { @@ -722,10 +724,10 @@ openNewTab( { - title: scriptTemplate ? 'Query #' : getObjectTitle(connection, schemaName, pureName), + title: getObjectTitle(connection, schemaName, pureName), tooltip, icon: icon || (scriptTemplate ? 'img sql-file' : databaseObjectIcons[objectTypeField]), - tabComponent: scriptTemplate ? 'QueryTab' : tabComponent, + tabComponent: scriptTemplate ? 'SqlObjectTab' : tabComponent, appObject: 'DatabaseObjectAppObject', appObjectData, tabPreviewMode, diff --git a/packages/web/src/tabs/SqlObjectTab.svelte b/packages/web/src/tabs/SqlObjectTab.svelte index 57cffea99..1c96bdf9d 100644 --- a/packages/web/src/tabs/SqlObjectTab.svelte +++ b/packages/web/src/tabs/SqlObjectTab.svelte @@ -32,9 +32,23 @@ export let appObjectData; export let scriptTemplate; + export let schemaName; + export let pureName; + export let conid; + export let database; + export let objectTypeField; + + $: appObjectData = { + schemaName, + pureName, + conid, + database, + objectTypeField, + }; + $: defaultScriptTemplate = getSupportedScriptTemplates(appObjectData.objectTypeField)?.[0]?.scriptTemplate; - $: connection = useConnectionInfo({ conid: appObjectData.conid }); + $: connection = useConnectionInfo({ conid }); $: driver = findEngineDriver($connection, $extensions); const tabVisible: any = getContext('tabVisible'); From 86186072edd2cfc8b2dc719f2fbbf1bbfa7fb256 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Wed, 20 Nov 2024 17:12:54 +0100 Subject: [PATCH 13/25] db app obj WIP --- .../src/appobj/DatabaseObjectAppObject.svelte | 243 +++++++----------- packages/web/src/appobj/appObjectMatchers.ts | 9 - packages/web/src/appobj/appObjectTools.ts | 80 ++++++ packages/web/src/tabs/SqlObjectTab.svelte | 4 +- packages/web/src/widgets/SqlObjectList.svelte | 2 +- 5 files changed, 182 insertions(+), 156 deletions(-) delete mode 100644 packages/web/src/appobj/appObjectMatchers.ts create mode 100644 packages/web/src/appobj/appObjectTools.ts diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index 536212989..5115bce25 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -29,6 +29,8 @@ views: 'ViewDataTab', matviews: 'ViewDataTab', queries: 'QueryDataTab', + procedures: 'SqlObjectTab', + functions: 'SqlObjectTab', }; function createScriptTemplatesSubmenu(objectTypeField) { @@ -70,25 +72,9 @@ switch (objectTypeField) { case 'tables': return [ + ...defaultDatabaseObjectAppObjectActions['tables'], { - label: 'Open data', - tab: 'TableDataTab', - forceNewTab: true, - }, - { - label: 'Open form', - tab: 'TableDataTab', - forceNewTab: true, - initialData: { - grid: { - isFormView: true, - }, - }, - }, - { - label: 'Open structure', - tab: 'TableStructureTab', - icon: 'img table-structure', + divider: true, }, { label: 'Design query', @@ -101,6 +87,33 @@ forceNewTab: true, icon: 'img perspective', }, + createScriptTemplatesSubmenu('tables'), + { + label: 'SQL generator', + submenu: [ + { + label: 'CREATE TABLE', + sqlGeneratorProps: { + createTables: true, + createIndexes: true, + createForeignKeys: true, + }, + }, + { + label: 'DROP TABLE', + sqlGeneratorProps: { + dropTables: true, + dropReferences: true, + }, + }, + { + label: 'INSERT', + sqlGeneratorProps: { + insert: true, + }, + }, + ], + }, { divider: true, }, @@ -150,52 +163,12 @@ label: 'Open active chart', isActiveChart: true, }, - { - divider: true, - }, - { - isShowSql: true, - label: 'Show SQL', - }, - createScriptTemplatesSubmenu('tables'), - { - label: 'SQL generator', - submenu: [ - { - label: 'CREATE TABLE', - sqlGeneratorProps: { - createTables: true, - createIndexes: true, - createForeignKeys: true, - }, - }, - { - label: 'DROP TABLE', - sqlGeneratorProps: { - dropTables: true, - dropReferences: true, - }, - }, - { - label: 'INSERT', - sqlGeneratorProps: { - insert: true, - }, - }, - ], - }, ]; case 'views': return [ + ...defaultDatabaseObjectAppObjectActions['views'], { - label: 'Open data', - tab: 'ViewDataTab', - forceNewTab: true, - }, - { - label: 'Open structure', - tab: 'TableStructureTab', - icon: 'img view-structure', + divider: true, }, { label: 'Design query', @@ -207,35 +180,6 @@ forceNewTab: true, icon: 'img perspective', }, - hasPermission('dbops/model/edit') && { - label: 'Drop view', - isDrop: true, - requiresWriteAccess: true, - }, - hasPermission('dbops/model/edit') && { - label: 'Rename view', - isRename: true, - requiresWriteAccess: true, - }, - { - divider: true, - }, - { - label: 'Export', - isExport: true, - functionName: 'tableReader', - }, - { - label: 'Open active chart', - isActiveChart: true, - }, - { - divider: true, - }, - { - isShowSql: true, - label: 'Show SQL', - }, createScriptTemplatesSubmenu('views'), { label: 'SQL generator', @@ -254,17 +198,8 @@ }, ], }, - ]; - case 'matviews': - return [ { - label: 'Open data', - tab: 'ViewDataTab', - forceNewTab: true, - }, - { - label: 'Open structure', - tab: 'TableStructureTab', + divider: true, }, hasPermission('dbops/model/edit') && { label: 'Drop view', @@ -276,10 +211,6 @@ isRename: true, requiresWriteAccess: true, }, - { - label: 'Query designer', - isQueryDesigner: true, - }, { divider: true, }, @@ -292,12 +223,29 @@ label: 'Open active chart', isActiveChart: true, }, + ]; + case 'matviews': + return [ + ...defaultDatabaseObjectAppObjectActions['matviews'], + { + divider: true, + }, + hasPermission('dbops/model/edit') && { + label: 'Drop view', + isDrop: true, + requiresWriteAccess: true, + }, + hasPermission('dbops/model/edit') && { + label: 'Rename view', + isRename: true, + requiresWriteAccess: true, + }, { divider: true, }, { - isShowSql: true, - label: 'Show SQL', + label: 'Query designer', + isQueryDesigner: true, }, createScriptTemplatesSubmenu('matviews'), { @@ -317,6 +265,18 @@ }, ], }, + { + divider: true, + }, + { + label: 'Export', + isExport: true, + functionName: 'tableReader', + }, + { + label: 'Open active chart', + isActiveChart: true, + }, ]; case 'queries': return [ @@ -328,6 +288,10 @@ ]; case 'procedures': return [ + ...defaultDatabaseObjectAppObjectActions['procedures'], + { + divider: true, + }, hasPermission('dbops/model/edit') && { label: 'Drop procedure', isDrop: true, @@ -338,10 +302,6 @@ isRename: true, requiresWriteAccess: true, }, - { - isShowSql: true, - label: 'Show SQL', - }, createScriptTemplatesSubmenu('procedures'), { label: 'SQL generator', @@ -363,6 +323,10 @@ ]; case 'functions': return [ + ...defaultDatabaseObjectAppObjectActions['functions'], + { + divider: true, + }, hasPermission('dbops/model/edit') && { label: 'Drop function', isDrop: true, @@ -373,10 +337,6 @@ isRename: true, requiresWriteAccess: true, }, - { - isShowSql: true, - label: 'Show SQL', - }, createScriptTemplatesSubmenu('functions'), { label: 'SQL generator', @@ -398,20 +358,9 @@ ]; case 'collections': return [ + ...defaultDatabaseObjectAppObjectActions['collections'], { - label: 'Open data', - tab: 'CollectionDataTab', - forceNewTab: true, - }, - { - label: 'Open JSON', - tab: 'CollectionDataTab', - forceNewTab: true, - initialData: { - grid: { - isJsonView: true, - }, - }, + divider: true, }, { label: 'Design perspective query', @@ -657,20 +606,20 @@ // fixedTargetPureName: data.pureName, // }, // }); - } else if (menu.isShowSql) { - openNewTab({ - title: data.pureName, - icon: 'img sql-file', - tabComponent: 'SqlObjectTab', - tabPreviewMode: true, - props: { - conid: data.conid, - database: data.database, - schemaName: data.schemaName, - pureName: data.pureName, - objectTypeField: data.objectTypeField, - }, - }); + // } else if (menu.isShowSql) { + // openNewTab({ + // title: data.pureName, + // icon: 'img sql-file', + // tabComponent: 'SqlObjectTab', + // tabPreviewMode: true, + // props: { + // conid: data.conid, + // database: data.database, + // schemaName: data.schemaName, + // pureName: data.pureName, + // objectTypeField: data.objectTypeField, + // }, + // }); } else { openDatabaseObjectDetail( menu.tab, @@ -724,10 +673,13 @@ openNewTab( { - title: getObjectTitle(connection, schemaName, pureName), + // title: getObjectTitle(connection, schemaName, pureName), + title: tabComponent ? getObjectTitle(connection, schemaName, pureName) : 'Query #', tooltip, - icon: icon || (scriptTemplate ? 'img sql-file' : databaseObjectIcons[objectTypeField]), - tabComponent: scriptTemplate ? 'SqlObjectTab' : tabComponent, + icon: + icon || + (scriptTemplate || tabComponent == 'SqlObjectTab' ? 'img sql-file' : databaseObjectIcons[objectTypeField]), + tabComponent: tabComponent ?? 'QueryTab', appObject: 'DatabaseObjectAppObject', appObjectData, tabPreviewMode, @@ -750,6 +702,7 @@ const driver = findEngineDriver(data, getExtensions()); const activeTab = getActiveTab(); + console.log('activeTab', activeTab); const configuredAction = getCurrentSettings()[`defaultAction.dbObjectClick.${objectTypeField}`]; const overrideMenu = createMenus(objectTypeField, driver).find(x => x.label && x.label == configuredAction); @@ -760,7 +713,7 @@ openDatabaseObjectDetail( defaultTabs[objectTypeField], - defaultTabs[objectTypeField] ? null : 'CREATE OBJECT', + null, { schemaName, pureName, @@ -910,7 +863,7 @@ import { getDefaultFileFormat } from '../plugins/fileformats'; import hasPermission from '../utility/hasPermission'; import { openImportExportTab } from '../utility/importExportTools'; - import { matchDatabaseObjectAppObject } from './appObjectMatchers'; + import { defaultDatabaseObjectAppObjectActions, matchDatabaseObjectAppObject } from './appObjectTools'; import { getSupportedScriptTemplates } from '../utility/applyScriptTemplate'; export let data; diff --git a/packages/web/src/appobj/appObjectMatchers.ts b/packages/web/src/appobj/appObjectMatchers.ts deleted file mode 100644 index 12daa26d8..000000000 --- a/packages/web/src/appobj/appObjectMatchers.ts +++ /dev/null @@ -1,9 +0,0 @@ -export function matchDatabaseObjectAppObject(obj1, obj2) { - return ( - obj1?.objectTypeField == obj2?.objectTypeField && - obj1?.conid == obj2?.conid && - obj1?.database == obj2?.database && - obj1?.pureName == obj2?.pureName && - obj1?.schemaName == obj2?.schemaName - ); -} diff --git a/packages/web/src/appobj/appObjectTools.ts b/packages/web/src/appobj/appObjectTools.ts new file mode 100644 index 000000000..a22f0b705 --- /dev/null +++ b/packages/web/src/appobj/appObjectTools.ts @@ -0,0 +1,80 @@ +export function matchDatabaseObjectAppObject(obj1, obj2) { + return ( + obj1?.objectTypeField == obj2?.objectTypeField && + obj1?.conid == obj2?.conid && + obj1?.database == obj2?.database && + obj1?.pureName == obj2?.pureName && + obj1?.schemaName == obj2?.schemaName + ); +} + +function getTableLikeActions(dataTab) { + return [ + { + label: 'Open data', + tab: dataTab, + defaultActionId: 'openTable', + }, + { + label: 'Open form', + tab: dataTab, + initialData: { + grid: { + isFormView: true, + }, + }, + defaultActionId: 'openForm', + }, + { + label: 'Open structure', + tab: 'TableStructureTab', + icon: 'img table-structure', + defaultActionId: 'openStructure', + }, + { + label: 'Show SQL', + tab: 'SqlObjectTab', + defaultActionId: 'showSql', + icon: 'img sql-file', + }, + ]; +} + +export const defaultDatabaseObjectAppObjectActions = { + tables: getTableLikeActions('TableDataTab'), + views: getTableLikeActions('ViewDataTab'), + matviews: getTableLikeActions('ViewDataTab'), + procedures: [ + { + label: 'Show SQL', + tab: 'SqlObjectTab', + defaultActionId: 'showSql', + icon: 'img sql-file', + }, + ], + functions: [ + { + label: 'Show SQL', + tab: 'SqlObjectTab', + defaultActionId: 'showSql', + icon: 'img sql-file', + }, + ], + collections: [ + { + label: 'Open data', + tab: 'CollectionDataTab', + defaultActionId: 'openTable', + }, + { + label: 'Open JSON', + tab: 'CollectionDataTab', + defaultActionId: 'openJson', + initialData: { + grid: { + isJsonView: true, + }, + }, + }, + ], +}; diff --git a/packages/web/src/tabs/SqlObjectTab.svelte b/packages/web/src/tabs/SqlObjectTab.svelte index 1c96bdf9d..329849777 100644 --- a/packages/web/src/tabs/SqlObjectTab.svelte +++ b/packages/web/src/tabs/SqlObjectTab.svelte @@ -9,6 +9,8 @@ testEnabled: () => getCurrentEditor() != null, onClick: () => getCurrentEditor().find(), }); + + export const matchingProps = ['conid', 'database', 'schemaName', 'pureName', 'objectTypeField']; + + ({ + value: x.defaultActionId, + label: x.label, + }))} +/> diff --git a/packages/web/src/settings/SettingsModal.svelte b/packages/web/src/settings/SettingsModal.svelte index 45ffc7fac..8dd8e2e68 100644 --- a/packages/web/src/settings/SettingsModal.svelte +++ b/packages/web/src/settings/SettingsModal.svelte @@ -37,6 +37,7 @@ import { useSettings } from '../utility/metadataLoaders'; import { derived } from 'svelte/store'; import { safeFormatDate } from 'dbgate-tools'; + import FormDefaultActionField from './FormDefaultActionField.svelte'; const electron = getElectron(); let restartWarning = false; @@ -279,56 +280,11 @@ ORDER BY ]} /> - - - - - - - + + + + +
Confirmations
From dc18be07ce3c04290a2ed0ab78d7c0ab2afe53f9 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Thu, 21 Nov 2024 15:03:43 +0100 Subject: [PATCH 15/25] #938 current database is not changed after closing tab --- packages/web/src/stores.ts | 2 +- packages/web/src/tabpanel/TabsPanel.svelte | 2 + .../web/src/utility/changeCurrentDbByTab.ts | 60 ++++++++++++------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index 847b6168c..3ffc1a50f 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -92,7 +92,7 @@ export const openedConnections = writable([]); export const temporaryOpenedConnections = writable([]); export const openedSingleDatabaseConnections = writable([]); export const expandedConnections = writable([]); -export const currentDatabase = writable(null); +export const currentDatabase = writableWithForage(null, 'currentDatabase'); export const openedTabs = writableWithForage([], getOpenedTabsStorageName(), x => [...(x || [])]); export const copyRowsFormat = writableWithStorage('textWithoutHeaders', 'copyRowsFormat'); export const extensions = writable(null); diff --git a/packages/web/src/tabpanel/TabsPanel.svelte b/packages/web/src/tabpanel/TabsPanel.svelte index 684e7c3af..514dfb9a7 100644 --- a/packages/web/src/tabpanel/TabsPanel.svelte +++ b/packages/web/src/tabpanel/TabsPanel.svelte @@ -295,6 +295,7 @@ import CloseTabModal from '../modals/CloseTabModal.svelte'; import SwitchDatabaseModal from '../modals/SwitchDatabaseModal.svelte'; import { getConnectionLabel } from 'dbgate-tools'; + import { changeDatabaseByCurrentTab } from '../utility/changeCurrentDbByTab'; export let multiTabIndex; export let shownTab; @@ -334,6 +335,7 @@ return; } setSelectedTab(tabid); + changeDatabaseByCurrentTab(); }; const handleMouseDown = (e, tabid) => { diff --git a/packages/web/src/utility/changeCurrentDbByTab.ts b/packages/web/src/utility/changeCurrentDbByTab.ts index 7a8183643..864abd206 100644 --- a/packages/web/src/utility/changeCurrentDbByTab.ts +++ b/packages/web/src/utility/changeCurrentDbByTab.ts @@ -1,35 +1,51 @@ import _ from 'lodash'; -import { currentDatabase, getCurrentDatabase, getLockedDatabaseMode, openedTabs } from '../stores'; +import { currentDatabase, getActiveTab, getCurrentDatabase, getLockedDatabaseMode, openedTabs } from '../stores'; import { shouldShowTab } from '../tabpanel/TabsPanel.svelte'; import { callWhenAppLoaded, getAppLoaded } from './appLoadManager'; import { getConnectionInfo } from './metadataLoaders'; import { switchCurrentDatabase } from './common'; -let lastCurrentTab = null; +// let lastCurrentTab = null; -openedTabs.subscribe(value => { - const newCurrentTab = (value || []).find(x => x.selected); - if (newCurrentTab == lastCurrentTab) return; - if (getLockedDatabaseMode() && getCurrentDatabase()) return; +// openedTabs.subscribe(value => { +// const newCurrentTab = (value || []).find(x => x.selected); +// if (newCurrentTab == lastCurrentTab) return; +// if (getLockedDatabaseMode() && getCurrentDatabase()) return; - const lastTab = lastCurrentTab; - lastCurrentTab = newCurrentTab; - // if (lastTab?.tabComponent == 'ConnectionTab') return; +// const lastTab = lastCurrentTab; +// lastCurrentTab = newCurrentTab; +// // if (lastTab?.tabComponent == 'ConnectionTab') return; - if (newCurrentTab) { - const { conid, database } = newCurrentTab.props || {}; - if (conid && database && (conid != lastTab?.props?.conid || database != lastTab?.props?.database)) { - const doWork = async () => { - const connection = await getConnectionInfo({ conid }); - switchCurrentDatabase({ - connection, - name: database, - }); - }; - callWhenAppLoaded(doWork); - } +// if (newCurrentTab) { +// const { conid, database } = newCurrentTab.props || {}; +// if (conid && database && (conid != lastTab?.props?.conid || database != lastTab?.props?.database)) { +// const doWork = async () => { +// const connection = await getConnectionInfo({ conid }); +// switchCurrentDatabase({ +// connection, +// name: database, +// }); +// }; +// callWhenAppLoaded(doWork); +// } +// } +// }); + +export function changeDatabaseByCurrentTab() { + const currentTab = getActiveTab(); + const { conid, database } = currentTab?.props || {}; + const db = getCurrentDatabase(); + if (conid && database && (conid != db?.connection?._id || database != db?.name)) { + const doWork = async () => { + const connection = await getConnectionInfo({ conid }); + switchCurrentDatabase({ + connection, + name: database, + }); + }; + callWhenAppLoaded(doWork); } -}); +} currentDatabase.subscribe(currentDb => { if (!getLockedDatabaseMode()) return; From 1f79627dbea79b12f6d36e7dab9e8fea64598b83 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Thu, 21 Nov 2024 15:47:46 +0100 Subject: [PATCH 16/25] change selected object when switching tab --- .../src/appobj/DatabaseObjectAppObject.svelte | 4 +- .../web/src/utility/changeCurrentDbByTab.ts | 44 ++++++++++++++----- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index 702162dca..2c1de04fc 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -887,7 +887,7 @@ export let passProps; function handleClick({ forceNewTab = false, tabPreviewMode = false } = {}) { - $selectedDatabaseObjectAppObject = data; + $selectedDatabaseObjectAppObject = _.pick(data, ['conid', 'database', 'objectTypeField', 'pureName', 'schemaName']); handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode }); } @@ -924,7 +924,7 @@ isChoosed={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)} on:click={() => handleClick({ tabPreviewMode: true })} on:middleclick={() => handleClick({ forceNewTab: true })} - on:dblclick={() => handleClick({})} + on:dblclick={() => handleClick({ tabPreviewMode: false })} on:expand on:dragstart on:dragenter diff --git a/packages/web/src/utility/changeCurrentDbByTab.ts b/packages/web/src/utility/changeCurrentDbByTab.ts index 864abd206..9e4f73492 100644 --- a/packages/web/src/utility/changeCurrentDbByTab.ts +++ b/packages/web/src/utility/changeCurrentDbByTab.ts @@ -1,5 +1,12 @@ import _ from 'lodash'; -import { currentDatabase, getActiveTab, getCurrentDatabase, getLockedDatabaseMode, openedTabs } from '../stores'; +import { + currentDatabase, + getActiveTab, + getCurrentDatabase, + getLockedDatabaseMode, + openedTabs, + selectedDatabaseObjectAppObject, +} from '../stores'; import { shouldShowTab } from '../tabpanel/TabsPanel.svelte'; import { callWhenAppLoaded, getAppLoaded } from './appLoadManager'; import { getConnectionInfo } from './metadataLoaders'; @@ -31,19 +38,34 @@ import { switchCurrentDatabase } from './common'; // } // }); -export function changeDatabaseByCurrentTab() { +export async function changeDatabaseByCurrentTab() { const currentTab = getActiveTab(); - const { conid, database } = currentTab?.props || {}; + const { conid, database, objectTypeField, pureName, schemaName, defaultActionId } = currentTab?.props || {}; const db = getCurrentDatabase(); if (conid && database && (conid != db?.connection?._id || database != db?.name)) { - const doWork = async () => { - const connection = await getConnectionInfo({ conid }); - switchCurrentDatabase({ - connection, - name: database, - }); - }; - callWhenAppLoaded(doWork); + const connection = await getConnectionInfo({ conid }); + switchCurrentDatabase({ + connection, + name: database, + }); + // const doWork = async () => { + // const connection = await getConnectionInfo({ conid }); + // switchCurrentDatabase({ + // connection, + // name: database, + // }); + // }; + // callWhenAppLoaded(doWork); + } + + if (conid && database && objectTypeField && pureName && defaultActionId) { + selectedDatabaseObjectAppObject.set({ + conid, + database, + objectTypeField, + pureName, + schemaName, + }); } } From 4b1c0218711678e81d433cb7709b3a64809bbac9 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Thu, 21 Nov 2024 16:12:27 +0100 Subject: [PATCH 17/25] Revert "don't focus in tabs" This reverts commit 90946c582d883b8487ab3ba76b0c2b3ca4019b73. --- packages/web/src/tabs/ArchiveFileTab.svelte | 1 + packages/web/src/tabs/CollectionDataTab.svelte | 1 + packages/web/src/tabs/QueryDataTab.svelte | 2 +- packages/web/src/tabs/TableDataTab.svelte | 1 + packages/web/src/tabs/ViewDataTab.svelte | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/web/src/tabs/ArchiveFileTab.svelte b/packages/web/src/tabs/ArchiveFileTab.svelte index ed48ba5f1..74e6d1579 100644 --- a/packages/web/src/tabs/ArchiveFileTab.svelte +++ b/packages/web/src/tabs/ArchiveFileTab.svelte @@ -170,6 +170,7 @@ supportsReload allowChangeChangeSetStructure changeSetState={$changeSetStore} + focusOnVisible {changeSetStore} {dispatchChangeSet} {infoLoadCounter} diff --git a/packages/web/src/tabs/CollectionDataTab.svelte b/packages/web/src/tabs/CollectionDataTab.svelte index e0ecfe592..03f9fa85d 100644 --- a/packages/web/src/tabs/CollectionDataTab.svelte +++ b/packages/web/src/tabs/CollectionDataTab.svelte @@ -191,6 +191,7 @@ cache={$cache} setCache={cache.update} changeSetState={$changeSetStore} + focusOnVisible {display} {changeSetStore} {dispatchChangeSet} diff --git a/packages/web/src/tabs/QueryDataTab.svelte b/packages/web/src/tabs/QueryDataTab.svelte index 6b3544694..227414ec6 100644 --- a/packages/web/src/tabs/QueryDataTab.svelte +++ b/packages/web/src/tabs/QueryDataTab.svelte @@ -100,7 +100,7 @@ {#if jslid} - + {:else} {/if} diff --git a/packages/web/src/tabs/TableDataTab.svelte b/packages/web/src/tabs/TableDataTab.svelte index 45609a852..83a6f13df 100644 --- a/packages/web/src/tabs/TableDataTab.svelte +++ b/packages/web/src/tabs/TableDataTab.svelte @@ -255,6 +255,7 @@ cache={$cache} setCache={cache.update} changeSetState={$changeSetStore} + focusOnVisible {changeSetStore} {dispatchChangeSet} /> diff --git a/packages/web/src/tabs/ViewDataTab.svelte b/packages/web/src/tabs/ViewDataTab.svelte index 95d04e72a..a5fb401db 100644 --- a/packages/web/src/tabs/ViewDataTab.svelte +++ b/packages/web/src/tabs/ViewDataTab.svelte @@ -68,6 +68,7 @@ setConfig={config.update} cache={$cache} setCache={cache.update} + focusOnVisible hasMultiColumnFilter gridCoreComponent={SqlDataGridCore} formViewComponent={SqlFormView} From b9f9501e67f47525dd58995dab314b5be20d4971 Mon Sep 17 00:00:00 2001 From: "SPRINX0\\prochazka" Date: Thu, 21 Nov 2024 16:49:56 +0100 Subject: [PATCH 18/25] handle tab focus --- .../src/appobj/DatabaseObjectAppObject.svelte | 21 +++++++++++++++---- packages/web/src/datagrid/DataGridCore.svelte | 4 ++-- packages/web/src/stores.ts | 3 ++- packages/web/src/tabpanel/TabContent.svelte | 11 +++++++--- packages/web/src/tabpanel/TabRegister.svelte | 1 + packages/web/src/tabpanel/TabsPanel.svelte | 4 ++-- .../web/src/utility/changeCurrentDbByTab.ts | 10 ++++++++- packages/web/src/utility/common.ts | 17 ++++++++++++--- packages/web/src/utility/openNewTab.ts | 4 +++- 9 files changed, 58 insertions(+), 17 deletions(-) diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index 2c1de04fc..a2ac29ac7 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -699,7 +699,10 @@ ); } - export function handleDatabaseObjectClick(data, { forceNewTab = false, tabPreviewMode = false } = {}) { + export function handleDatabaseObjectClick( + data, + { forceNewTab = false, tabPreviewMode = false, focusTab = false } = {} + ) { const { schemaName, pureName, conid, database, objectTypeField } = data; const driver = findEngineDriver(data, getExtensions()); @@ -708,6 +711,15 @@ const activeDefaultActionId = activeTab?.props?.defaultActionId; if (matchDatabaseObjectAppObject(data, activeTabProps)) { + if (!tabPreviewMode) { + openedTabs.update(tabs => { + return tabs.map(tab => ({ + ...tab, + tabPreviewMode: tab.tabid == activeTab.tabid ? false : tab.tabPreviewMode, + focused: focusTab && tab.tabid == activeTab.tabid ? true : tab.focused, + })); + }); + } return; } @@ -851,6 +863,7 @@ getCurrentSettings, getExtensions, openedConnections, + openedTabs, pinnedTables, selectedDatabaseObjectAppObject, } from '../stores'; @@ -886,9 +899,9 @@ export let data; export let passProps; - function handleClick({ forceNewTab = false, tabPreviewMode = false } = {}) { + function handleClick({ forceNewTab = false, tabPreviewMode = false, focusTab = false } = {}) { $selectedDatabaseObjectAppObject = _.pick(data, ['conid', 'database', 'objectTypeField', 'pureName', 'schemaName']); - handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode }); + handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode, focusTab }); } function createMenu() { @@ -924,7 +937,7 @@ isChoosed={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)} on:click={() => handleClick({ tabPreviewMode: true })} on:middleclick={() => handleClick({ forceNewTab: true })} - on:dblclick={() => handleClick({ tabPreviewMode: false })} + on:dblclick={() => handleClick({ tabPreviewMode: false, focusTab: true })} on:expand on:dragstart on:dragenter diff --git a/packages/web/src/datagrid/DataGridCore.svelte b/packages/web/src/datagrid/DataGridCore.svelte index 3010f74db..787708194 100644 --- a/packages/web/src/datagrid/DataGridCore.svelte +++ b/packages/web/src/datagrid/DataGridCore.svelte @@ -472,7 +472,7 @@ export let dataEditorTypesBehaviourOverride = null; const wheelRowCount = 5; - const tabVisible: any = getContext('tabVisible'); + const tabFocused: any = getContext('tabFocused'); let containerHeight = 0; let containerWidth = 0; @@ -1135,7 +1135,7 @@ } } - $: if ($tabVisible && domFocusField && focusOnVisible) { + $: if ($tabFocused && domFocusField && focusOnVisible) { domFocusField.focus(); } diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index 3ffc1a50f..7cffe2eb5 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -23,6 +23,7 @@ export interface TabDefinition { multiTabIndex?: number; unsaved?: boolean; tabPreviewMode?: boolean; + focused?: boolean; } export function writableWithStorage(defaultValue: T, storageName) { @@ -328,4 +329,4 @@ let selectedDatabaseObjectAppObjectValue = null; selectedDatabaseObjectAppObject.subscribe(value => { selectedDatabaseObjectAppObjectValue = value; }); -export const getSelectedDatabaseObjectAppObject = () => selectedDatabaseObjectAppObjectValue; \ No newline at end of file +export const getSelectedDatabaseObjectAppObject = () => selectedDatabaseObjectAppObjectValue; diff --git a/packages/web/src/tabpanel/TabContent.svelte b/packages/web/src/tabpanel/TabContent.svelte index bff6f575e..8eac0de10 100644 --- a/packages/web/src/tabpanel/TabContent.svelte +++ b/packages/web/src/tabpanel/TabContent.svelte @@ -4,17 +4,22 @@ export let tabid; export let tabVisible; + export let tabFocused; export let tabComponent; - const tabVisibleStore = writable(tabVisible); setContext('tabid', tabid); - setContext('tabVisible', tabVisibleStore); + const tabVisibleStore = writable(tabVisible); + setContext('tabVisible', tabVisibleStore); $: tabVisibleStore.set(tabVisible); + + const tabFocusedStore = writable(tabFocused); + setContext('tabFocused', tabFocusedStore); + $: tabFocusedStore.set(tabFocused);
- +