Skip to content

Commit 124667a

Browse files
committed
More experimenting
1 parent 4d5cf66 commit 124667a

File tree

5 files changed

+116
-67
lines changed

5 files changed

+116
-67
lines changed

src/connectionconfig/connectionDialogWebviewController.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,10 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
835835
// eslint-disable-next-line @typescript-eslint/no-explicit-any
836836
cleanedConnection as any,
837837
);
838+
// Refresh the Object Explorer tree to include new connections/groups
839+
if (self._objectExplorerProvider?.objectExplorerService?.refreshTree) {
840+
await self._objectExplorerProvider.objectExplorerService.refreshTree();
841+
}
838842
const node =
839843
await self._mainController.createObjectExplorerSession(cleanedConnection);
840844
await self.updateLoadedConnections(state);

src/connectionconfig/connectionconfig.ts

Lines changed: 59 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import * as Utils from "../models/utils";
99
import { IConnectionGroup, IConnectionProfile } from "../models/interfaces";
1010
import { IConnectionConfig } from "./iconnectionconfig";
1111
import VscodeWrapper, { ConfigurationTarget } from "../controllers/vscodeWrapper";
12+
13+
export { ConfigurationTarget };
1214
import { ConnectionProfile } from "../models/connectionProfile";
1315
import { getConnectionDisplayName } from "../models/connectionInfo";
1416
import { Deferred } from "../protocol";
@@ -291,8 +293,11 @@ export class ConnectionConfig implements IConnectionConfig {
291293
* @returns The connection group with the specified ID, or `undefined` if not found.
292294
*/
293295
public getGroupById(id: string): IConnectionGroup | undefined {
294-
const connGroups = this.getGroupsFromSettings(ConfigurationTarget.Global);
295-
return connGroups.find((g) => g.id === id);
296+
// Search both user and workspace groups for the given ID
297+
const userGroups = this.getGroupsFromSettings(ConfigurationTarget.Global);
298+
const workspaceGroups = this.getGroupsFromSettings(ConfigurationTarget.Workspace);
299+
const allGroups = [...userGroups, ...workspaceGroups];
300+
return allGroups.find((g) => g.id === id);
296301
}
297302

298303
public addGroup(group: IConnectionGroup): Promise<void> {
@@ -501,82 +506,101 @@ export class ConnectionConfig implements IConnectionConfig {
501506

502507
private async assignConnectionGroupMissingIds(): Promise<void> {
503508
let madeChanges = false;
504-
const groups: IConnectionGroup[] = this.getGroupsFromSettings();
505-
let connections: IConnectionProfile[] = this.getConnectionsFromSettings();
509+
// User groups and connections
510+
const userGroups: IConnectionGroup[] = this.getGroupsFromSettings(
511+
ConfigurationTarget.Global,
512+
);
513+
let userConnections: IConnectionProfile[] = this.getConnectionsFromSettings(
514+
ConfigurationTarget.Global,
515+
);
516+
// Workspace groups and connections
517+
const workspaceGroups: IConnectionGroup[] = this.getGroupsFromSettings(
518+
ConfigurationTarget.Workspace,
519+
);
520+
let workspaceConnections: IConnectionProfile[] = this.getConnectionsFromSettings(
521+
ConfigurationTarget.Workspace,
522+
);
506523

507-
// ensure ROOT group exists
508-
let rootGroup = await this.getRootGroup();
524+
// ensure ROOT group exists in user settings
525+
let rootGroup = userGroups.find((g) => g.name === ConnectionConfig.RootGroupName);
509526
if (!rootGroup) {
510527
rootGroup = {
511528
name: ConnectionConfig.RootGroupName,
512529
id: Utils.generateGuid(),
513530
};
514-
this._logger.logDebug(`Adding missing ROOT group to connection groups`);
531+
userGroups.push(rootGroup);
515532
madeChanges = true;
516-
groups.push(rootGroup);
533+
this._logger.logDebug(`Adding missing ROOT group to user connection groups`);
517534
}
518535

519-
// Check for User Connections and Workspace Connections under ROOT
520-
let userConnectionsGroup = groups.find(
536+
// Ensure User Connections group exists in user settings
537+
let userConnectionsGroup = userGroups.find(
521538
(g) => g.name === "User Connections" && g.parentId === rootGroup.id,
522539
);
523-
let workspaceConnectionsGroup = groups.find(
524-
(g) => g.name === "Workspace Connections" && g.parentId === rootGroup.id,
525-
);
526-
527540
if (!userConnectionsGroup) {
528541
userConnectionsGroup = {
529542
name: "User Connections",
530543
id: Utils.generateGuid(),
531544
parentId: rootGroup.id,
532545
};
533-
groups.push(userConnectionsGroup);
546+
userGroups.push(userConnectionsGroup);
534547
madeChanges = true;
535548
this._logger.logDebug(`Created 'User Connections' group under ROOT`);
536549
}
550+
551+
// Ensure Workspace Connections group exists in workspace settings, parented to ROOT (user)
552+
let workspaceConnectionsGroup = workspaceGroups.find(
553+
(g) => g.name === "Workspace Connections" && g.parentId === rootGroup.id,
554+
);
537555
if (!workspaceConnectionsGroup) {
538556
workspaceConnectionsGroup = {
539557
name: "Workspace Connections",
540558
id: Utils.generateGuid(),
541559
parentId: rootGroup.id,
542560
};
543-
groups.push(workspaceConnectionsGroup);
561+
workspaceGroups.push(workspaceConnectionsGroup);
544562
madeChanges = true;
545-
this._logger.logDebug(`Created 'Workspace Connections' group under ROOT`);
563+
this._logger.logDebug(`Created 'Workspace Connections' group under ROOT (user)`);
546564
}
547565

548-
// Reparent all groups directly under ROOT (except the two new groups) to User Connections
549-
for (const group of groups) {
550-
if (
551-
group.parentId === rootGroup.id &&
552-
group.id !== userConnectionsGroup.id &&
553-
group.id !== workspaceConnectionsGroup.id
554-
) {
555-
group.parentId = userConnectionsGroup.id;
566+
// Reparent all workspace groups directly under ROOT to Workspace Connections group
567+
for (const group of workspaceGroups) {
568+
if (group.parentId === rootGroup.id && group.id !== workspaceConnectionsGroup.id) {
569+
group.parentId = workspaceConnectionsGroup.id;
556570
madeChanges = true;
557-
this._logger.logDebug(`Reparented group '${group.name}' to 'User Connections'`);
571+
this._logger.logDebug(
572+
`Reparented workspace group '${group.name}' to 'Workspace Connections'`,
573+
);
558574
}
559575
}
560576

561-
// Reparent all connections directly under ROOT to User Connections
562-
for (const conn of connections) {
563-
// If connection is under ROOT or has no group, move to User Connections
577+
// Reparent all workspace connections directly under ROOT to Workspace Connections group
578+
for (const conn of workspaceConnections) {
564579
if (!conn.groupId || conn.groupId === rootGroup.id) {
565-
conn.groupId = userConnectionsGroup.id;
580+
conn.groupId = workspaceConnectionsGroup.id;
566581
madeChanges = true;
567582
this._logger.logDebug(
568-
`Reparented connection '${getConnectionDisplayName(conn)}' to 'User Connections'`,
583+
`Reparented workspace connection '${getConnectionDisplayName(conn)}' to 'Workspace Connections'`,
569584
);
570585
}
571586
}
572587

573-
// Save the changes to settings
588+
// Save changes to settings
574589
if (madeChanges) {
590+
this._logger.logDebug(`Writing updated user groups and connections to user settings.`);
591+
await this.writeConnectionGroupsToSettings(userGroups);
592+
await this.writeConnectionsToSettings(userConnections);
575593
this._logger.logDebug(
576-
`Updates made to connection groups. Writing all ${groups.length} group(s) to settings.`,
594+
`Writing updated workspace groups and connections to workspace settings.`,
595+
);
596+
await this.writeConnectionGroupsToSettingsWithTarget(
597+
workspaceGroups,
598+
ConfigurationTarget.Workspace,
599+
);
600+
await this.writeConnectionsToSettings(
601+
workspaceConnections,
602+
ConfigurationTarget.Workspace,
577603
);
578-
await this.writeConnectionGroupsToSettings(groups);
579-
await this.writeConnectionsToSettings(connections);
580604
}
581605
}
582606

src/models/connectionStore.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
IConnectionGroup,
2121
} from "../models/interfaces";
2222
import { ICredentialStore } from "../credentialstore/icredentialstore";
23-
import { ConnectionConfig } from "../connectionconfig/connectionconfig";
23+
import { ConnectionConfig, ConfigurationTarget } from "../connectionconfig/connectionconfig";
2424
import VscodeWrapper from "../controllers/vscodeWrapper";
2525
import { IConnectionInfo } from "vscode-mssql";
2626
import { Logger } from "./logger";
@@ -368,6 +368,17 @@ export class ConnectionStore {
368368
): Promise<IConnectionProfile> {
369369
await this._connectionConfig.populateMissingConnectionIds(profile);
370370

371+
// Determine the correct target for saving based on groupId
372+
let target = ConfigurationTarget.Global;
373+
// Get all workspace group IDs
374+
const workspaceGroups = this._connectionConfig.getGroupsFromSettings(
375+
ConfigurationTarget.Workspace,
376+
);
377+
const workspaceGroupIds = new Set(workspaceGroups.map((g) => g.id));
378+
if (workspaceGroupIds.has(profile.groupId)) {
379+
target = ConfigurationTarget.Workspace;
380+
}
381+
371382
// Add the profile to the saved list, taking care to clear out the password field if necessary
372383
let savedProfile: IConnectionProfile;
373384
if (profile.authenticationType === Utils.authTypeToString(AuthenticationTypes.AzureMFA)) {
@@ -382,7 +393,7 @@ export class ConnectionStore {
382393
}
383394
}
384395

385-
await this._connectionConfig.addConnection(savedProfile);
396+
await this._connectionConfig.addConnection(savedProfile, target);
386397

387398
if (await this.saveProfilePasswordIfNeeded(profile)) {
388399
ConnInfo.fixupConnectionCredentials(profile);

src/objectExplorer/objectExplorerService.ts

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,20 @@ export class ObjectExplorerService {
105105
return result;
106106
}
107107

108+
/**
109+
* Public method to refresh the Object Explorer tree and internal maps, merging user and workspace connections/groups.
110+
* Call this after adding/removing connections/groups to ensure the tree is up to date.
111+
*/
112+
public async refreshTree(): Promise<void> {
113+
await this.getRootNodes();
114+
// Optionally, trigger a UI refresh if needed
115+
if (this._refreshCallback && this._rootTreeNodeArray.length > 0) {
116+
for (const node of this._rootTreeNodeArray) {
117+
this._refreshCallback(node);
118+
}
119+
}
120+
}
121+
108122
/**
109123
* Map of pending session creations
110124
*/
@@ -402,7 +416,7 @@ export class ObjectExplorerService {
402416
this._connectionManager.connectionStore.connectionConfig.getGroupsFromSettings(
403417
ConfigurationTarget.Workspace,
404418
);
405-
// Merge root, user, and workspace groups
419+
// Merge user and workspace groups before building hierarchy
406420
const allGroups = [...userGroups, ...workspaceGroups];
407421
let savedConnections = await this._connectionManager.connectionStore.readAllConnections();
408422

@@ -417,10 +431,8 @@ export class ObjectExplorerService {
417431
return this.getAddConnectionNodes();
418432
}
419433

434+
// Build group nodes from merged settings
420435
const newConnectionGroupNodes = new Map<string, ConnectionGroupNode>();
421-
const newConnectionNodes = new Map<string, ConnectionNode>();
422-
423-
// Add all group nodes from merged settings
424436
for (const group of allGroups) {
425437
const groupNode = new ConnectionGroupNode(group);
426438
if (this._connectionGroupNodes.has(group.id)) {
@@ -429,12 +441,9 @@ export class ObjectExplorerService {
429441
newConnectionGroupNodes.set(group.id, groupNode);
430442
}
431443

432-
// Populate group hierarchy - add each group as a child to its parent
444+
// Build hierarchy: add each group as a child to its parent
433445
for (const group of allGroups) {
434-
// Skip the root group as it has no parent
435-
if (group.id === rootId) {
436-
continue;
437-
}
446+
if (group.id === rootId) continue;
438447
if (group.parentId && newConnectionGroupNodes.has(group.parentId)) {
439448
const parentNode = newConnectionGroupNodes.get(group.parentId);
440449
const childNode = newConnectionGroupNodes.get(group.id);
@@ -443,19 +452,12 @@ export class ObjectExplorerService {
443452
if (parentNode.id !== rootId) {
444453
childNode.parentNode = parentNode;
445454
}
446-
} else {
447-
this._logger.error(
448-
`Child group '${group.name}' with ID '${group.id}' does not have a valid parent group (${group.parentId}).`,
449-
);
450455
}
451-
} else {
452-
this._logger.error(
453-
`Group '${group.name}' with ID '${group.id}' does not have a valid parent group ID. This should have been corrected when reading server groups from settings.`,
454-
);
455456
}
456457
}
457458

458459
// Add connections as children of their respective groups
460+
const newConnectionNodes = new Map<string, ConnectionNode>();
459461
for (const connection of savedConnections) {
460462
if (connection.groupId && newConnectionGroupNodes.has(connection.groupId)) {
461463
const groupNode = newConnectionGroupNodes.get(connection.groupId);
@@ -473,21 +475,21 @@ export class ObjectExplorerService {
473475
connectionNode.parentNode = groupNode.id === rootId ? undefined : groupNode;
474476
newConnectionNodes.set(connection.id, connectionNode);
475477
groupNode.addChild(connectionNode);
476-
} else {
477-
this._logger.error(
478-
`Connection '${getConnectionDisplayName(connection)}' with ID '${connection.id}' does not have a valid group ID. This should have been corrected when reading connections from settings.`,
479-
);
480478
}
481479
}
482480

481+
// Set the new maps before refreshing UI
483482
this._connectionGroupNodes = newConnectionGroupNodes;
484483
this._connectionNodes = newConnectionNodes;
485484

486-
const result = [...this._rootTreeNodeArray];
485+
// For the ROOT node, include as children any group whose parentId matches rootId
486+
const rootChildren = Array.from(newConnectionGroupNodes.values()).filter(
487+
(groupNode) => groupNode.connectionGroup.parentId === rootId,
488+
);
487489
getConnectionActivity.end(ActivityStatus.Succeeded, undefined, {
488-
nodeCount: result.length,
490+
nodeCount: rootChildren.length,
489491
});
490-
return result;
492+
return rootChildren;
491493
}
492494

493495
/**

src/views/connectionUI.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { AddFirewallRuleWebviewController } from "../controllers/addFirewallRule
3030
import { SessionCreatedParameters } from "../models/contracts/objectExplorer/createSessionRequest";
3131
import { CREATE_NEW_GROUP_ID, IConnectionGroup } from "../sharedInterfaces/connectionGroup";
3232
import { FormItemOptions } from "../sharedInterfaces/form";
33+
import { ConfigurationTarget } from "../connectionconfig/connectionconfig";
3334

3435
/**
3536
* The different tasks for managing connection profiles.
@@ -663,19 +664,26 @@ export class ConnectionUI {
663664
*/
664665
public async getConnectionGroupOptions(): Promise<FormItemOptions[]> {
665666
const rootId = this._connectionManager.connectionStore.rootGroupId;
666-
let connectionGroups =
667-
await this._connectionManager.connectionStore.readAllConnectionGroups();
668-
connectionGroups = connectionGroups.filter((g) => g.id !== rootId);
667+
// Fetch user and workspace groups separately
668+
const userGroups = await this._connectionManager.connectionStore.connectionConfig.getGroups(
669+
ConfigurationTarget.Global,
670+
);
671+
const workspaceGroups =
672+
await this._connectionManager.connectionStore.connectionConfig.getGroups(
673+
ConfigurationTarget.Workspace,
674+
);
675+
// Merge and filter out the root group
676+
let allGroups = [...userGroups, ...workspaceGroups].filter((g) => g.id !== rootId);
669677

670678
// Count occurrences of group names to handle naming conflicts
671679
const nameOccurrences = new Map<string, number>();
672-
for (const group of connectionGroups) {
680+
for (const group of allGroups) {
673681
const count = nameOccurrences.get(group.name) || 0;
674682
nameOccurrences.set(group.name, count + 1);
675683
}
676684

677685
// Create a map of group IDs to their full paths
678-
const groupById = new Map(connectionGroups.map((g) => [g.id, g]));
686+
const groupById = new Map(allGroups.map((g) => [g.id, g]));
679687

680688
// Helper function to get parent path
681689
const getParentPath = (group: IConnectionGroup): string => {
@@ -689,7 +697,7 @@ export class ConnectionUI {
689697
return `${getParentPath(parent)} > ${group.name}`;
690698
};
691699

692-
const result = connectionGroups
700+
const result = allGroups
693701
.map((g) => {
694702
// If there are naming conflicts, use the full path
695703
const displayName = nameOccurrences.get(g.name) > 1 ? getParentPath(g) : g.name;

0 commit comments

Comments
 (0)