diff --git a/packages/web/src/appobj/AppObjectCore.svelte b/packages/web/src/appobj/AppObjectCore.svelte index 02ed23eaa..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; @@ -66,11 +67,21 @@ } // $: console.log(title, indentLevel); + let domDiv; + + $: if (isBold && domDiv) { + domDiv.scrollIntoView({ block: 'nearest', inline: 'nearest' }); + } + + $: if (isChoosed && domDiv) { + domDiv.scrollIntoView({ block: 'nearest', inline: 'nearest' }); + }
{#if checkedObjectsStore} { diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index 87bbbe4be..4e1cb7339 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -509,9 +509,9 @@ await dbgateApi.dropAllDbObjects(${JSON.stringify( extInfo={data.extInfo} icon="img database" colorMark={passProps?.connectionColorFactory && - passProps?.connectionColorFactory({ conid: _.get(data.connection, '_id'), database: data.name }, null, null, false)} - isBold={_.get($currentDatabase, 'connection._id') == _.get(data.connection, '_id') && - extractDbNameFromComposite(_.get($currentDatabase, 'name')) == data.name} + passProps?.connectionColorFactory({ conid: data?.connection?._id, database: data.name }, null, null, false)} + isBold={$currentDatabase?.connection?._id == data?.connection?._id && + extractDbNameFromComposite($currentDatabase?.name) == data.name} on:click={() => switchCurrentDatabase(data)} on:dragstart on:dragenter diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index f0de19506..352e4f6c9 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -29,12 +29,18 @@ views: 'ViewDataTab', matviews: 'ViewDataTab', queries: 'QueryDataTab', + procedures: 'SqlObjectTab', + functions: 'SqlObjectTab', }; - function createMenusCore( - objectTypeField, - driver - ): { + function createScriptTemplatesSubmenu(objectTypeField) { + return { + label: 'SQL template', + submenu: getSupportedScriptTemplates(objectTypeField), + }; + } + + interface DbObjMenuItem { label?: string; tab?: string; forceNewTab?: boolean; @@ -53,34 +59,22 @@ isExport?: boolean; isImport?: boolean; isActiveChart?: boolean; + isShowSql?: boolean; scriptTemplate?: string; sqlGeneratorProps?: any; isDropCollection?: boolean; isRenameCollection?: boolean; isDuplicateCollection?: boolean; - }[] { + submenu?: DbObjMenuItem[]; + } + + function createMenusCore(objectTypeField, driver): DbObjMenuItem[] { 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', @@ -93,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, }, @@ -142,50 +163,12 @@ label: 'Open active chart', isActiveChart: true, }, - { - divider: true, - }, - { - label: 'SQL: CREATE TABLE', - scriptTemplate: 'CREATE TABLE', - }, - { - label: 'SQL: SELECT', - scriptTemplate: 'SELECT', - }, - { - 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, - }, - }, ]; 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', @@ -197,6 +180,27 @@ forceNewTab: true, icon: 'img perspective', }, + createScriptTemplatesSubmenu('views'), + { + label: 'SQL generator', + submenu: [ + { + label: 'CREATE VIEW', + sqlGeneratorProps: { + createViews: true, + }, + }, + { + label: 'DROP VIEW', + sqlGeneratorProps: { + dropViews: true, + }, + }, + ], + }, + { + divider: true, + }, hasPermission('dbops/model/edit') && { label: 'Drop view', isDrop: true, @@ -219,48 +223,12 @@ label: 'Open active chart', isActiveChart: true, }, - { - divider: true, - }, - { - label: 'SQL: CREATE VIEW', - scriptTemplate: 'CREATE OBJECT', - }, - { - label: 'SQL: ALTER VIEW', - scriptTemplate: 'ALTER OBJECT', - }, - { - label: 'SQL: CREATE TABLE', - scriptTemplate: 'CREATE TABLE', - }, - { - label: 'SQL: SELECT', - scriptTemplate: 'SELECT', - }, - { - label: 'SQL Generator: CREATE VIEW', - sqlGeneratorProps: { - createViews: true, - }, - }, - { - label: 'SQL Generator: DROP VIEW', - sqlGeneratorProps: { - dropViews: true, - }, - }, ]; case 'matviews': return [ + ...defaultDatabaseObjectAppObjectActions['matviews'], { - label: 'Open data', - tab: 'ViewDataTab', - forceNewTab: true, - }, - { - label: 'Open structure', - tab: 'TableStructureTab', + divider: true, }, hasPermission('dbops/model/edit') && { label: 'Drop view', @@ -272,10 +240,31 @@ isRename: true, requiresWriteAccess: true, }, + { + divider: true, + }, { label: 'Query designer', isQueryDesigner: true, }, + createScriptTemplatesSubmenu('matviews'), + { + label: 'SQL generator', + submenu: [ + { + label: 'CREATE MATERIALIZED VIEW', + sqlGeneratorProps: { + createMatviews: true, + }, + }, + { + label: 'DROP MATERIALIZED VIEW', + sqlGeneratorProps: { + dropMatviews: true, + }, + }, + ], + }, { divider: true, }, @@ -288,37 +277,6 @@ label: 'Open active chart', isActiveChart: true, }, - { - divider: true, - }, - { - label: 'SQL: CREATE MATERIALIZED VIEW', - scriptTemplate: 'CREATE OBJECT', - }, - { - label: 'SQL: ALTER MATERIALIZED VIEW', - scriptTemplate: 'ALTER OBJECT', - }, - { - label: 'SQL: CREATE TABLE', - scriptTemplate: 'CREATE TABLE', - }, - { - label: 'SQL: SELECT', - scriptTemplate: 'SELECT', - }, - { - label: 'SQL Generator: CREATE MATERIALIZED VIEW', - sqlGeneratorProps: { - createMatviews: true, - }, - }, - { - label: 'SQL Generator: DROP MATERIALIZED VIEW', - sqlGeneratorProps: { - dropMatviews: true, - }, - }, ]; case 'queries': return [ @@ -330,6 +288,10 @@ ]; case 'procedures': return [ + ...defaultDatabaseObjectAppObjectActions['procedures'], + { + divider: true, + }, hasPermission('dbops/model/edit') && { label: 'Drop procedure', isDrop: true, @@ -340,33 +302,31 @@ isRename: true, requiresWriteAccess: true, }, + createScriptTemplatesSubmenu('procedures'), { - label: 'SQL: CREATE PROCEDURE', - scriptTemplate: 'CREATE OBJECT', - }, - { - label: 'SQL: ALTER PROCEDURE', - scriptTemplate: 'ALTER OBJECT', - }, - { - label: 'SQL: EXECUTE', - scriptTemplate: 'EXECUTE PROCEDURE', - }, - { - 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': return [ + ...defaultDatabaseObjectAppObjectActions['functions'], + { + divider: true, + }, hasPermission('dbops/model/edit') && { label: 'Drop function', isDrop: true, @@ -377,43 +337,30 @@ isRename: true, requiresWriteAccess: true, }, + createScriptTemplatesSubmenu('functions'), { - label: 'SQL: CREATE FUNCTION', - scriptTemplate: 'CREATE OBJECT', - }, - { - label: 'SQL: ALTER FUNCTION', - scriptTemplate: 'ALTER OBJECT', - }, - { - 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': 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', @@ -659,15 +606,30 @@ // 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 { openDatabaseObjectDetail( menu.tab, menu.scriptTemplate, - data, + { ...data, defaultActionId: menu.defaultActionId }, menu.forceNewTab, menu.initialData, menu.icon, - data + data, + !!menu.defaultActionId ); } } @@ -697,11 +659,12 @@ export async function openDatabaseObjectDetail( tabComponent, scriptTemplate, - { schemaName, pureName, conid, database, objectTypeField }, + { schemaName, pureName, conid, database, objectTypeField, defaultActionId }, forceNewTab?, initialData?, icon?, - appObjectData? + appObjectData?, + tabPreviewMode? ) { const connection = await getConnectionInfo({ conid }); const tooltip = `${getConnectionLabel(connection)}\n${database}\n${fullDisplayName({ @@ -711,12 +674,16 @@ openNewTab( { - title: scriptTemplate ? 'Query #' : 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 ? 'QueryTab' : tabComponent, + icon: + icon || + (scriptTemplate || tabComponent == 'SqlObjectTab' ? 'img sql-file' : databaseObjectIcons[objectTypeField]), + tabComponent: tabComponent ?? 'QueryTab', appObject: 'DatabaseObjectAppObject', appObjectData, + tabPreviewMode, props: { schemaName, pureName, @@ -724,6 +691,7 @@ database, objectTypeField, initialArgs: scriptTemplate ? { scriptTemplate } : null, + defaultActionId, }, }, initialData, @@ -731,31 +699,62 @@ ); } - export function handleDatabaseObjectClick(data, forceNewTab = false) { + export function handleDatabaseObjectClick( + data, + { forceNewTab = false, tabPreviewMode = false, focusTab = false } = {} + ) { const { schemaName, pureName, conid, database, objectTypeField } = data; const driver = findEngineDriver(data, getExtensions()); - const configuredAction = getCurrentSettings()[`defaultAction.dbObjectClick.${objectTypeField}`]; - const overrideMenu = createMenus(objectTypeField, driver).find(x => x.label && x.label == configuredAction); - if (overrideMenu) { - databaseObjectMenuClickHandler(data, overrideMenu); + const activeTab = getActiveTab(); + const activeTabProps = activeTab?.props || {}; + 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; } + const availableDefaultActions = defaultDatabaseObjectAppObjectActions[objectTypeField]; + + const configuredActionId = getCurrentSettings()[`defaultAction.dbObjectClick.${objectTypeField}`]; + const prefferedAction = + availableDefaultActions.find(x => x.defaultActionId == activeDefaultActionId) ?? + availableDefaultActions.find(x => x.defaultActionId == configuredActionId) ?? + availableDefaultActions[0]; + + // console.log('activeTab', activeTab); + + // const overrideMenu = createMenus(objectTypeField, driver).find(x => x.label && x.label == configuredAction); + // if (overrideMenu) { + // databaseObjectMenuClickHandler(data, overrideMenu); + // return; + // } + openDatabaseObjectDetail( - defaultTabs[objectTypeField], - defaultTabs[objectTypeField] ? null : 'CREATE OBJECT', + prefferedAction.tab, + activeTabProps?.scriptTemplate, { schemaName, pureName, conid, database, objectTypeField, + defaultActionId: prefferedAction.defaultActionId, }, forceNewTab, null, null, - data + data, + tabPreviewMode ); } @@ -769,64 +768,74 @@ ); } + function menuItemMapper(menu, data, connection) { + if (menu.divider) return menu; + + if (menu.isExport) { + return createQuickExportMenu( + fmt => async () => { + const coninfo = await getConnectionInfo(data); + exportQuickExportFile( + data.pureName, + { + functionName: menu.functionName, + props: { + connection: extractShellConnection(coninfo, data.database), + ..._.pick(data, ['pureName', 'schemaName']), + }, + }, + fmt + ); + }, + { + onClick: () => { + openImportExportTab({ + sourceStorageType: 'database', + sourceConnectionId: data.conid, + sourceDatabaseName: extractDbNameFromComposite(data.database), + sourceSchemaName: data.schemaName, + sourceList: [data.pureName], + }); + // showModal(ImportExportModal, { + // initialValues: { + // sourceStorageType: 'database', + // sourceConnectionId: data.conid, + // sourceDatabaseName: data.database, + // sourceSchemaName: data.schemaName, + // sourceList: [data.pureName], + // }, + // }); + }, + } + ); + } + + if (connection?.isReadOnly && menu.requiresWriteAccess) { + return null; + } + + if (menu.submenu) { + return { + ...menu, + submenu: menu.submenu.map(x => menuItemMapper(x, data, connection)), + }; + } + + return { + text: menu.label, + onClick: () => { + databaseObjectMenuClickHandler(data, menu); + }, + }; + } + export function createDatabaseObjectMenu(data, connection = null) { const driver = findEngineDriver(data, getExtensions()); const { objectTypeField } = data; return createMenus(objectTypeField, driver) .filter(x => x) - .map(menu => { - if (menu.divider) return menu; - - if (menu.isExport) { - return createQuickExportMenu( - fmt => async () => { - const coninfo = await getConnectionInfo(data); - exportQuickExportFile( - data.pureName, - { - functionName: menu.functionName, - props: { - connection: extractShellConnection(coninfo, data.database), - ..._.pick(data, ['pureName', 'schemaName']), - }, - }, - fmt - ); - }, - { - onClick: () => { - openImportExportTab({ - sourceStorageType: 'database', - sourceConnectionId: data.conid, - sourceDatabaseName: extractDbNameFromComposite(data.database), - sourceSchemaName: data.schemaName, - sourceList: [data.pureName], - }); - // showModal(ImportExportModal, { - // initialValues: { - // sourceStorageType: 'database', - // sourceConnectionId: data.conid, - // sourceDatabaseName: data.database, - // sourceSchemaName: data.schemaName, - // sourceList: [data.pureName], - // }, - // }); - }, - } - ); - } - - if (connection?.isReadOnly && menu.requiresWriteAccess) { - return null; - } - return { - text: menu.label, - onClick: () => { - databaseObjectMenuClickHandler(data, menu); - }, - }; - }); + .map(menu => menuItemMapper(menu, data, connection)); } function formatRowCount(value) { @@ -838,6 +847,10 @@ export function createAppObjectMenu(data) { return createDatabaseObjectMenu(data); } + + export function handleObjectClick(data, { forceNewTab = false, tabPreviewMode = false, focusTab = false }) { + return handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode, focusTab }); + } {#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..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; @@ -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]))] @@ -1134,7 +1135,7 @@ } } - $: if ($tabVisible && domFocusField && focusOnVisible) { + $: if ($tabFocused && domFocusField && focusOnVisible) { domFocusField.focus(); } @@ -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; + }} /> (value = x), 500); + + export function focus() { + domInput.focus(); + } + import { defaultDatabaseObjectAppObjectActions } from '../appobj/appObjectTools'; + import FormSelectField from '../forms/FormSelectField.svelte'; + + export let label; + export let objectTypeField; + + + ({ + value: x.defaultActionId, + label: x.label, + }))} +/> diff --git a/packages/web/src/settings/SettingsModal.svelte b/packages/web/src/settings/SettingsModal.svelte index fc4ba2773..362047098 100644 --- a/packages/web/src/settings/SettingsModal.svelte +++ b/packages/web/src/settings/SettingsModal.svelte @@ -38,6 +38,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; @@ -288,56 +289,11 @@ ORDER BY ]} /> - - - - - - - + + + + +
Confirmations
diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts index 98d7ae912..76dd67dc1 100644 --- a/packages/web/src/stores.ts +++ b/packages/web/src/stores.ts @@ -22,6 +22,8 @@ export interface TabDefinition { tabOrder?: number; multiTabIndex?: number; unsaved?: boolean; + tabPreviewMode?: boolean; + focused?: boolean; } export function writableWithStorage(defaultValue: T, storageName) { @@ -91,7 +93,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); @@ -155,6 +157,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) ); @@ -324,6 +328,12 @@ appliedCurrentSchema.subscribe(value => { }); export const getAppliedCurrentSchema = () => appliedCurrentSchemaValue; +let selectedDatabaseObjectAppObjectValue = null; +selectedDatabaseObjectAppObject.subscribe(value => { + selectedDatabaseObjectAppObjectValue = value; +}); +export const getSelectedDatabaseObjectAppObject = () => selectedDatabaseObjectAppObjectValue; + let openedModalsValue = []; openedModals.subscribe(value => { openedModalsValue = value; 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);
- +
diff --git a/packages/web/src/widgets/SqlObjectList.svelte b/packages/web/src/widgets/SqlObjectList.svelte index 8704e94b7..d829b5d52 100644 --- a/packages/web/src/widgets/SqlObjectList.svelte +++ b/packages/web/src/widgets/SqlObjectList.svelte @@ -36,18 +36,28 @@ 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/appObjectTools'; export let conid; export let database; let filter = ''; + let domContainer = null; + let domFilter = null; + let domListHandler; $: objects = useDatabaseInfo({ conid, database }); $: status = useDatabaseStatus({ conid, database }); @@ -151,7 +161,14 @@ {:else} - + { + domListHandler?.focusFirst(); + }} + /> @@ -168,27 +185,42 @@ negativeMarginTop /> - + {#if ($status && ($status.name == 'pending' || $status.name == 'checkStructure' || $status.name == 'loadStructure') && $objects) || !$objects} {:else} - ($appliedCurrentSchema ? x.schemaName == $appliedCurrentSchema : true)) - .map(x => ({ ...x, conid, database }))} + ({ ...x, conid, database }))} + selectedObjectStore={selectedDatabaseObjectAppObject} + getSelectedObject={getSelectedDatabaseObjectAppObject} + selectedObjectMatcher={matchDatabaseObjectAppObject} 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, + onScrollTop={() => { + domContainer?.scrollTop(); }} - /> + onFocusFilterBox={() => { + domFilter?.focus(); + }} + > + ($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} diff --git a/packages/web/src/widgets/WidgetsInnerContainer.svelte b/packages/web/src/widgets/WidgetsInnerContainer.svelte index 498f333e0..76f7f2895 100644 --- a/packages/web/src/widgets/WidgetsInnerContainer.svelte +++ b/packages/web/src/widgets/WidgetsInnerContainer.svelte @@ -1,4 +1,12 @@ -
+ + +