diff --git a/.node-version b/.node-version
new file mode 100644
index 000000000..d9f880069
--- /dev/null
+++ b/.node-version
@@ -0,0 +1 @@
+16.14.2
diff --git a/packages/api/src/controllers/connections.js b/packages/api/src/controllers/connections.js
index 63b3c872c..5447a6f4d 100644
--- a/packages/api/src/controllers/connections.js
+++ b/packages/api/src/controllers/connections.js
@@ -62,6 +62,7 @@ function getPortalCollections() {
displayName: process.env[`LABEL_${id}`],
isReadOnly: process.env[`READONLY_${id}`],
databases: process.env[`DBCONFIG_${id}`] ? safeJsonParse(process.env[`DBCONFIG_${id}`]) : null,
+ parent: process.env[`PARENT_${id}`] || undefined,
// SSH tunnel
useSshTunnel: process.env[`USE_SSH_${id}`],
diff --git a/packages/web/src/appobj/AppObjectGroup.svelte b/packages/web/src/appobj/AppObjectGroup.svelte
index 09d4ca740..e7f791602 100644
--- a/packages/web/src/appobj/AppObjectGroup.svelte
+++ b/packages/web/src/appobj/AppObjectGroup.svelte
@@ -10,10 +10,12 @@
export let group;
export let groupFunc;
export let items;
+ export let groupIconFunc = plusExpandIcon;
export let module;
export let checkedObjectsStore = null;
export let disableContextMenu = false;
export let passProps;
+ export let onDropOnGroup = undefined;
let isExpanded = true;
@@ -35,9 +37,19 @@
}
-
(isExpanded = !isExpanded)}>
+
(isExpanded = !isExpanded)}
+ on:drop={e => {
+ var data = e.dataTransfer.getData('app_object_drag_data');
+ if (data && onDropOnGroup) {
+ e.stopPropagation();
+ onDropOnGroup(data, group);
+ }
+ }}
+>
-
+
{group}
diff --git a/packages/web/src/appobj/AppObjectList.svelte b/packages/web/src/appobj/AppObjectList.svelte
index 7644d5469..d95b14f23 100644
--- a/packages/web/src/appobj/AppObjectList.svelte
+++ b/packages/web/src/appobj/AppObjectList.svelte
@@ -2,6 +2,7 @@
import _ from 'lodash';
import { asyncFilter } from '../utility/common';
import AppObjectGroup from './AppObjectGroup.svelte';
+ import { plusExpandIcon } from '../icons/expandIcons';
import AppObjectListItem from './AppObjectListItem.svelte';
@@ -18,7 +19,9 @@
export let getIsExpanded = null;
export let setIsExpanded = null;
+ export let groupIconFunc = plusExpandIcon;
export let groupFunc = undefined;
+ export let onDropOnGroup = undefined;
$: filtered = !groupFunc
? list.filter(data => {
@@ -71,6 +74,7 @@
{module}
items={groups[group]}
{expandIconFunc}
+ {groupIconFunc}
{isExpandable}
{subItemsComponent}
{checkedObjectsStore}
@@ -80,6 +84,7 @@
{passProps}
{getIsExpanded}
{setIsExpanded}
+ {onDropOnGroup}
/>
{/each}
{:else}
diff --git a/packages/web/src/settings/ConnectionDriverFields.svelte b/packages/web/src/settings/ConnectionDriverFields.svelte
index ebe5e5186..53061a680 100644
--- a/packages/web/src/settings/ConnectionDriverFields.svelte
+++ b/packages/web/src/settings/ConnectionDriverFields.svelte
@@ -217,6 +217,19 @@
disabled={isConnected}
/>
+
+ {/if}
+
+{#if driver}
+
{/if}
diff --git a/packages/web/src/widgets/ConnectionList.svelte b/packages/web/src/widgets/ConnectionList.svelte
index cf7633878..f6e5e5d25 100644
--- a/packages/web/src/widgets/ConnectionList.svelte
+++ b/packages/web/src/widgets/ConnectionList.svelte
@@ -25,6 +25,8 @@
import { apiCall } from '../utility/api';
import LargeButton from '../buttons/LargeButton.svelte';
import { matchingProps } from '../tabs/TableDataTab.svelte';
+ import { plusExpandIcon, chevronExpandIcon } from '../icons/expandIcons';
+ import { safeJsonParse } from 'dbgate-tools';
const connections = useConnectionList();
const serverStatus = useServerStatus();
@@ -40,12 +42,29 @@
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)
+ : [];
+
const handleRefreshConnections = () => {
for (const conid of $openedConnections) {
apiCall('server-connections/refresh', { conid });
}
};
+ const handleDropOnGroup = (data, group) => {
+ const json = safeJsonParse(data);
+ if (json?._id) {
+ apiCall('connections/update', {
+ _id: json?._id,
+ values: { parent: group },
+ });
+ }
+ };
+
const connectionColorFactory = useConnectionColorFactory(3);
@@ -61,9 +80,36 @@
-
+ {
+ var data = e.dataTransfer.getData('app_object_drag_data');
+ if (data) {
+ handleDropOnGroup(data, '');
+ }
+ }}
+>
(getConnectionLabel(connection) || '').toUpperCase())}
+ list={_.sortBy(connectionsWithParent, connection => (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)));
+ }}
+ groupIconFunc={chevronExpandIcon}
+ groupFunc={data => data.parent}
+ expandIconFunc={plusExpandIcon}
+ onDropOnGroup={handleDropOnGroup}
+ />
+ {#if connectionsWithParent?.length > 0 && connectionsWithoutParent?.length > 0}
+
+ {/if}
+ (getConnectionLabel(connection) || '').toUpperCase())}
module={connectionAppObject}
subItemsComponent={SubDatabaseList}
expandOnClick
@@ -84,3 +130,11 @@
-->
{/if}
+
+
diff --git a/packages/web/src/widgets/WidgetsInnerContainer.svelte b/packages/web/src/widgets/WidgetsInnerContainer.svelte
index 1ee9dd5bc..498f333e0 100644
--- a/packages/web/src/widgets/WidgetsInnerContainer.svelte
+++ b/packages/web/src/widgets/WidgetsInnerContainer.svelte
@@ -1,4 +1,4 @@
-
+