diff --git a/packages/web/src/appobj/AppObjectListItem.svelte b/packages/web/src/appobj/AppObjectListItem.svelte index b3524adaa..2b61b232b 100644 --- a/packages/web/src/appobj/AppObjectListItem.svelte +++ b/packages/web/src/appobj/AppObjectListItem.svelte @@ -50,7 +50,7 @@ x.name)); }; export function openConnection(connection) { + if (connection.singleDatabase) { + if (getOpenedSingleDatabaseConnections().includes(connection._id)) { + return; + } + } else { + if (getOpenedConnections().includes(connection._id)) { + return; + } + } + const config = getCurrentConfig(); if (connection.singleDatabase) { switchCurrentDatabase({ connection, name: connection.defaultDatabase }); @@ -83,10 +93,12 @@ currentDatabase, expandedConnections, extensions, + focusedConnectionOrDatabase, getCurrentConfig, getCurrentDatabase, getCurrentSettings, getOpenedConnections, + getOpenedSingleDatabaseConnections, getOpenedTabs, openedConnections, openedSingleDatabaseConnections, @@ -135,7 +147,7 @@ }); }; - const handleClick = async () => { + const handleDoubleClick = async () => { const config = getCurrentConfig(); if (config.runAsPortal) { await tick(); @@ -158,6 +170,19 @@ } }; + const handleClick = async e => { + focusedConnectionOrDatabase.set({ conid: data?._id }); + openNewTab({ + title: getConnectionLabel(data), + icon: 'img connection', + tabComponent: 'ConnectionTab', + tabPreviewMode: true, + props: { + conid: data._id, + }, + }); + }; + const handleSqlRestore = () => { showModal(ImportDatabaseDumpModal, { connection: data, @@ -329,7 +354,7 @@ colorMark={passProps?.connectionColorFactory && passProps?.connectionColorFactory({ conid: data._id })} menu={getContextMenu} on:click={handleClick} - on:click + on:dblclick on:expand on:dblclick={handleConnect} on:middleclick={() => { @@ -337,4 +362,5 @@ .find(x => x.isNewQuery) .onClick(); }} + isChoosed={data._id == $focusedConnectionOrDatabase?.conid && !$focusedConnectionOrDatabase?.database} /> diff --git a/packages/web/src/appobj/DatabaseAppObject.svelte b/packages/web/src/appobj/DatabaseAppObject.svelte index 4e1cb7339..620b8441a 100644 --- a/packages/web/src/appobj/DatabaseAppObject.svelte +++ b/packages/web/src/appobj/DatabaseAppObject.svelte @@ -446,6 +446,7 @@ await dbgateApi.dropAllDbObjects(${JSON.stringify( currentArchive, currentDatabase, extensions, + focusedConnectionOrDatabase, getCurrentDatabase, getExtensions, getOpenedTabs, @@ -512,7 +513,14 @@ await dbgateApi.dropAllDbObjects(${JSON.stringify( 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:dblclick={() => { + switchCurrentDatabase(data); + // passProps?.onFocusSqlObjectList?.(); + }} + on:click={() => { + // switchCurrentDatabase(data); + $focusedConnectionOrDatabase = { conid: data.connection?._id, database: data.name, connection: data.connection }; + }} on:dragstart on:dragenter on:dragend @@ -532,4 +540,6 @@ await dbgateApi.dropAllDbObjects(${JSON.stringify( list.filter(x => x?.name != data?.name || x?.connection?._id != data?.connection?._id) ) : null} + isChoosed={data.connection?._id == $focusedConnectionOrDatabase?.conid && + data.name == $focusedConnectionOrDatabase?.database} /> diff --git a/packages/web/src/appobj/SubDatabaseList.svelte b/packages/web/src/appobj/SubDatabaseList.svelte index b48b646a2..6d8abaec0 100644 --- a/packages/web/src/appobj/SubDatabaseList.svelte +++ b/packages/web/src/appobj/SubDatabaseList.svelte @@ -15,13 +15,11 @@ $: databases = useDatabaseList({ conid: isExpandedOnlyBySearch ? null : data._id }); $: dbList = isExpandedOnlyBySearch ? getLocalStorage(`database_list_${data._id}`) || [] : $databases || []; - - $: connectionLabel = getConnectionLabel(data); filterName(filter, x.name, connectionLabel)), + dbList.filter(x => filterName(filter, x.name, data.displayName, data.server)), x => x.sortOrder ?? x.name ).map(db => ({ ...db, connection: data }))} module={databaseAppObject} diff --git a/packages/web/src/buttons/FormStyledButton.svelte b/packages/web/src/buttons/FormStyledButton.svelte index ac731ee02..00a97d20d 100644 --- a/packages/web/src/buttons/FormStyledButton.svelte +++ b/packages/web/src/buttons/FormStyledButton.svelte @@ -7,6 +7,7 @@ export let disabled = false; export let value; export let title = null; + export let skipWidth = false; function handleClick() { if (!disabled) dispatch('click'); @@ -19,19 +20,22 @@ } - + diff --git a/packages/web/src/widgets/ConnectionList.svelte b/packages/web/src/widgets/ConnectionList.svelte index 03160390b..1e4263c8c 100644 --- a/packages/web/src/widgets/ConnectionList.svelte +++ b/packages/web/src/widgets/ConnectionList.svelte @@ -16,9 +16,12 @@ openedTabs, emptyConnectionGroupNames, collapsedConnectionGroupNames, + focusedConnectionOrDatabase, + getFocusedConnectionOrDatabase, + currentDatabase, } from '../stores'; import runCommand from '../commands/runCommand'; - import { getConnectionLabel } from 'dbgate-tools'; + import { filterName, getConnectionLabel } from 'dbgate-tools'; import { useConnectionColorFactory } from '../utility/useConnectionColor'; import FontIcon from '../icons/FontIcon.svelte'; import CloseSearchButton from '../buttons/CloseSearchButton.svelte'; @@ -29,11 +32,21 @@ import { showModal } from '../modals/modalTools'; import InputTextModal from '../modals/InputTextModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte'; + import AppObjectListHandler from './AppObjectListHandler.svelte'; + import { getLocalStorage } from '../utility/storageCache'; + import { switchCurrentDatabase } from '../utility/common'; + import openNewTab from '../utility/openNewTab'; + import { openConnection } from '../appobj/ConnectionAppObject.svelte'; const connections = useConnectionList(); const serverStatus = useServerStatus(); + export let passProps: any = {}; + let filter = ''; + let domListHandler; + let domContainer = null; + let domFilter = null; $: connectionsWithStatus = $connections && $serverStatus @@ -47,12 +60,52 @@ x => !x.unsaved || $openedConnections.includes(x._id) || $openedSingleDatabaseConnections.includes(x._id) ); - $: connectionsWithParent = connectionsWithStatusFiltered - ? connectionsWithStatusFiltered?.filter(x => x.parent !== undefined && x.parent !== null && x.parent.length !== 0) - : []; - $: connectionsWithoutParent = connectionsWithStatusFiltered - ? connectionsWithStatusFiltered?.filter(x => x.parent === undefined || x.parent === null || x.parent.length === 0) - : []; + $: connectionsWithParent = _.sortBy( + connectionsWithStatusFiltered + ? connectionsWithStatusFiltered?.filter(x => x.parent !== undefined && x.parent !== null && x.parent.length !== 0) + : [], + connection => (getConnectionLabel(connection) || '').toUpperCase() + ); + $: connectionsWithoutParent = _.sortBy( + connectionsWithStatusFiltered + ? connectionsWithStatusFiltered?.filter(x => x.parent === undefined || x.parent === null || x.parent.length === 0) + : [], + connection => (getConnectionLabel(connection) || '').toUpperCase() + ); + + function getFocusFlatList() { + const expanded = $expandedConnections; + const opened = $openedConnections; + + const res = []; + for (const con of [...connectionsWithParent, ...connectionsWithoutParent]) { + const databases = getLocalStorage(`database_list_${con._id}`) || []; + if (!filterName(filter, con.displayName, con.server, ...databases.map(x => x.name))) { + continue; + } + + res.push({ + connection: con, + conid: con._id, + }); + + if ((expanded.includes(con._id) && opened.includes(con._id)) || filter) { + for (const db of _.sortBy(databases, x => x.sortOrder ?? x.name)) { + if (!filterName(filter, con.displayName, con.server, db.name)) { + continue; + } + + res.push({ + conid: con._id, + database: db.name, + connection: con, + }); + } + } + } + + return res; + } const handleRefreshConnections = () => { for (const conid of $openedConnections) { @@ -112,7 +165,14 @@ - + { + domListHandler?.focusFirst(); + }} + /> {#if $commandsCustomized['new.connection']?.enabled} runCommand('new.connection')} title="Add new connection"> @@ -127,6 +187,7 @@ { var data = e.dataTransfer.getData('app_object_drag_data'); if (data) { @@ -134,43 +195,88 @@ } }} > - (getConnectionLabel(connection) || '').toUpperCase())} - module={connectionAppObject} - subItemsComponent={SubDatabaseList} - expandOnClick - isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase} - {filter} - passProps={{ connectionColorFactory: $connectionColorFactory, showPinnedInsteadOfUnpin: true }} - getIsExpanded={data => $expandedConnections.includes(data._id) && !data.singleDatabase} - setIsExpanded={(data, value) => { - expandedConnections.update(old => (value ? [...old, data._id] : old.filter(x => x != data._id))); + o1?.conid == o2?.conid && o1?.database == o2?.database} + getDefaultFocusedItem={() => + $currentDatabase + ? { + conid: $currentDatabase?.connection?._id, + database: $currentDatabase?.name, + connection: $currentDatabase?.connection, + } + : null} + onScrollTop={() => { + domContainer?.scrollTop(); }} - groupIconFunc={chevronExpandIcon} - groupFunc={data => data.parent} - expandIconFunc={plusExpandIcon} - onDropOnGroup={handleDropOnGroup} - emptyGroupNames={$emptyConnectionGroupNames} - sortGroups - groupContextMenu={createGroupContextMenu} - collapsedGroupNames={collapsedConnectionGroupNames} - /> - {#if (connectionsWithParent?.length > 0 && connectionsWithoutParent?.length > 0) || ($emptyConnectionGroupNames.length > 0 && connectionsWithoutParent?.length > 0)} -
- {/if} - (getConnectionLabel(connection) || '').toUpperCase())} - module={connectionAppObject} - subItemsComponent={SubDatabaseList} - expandOnClick - isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase} - {filter} - passProps={{ connectionColorFactory: $connectionColorFactory, showPinnedInsteadOfUnpin: true }} - getIsExpanded={data => $expandedConnections.includes(data._id) && !data.singleDatabase} - setIsExpanded={(data, value) => { - expandedConnections.update(old => (value ? [...old, data._id] : old.filter(x => x != data._id))); + onFocusFilterBox={text => { + domFilter?.focus(text); }} - /> + handleObjectClick={(data, options) => { + if (data.database) { + if (options.focusTab) { + switchCurrentDatabase({ connection: data.connection, name: data.database }); + // console.log('FOCUSING DB', passProps); + // passProps?.onFocusSqlObjectList?.(); + } + } else { + if (options.focusTab) { + openConnection(data.connection); + } else { + openNewTab({ + title: getConnectionLabel(data.connection), + icon: 'img connection', + tabComponent: 'ConnectionTab', + tabPreviewMode: options.tabPreviewMode, + props: { + conid: data.conid, + }, + }); + } + } + }} + > + $openedConnections.includes(data._id) && !data.singleDatabase} + {filter} + passProps={{ ...passProps, connectionColorFactory: $connectionColorFactory, showPinnedInsteadOfUnpin: true }} + getIsExpanded={data => $expandedConnections.includes(data._id) && !data.singleDatabase} + setIsExpanded={(data, value) => { + expandedConnections.update(old => (value ? [...old, data._id] : old.filter(x => x != data._id))); + }} + groupIconFunc={chevronExpandIcon} + groupFunc={data => data.parent} + expandIconFunc={plusExpandIcon} + onDropOnGroup={handleDropOnGroup} + emptyGroupNames={$emptyConnectionGroupNames} + sortGroups + groupContextMenu={createGroupContextMenu} + collapsedGroupNames={collapsedConnectionGroupNames} + /> + {#if (connectionsWithParent?.length > 0 && connectionsWithoutParent?.length > 0) || ($emptyConnectionGroupNames.length > 0 && connectionsWithoutParent?.length > 0)} +
+ {/if} + $openedConnections.includes(data._id) && !data.singleDatabase} + {filter} + passProps={{ connectionColorFactory: $connectionColorFactory, showPinnedInsteadOfUnpin: true }} + getIsExpanded={data => $expandedConnections.includes(data._id) && !data.singleDatabase} + setIsExpanded={(data, value) => { + expandedConnections.update(old => (value ? [...old, data._id] : old.filter(x => x != data._id))); + }} + /> + {#if $connections && !$connections.find(x => !x.unsaved) && $openedConnections.length == 0 && $commandsCustomized['new.connection']?.enabled && !$openedTabs.find(x => !x.closedTime && x.tabComponent == 'ConnectionTab' && !x.props?.conid)} runCommand('new.connection')} fillHorizontal >Add new connection {:else if !$config?.singleDbConnection} - + domSqlObjectList.focus() }} /> {/if} - + {#if $status && $status.name == 'error'} @@ -185,7 +197,36 @@ negativeMarginTop /> - + {#if differentFocusedDb} +
+
Current database:
+
+ {database} +
+ + switchCurrentDatabase({ + connection: $focusedConnectionOrDatabase?.connection, + name: $focusedConnectionOrDatabase?.database, + })} + /> + { + $focusedConnectionOrDatabase = { + conid, + database, + connection: $connection, + }; + }} + /> +
+ {/if} + + {#if ($status && ($status.name == 'pending' || $status.name == 'checkStructure' || $status.name == 'loadStructure') && $objects) || !$objects} {:else} @@ -195,12 +236,12 @@ selectedObjectStore={selectedDatabaseObjectAppObject} getSelectedObject={getSelectedDatabaseObjectAppObject} selectedObjectMatcher={matchDatabaseObjectAppObject} - module={databaseObjectAppObject} + handleObjectClick={(data, options) => databaseObjectAppObject.handleObjectClick(data, options)} onScrollTop={() => { domContainer?.scrollTop(); }} - onFocusFilterBox={() => { - domFilter?.focus(); + onFocusFilterBox={text => { + domFilter?.focus(text); }} > {/if} + + diff --git a/packages/web/src/widgets/WidgetsInnerContainer.svelte b/packages/web/src/widgets/WidgetsInnerContainer.svelte index 76f7f2895..262c1856c 100644 --- a/packages/web/src/widgets/WidgetsInnerContainer.svelte +++ b/packages/web/src/widgets/WidgetsInnerContainer.svelte @@ -1,12 +1,14 @@ -
+