Fixing async server tree (#22511)

* Changing look of new OE

* Fixing styling

* Fixing moving of connected profile

* Fixing drag and drop where treenodes delete connection nodes

* Fixing Deleting and disconnecting in AsyncServerTree

* Adding constant for OE timeout

* Updated interfaces

* Removing test compilation errors

* Fixing most events in async server tree

* Fixing connection pane styling

* Fixing find node function

* Fixing some more operations

* Fixing some ops

* All operations done

* Fixed active connections

* Fixed data source

* Adding support for setting parents

* code cleanup

* Fixing icon styling issues

* Fix errors

* Fixing comment

* Fixing spacing

* Adding explanation to OE service.

* Reverting server delegate changes

* Reverting styling

* reverting more styling change

* reverting more styling

* Fixing has children

* Fixing drag and drop to tree nodes

* fixing drag and drop

* reverting timing

* fixing drag and drop

* cleaning some code

* Fixed server and group moving

* spell check

* consolidating some logic

* Fixed whitespace

* fixing moving to root group
This commit is contained in:
Aasim Khan
2023-03-29 13:59:35 -07:00
committed by GitHub
parent 7ecbbdf398
commit 2a9705c495
8 changed files with 641 additions and 107 deletions

View File

@@ -173,7 +173,10 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
this._register(this._tree.onContextMenu(e => this.onTreeNodeContextMenu(e)));
this._register(this._tree.onMouseDblClick(async e => { await this.onTreeNodeDoubleClick(e.element); }));
this._register(this._connectionManagementService.onConnectionChanged(() => {
this.refreshTree().catch(err => errors.onUnexpectedError);
// No need to refresh AsyncServerTree when a connection is edited or added
if (!(this._tree instanceof AsyncServerTree)) {
this.refreshTree().catch(err => errors.onUnexpectedError);
}
}));
}
@@ -185,11 +188,19 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
this.handleAddConnectionProfile(newProfile).catch(errors.onUnexpectedError);
}));
this._register(this._connectionManagementService.onDeleteConnectionProfile(() => {
this.refreshTree().catch(errors.onUnexpectedError);
// No need to refresh AsyncServerTree when a connection is deleted
if (!(this._tree instanceof AsyncServerTree)) {
this.refreshTree().catch(errors.onUnexpectedError);
}
}));
this._register(this._connectionManagementService.onDisconnect((connectionParams) => {
if (this.isObjectExplorerConnectionUri(connectionParams.connectionUri)) {
this.deleteObjectExplorerNodeAndRefreshTree(connectionParams.connectionProfile).catch(errors.onUnexpectedError);
this._register(this._connectionManagementService.onDisconnect(async (connectionParams) => {
if (!(this._tree instanceof AsyncServerTree)) {
if (this.isObjectExplorerConnectionUri(connectionParams.connectionUri)) {
this.deleteObjectExplorerNodeAndRefreshTree(connectionParams.connectionProfile).catch(errors.onUnexpectedError);
}
} else {
await this.disconnectConnection(<ConnectionProfile>connectionParams.connectionProfile);
}
}));
this._register(this._configurationService.onDidChangeConfiguration(e => {
@@ -202,13 +213,163 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
this._register(this._objectExplorerService.onUpdateObjectExplorerNodes(args => {
if (args.errorMessage) {
this.showError(args.errorMessage);
}
if (args.connection) {
} else if (args.connection) {
if (this._tree instanceof AsyncServerTree) {
// Rerendering the node to update the badge
this._tree.rerender(<ConnectionProfile>args.connection);
}
this.onObjectExplorerSessionCreated(args.connection).catch(err => errors.onUnexpectedError);
}
}));
}
// Add connection profile to parent group and update group children. Then reveal and expand the new connection
this._register(this._connectionManagementService.onConnectionProfileCreated(async (newConnection) => {
if (this._tree instanceof AsyncServerTree) {
const connectionParentGroup = this._tree.getElementById(newConnection.groupId) as ConnectionProfileGroup;
if (connectionParentGroup) {
connectionParentGroup.connections.push(newConnection);
newConnection.parent = connectionParentGroup;
newConnection.groupId = connectionParentGroup.id;
await this._tree.updateChildren(connectionParentGroup);
await this._tree.revealSelectFocusElement(newConnection);
await this._tree.expand(newConnection);
}
}
}));
// Rerender the connection in the tree to update the badge and update the children of the connection.
this._register(this._connectionManagementService.onConnectionProfileConnected(async (connectedConnection) => {
if (this._tree instanceof AsyncServerTree) {
const connectionInTree = this._tree.getElementById(connectedConnection.id);
if (connectionInTree) {
await this._tree.rerender(connectionInTree);
await this._tree.revealSelectFocusElement(connectionInTree);
await this._tree.updateChildren(connectionInTree);
await this._tree.expand(connectionInTree);
}
}
}));
// Remove the connection from the parent group and update the parent's children.
this._register(this._connectionManagementService.onConnectionProfileDeleted(async (e) => {
if (this._tree instanceof AsyncServerTree) {
const parentGroup = <ConnectionProfileGroup>this._tree.getElementById(e.groupId);
if (parentGroup) {
parentGroup.connections = parentGroup.connections.filter(c => c.id !== e.id);
await this._tree.updateChildren(parentGroup);
await this._tree.revealSelectFocusElement(parentGroup);
}
}
}));
this._register(this._connectionManagementService.onConnectionProfileEdited(async (e) => {
if (this._tree instanceof AsyncServerTree) {
const oldProfile = <ConnectionProfile>this._tree.getElementById(e.oldProfileId);
const oldProfileParent = <ConnectionProfileGroup>this._tree.getElementById(oldProfile.groupId);
if (oldProfileParent.id !== e.profile.groupId) {
// If the profile was moved to a different group then remove it from the old group and add it to the new group.
oldProfileParent.connections = oldProfileParent.connections.filter(c => c.id !== oldProfile.id);
await this._tree.updateChildren(oldProfileParent);
const newProfileParent = <ConnectionProfileGroup>this._tree.getElementById(e.profile.groupId);
newProfileParent.connections.push(e.profile);
e.profile.parent = newProfileParent;
e.profile.groupId = newProfileParent.id;
await this._tree.updateChildren(newProfileParent);
await this._tree.revealSelectFocusElement(e.profile);
await this._tree.expand(e.profile);
} else {
// If the profile was not moved to a different group then just update the profile in the group.
oldProfileParent.connections[oldProfileParent.connections.findIndex(c => c.id === e.oldProfileId)] = e.profile;
e.profile.parent = oldProfileParent;
e.profile.groupId = oldProfileParent.id;
await this._tree.updateChildren(oldProfileParent)
await this._tree.revealSelectFocusElement(e.profile);
await this._tree.expand(e.profile);
}
}
}));
this._register(this._connectionManagementService.onConnectionProfileMoved(async (e) => {
if (this._tree instanceof AsyncServerTree) {
const movedConnection = <ConnectionProfile>e.source;
const oldParent = <ConnectionProfileGroup>this._tree.getElementById(e.oldGroupId);
const newParent = <ConnectionProfileGroup>this._tree.getElementById(e.newGroupId);
// Storing the expanded state of children of the moved connection so that they can be expanded after the move.
const profileExpandedState = this._tree.getExpandedState(movedConnection);
if (oldParent) {
oldParent.connections = oldParent.connections.filter(c => c.id !== e.source.id);
await this._tree.updateChildren(oldParent);
}
if (newParent) {
newParent.connections.push(movedConnection);
movedConnection.parent = newParent;
movedConnection.groupId = newParent.id;
await this._tree.updateChildren(newParent);
}
const newConnection = this._tree.getElementById(movedConnection.id);
if (newConnection) {
await this._tree.revealSelectFocusElement(newConnection);
// Expanding the previously expanded children of the moved connection after the move.
await this._tree.expandElements(profileExpandedState);
}
}
}));
this._register(this._connectionManagementService.onConnectionProfileGroupDeleted(async (e) => {
if (this._tree instanceof AsyncServerTree) {
const parent = <ConnectionProfileGroup>this._tree.getElementById(e.parentId);
parent.children = parent.children.filter(c => c.id !== e.id);
await this._tree.updateChildren(parent);
await this._tree.revealSelectFocusElement(parent);
}
}));
this._register(this._connectionManagementService.onConnectionProfileGroupCreated(async (e) => {
if (this._tree instanceof AsyncServerTree) {
let parent = <ConnectionProfileGroup>this._tree.getElementById(e.parentId);
if (!parent) {
parent = this._tree.getInput(); // If the parent is not found then add the group to the root.
}
parent.children.push(e);
e.parent = parent;
e.parentId = parent.id;
await this._tree.updateChildren(parent);
await this._tree.revealSelectFocusElement(e);
}
}));
this._register(this._connectionManagementService.onConnectionProfileGroupEdited(async (e) => {
if (this._tree instanceof AsyncServerTree) {
const newParent = <ConnectionProfileGroup>this._tree.getElementById(e.parentId);
if (newParent) {
newParent.children[newParent.children.findIndex(c => c.id === e.id)] = e;
await this._tree.updateChildren(newParent);
await this._tree.revealSelectFocusElement(e);
}
}
}));
this._register(this._connectionManagementService.onConnectionProfileGroupMoved(async (e) => {
if (this._tree instanceof AsyncServerTree) {
const movedGroup = <ConnectionProfileGroup>e.source;
const oldParent = <ConnectionProfileGroup>this._tree.getElementById(e.oldGroupId);
const newParent = <ConnectionProfileGroup>this._tree.getElementById(e.newGroupId);
// Storing the expanded state of children of the moved group so that they can be expanded after the move.
const profileExpandedState = this._tree.getExpandedState(movedGroup);
oldParent.children = oldParent.children.filter(c => c.id !== movedGroup.id);
await this._tree.updateChildren(oldParent);
newParent.children.push(movedGroup);
(<ConnectionProfileGroup>movedGroup).parent = newParent;
(<ConnectionProfileGroup>movedGroup).parentId = newParent.id;
await this._tree.updateChildren(newParent);
await this._tree.revealSelectFocusElement(movedGroup);
// Expanding the previously expanded children of the moved group after the move.
this._tree.expandElements(profileExpandedState);
}
}));
return new Promise<void>(async (resolve, reject) => {
await this.refreshTree();
const root = <ConnectionProfileGroup>this._tree!.getInput();
@@ -216,9 +377,10 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
const expandGroups = this._configurationService.getValue<{ autoExpand: boolean }>(SERVER_GROUP_CONFIG).autoExpand;
if (expandGroups) {
if (this._tree instanceof AsyncServerTree) {
await Promise.all(ConnectionProfileGroup.getSubgroups(root).map(subgroup => {
return this._tree!.expand(subgroup);
}));
const subGroups = ConnectionProfileGroup.getSubgroups(root);
for (let group of subGroups) {
await this._tree.expand(group);
}
} else {
await this._tree!.expandAll(ConnectionProfileGroup.getSubgroups(root));
}
@@ -246,26 +408,6 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
}
if (this._tree instanceof AsyncServerTree) {
// When new connection groups are added the event is fired with undefined so
// we still want to refresh the tree in that case to pick up the changes
await this.refreshTree();
if (newProfile) {
const currentSelections = this._tree.getSelection();
const currentSelectedElement = currentSelections && currentSelections.length >= 1 ? currentSelections[0] : undefined;
const newProfileIsSelected = currentSelectedElement && currentSelectedElement.id === newProfile.id;
// Clear any other selected elements first
if (currentSelectedElement && !newProfileIsSelected) {
this._tree.setSelection([]);
}
const newConnectionProfile = this.getConnectionInTreeInput(newProfile.id);
if (newConnectionProfile) {
// Re-render to update the connection status badge
this._tree.rerender(newConnectionProfile);
this._tree.setSelection([newConnectionProfile]);
this._tree.expand(newConnectionProfile);
}
}
} else {
if (newProfile) {
const groups = this._connectionManagementService.getConnectionGroups();
@@ -324,17 +466,39 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
}
}
private async disconnectConnection(profile: ConnectionProfile, deleteConnFromConnectionService: boolean = false): Promise<void> {
if (this._tree instanceof AsyncServerTree) {
if (deleteConnFromConnectionService) {
await this._connectionManagementService.deleteConnection(profile);
}
const connectionProfile = this.getConnectionInTreeInput(profile.id);
// Delete the node from the tree
await this._objectExplorerService.deleteObjectExplorerNode(connectionProfile);
// Collapse the node
await this._tree.collapse(connectionProfile);
// Rerendering node to turn the badge red
await this._tree.rerender(connectionProfile);
connectionProfile.isDisconnecting = true;
await this._tree.updateChildren(connectionProfile);
connectionProfile.isDisconnecting = false;
// Make the connection dirty so that the next expansion will refresh the node
await this._tree.makeElementDirty(connectionProfile);
await this._tree.revealSelectFocusElement(connectionProfile);
}
}
private async onObjectExplorerSessionCreated(connection: IConnectionProfile): Promise<void> {
const element = this.getConnectionInTreeInput(connection.id);
if (element) {
if (this._tree instanceof AsyncServerTree) {
this._tree.rerender(element);
await this._tree.rerender(element);
await this._tree.revealSelectFocusElement(element);
} else {
await this._tree!.refresh(element);
await this._tree!.expand(element);
await this._tree!.reveal(element, 0.5);
this._treeSelectionHandler.onTreeActionStateChange(false);
}
await this._tree!.expand(element);
await this._tree!.reveal(element, 0.5);
this._treeSelectionHandler.onTreeActionStateChange(false);
}
}
@@ -354,7 +518,8 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
// Collapse the node before refreshing so the refresh doesn't try to fetch
// the children again (which causes it to try and connect)
this._tree.collapse(conn);
await this.refreshTree();
this._tree.rerender(conn);
this._tree.makeElementDirty(conn);
} else {
await this._tree!.collapse(conn);
return this._tree!.refresh(conn);
@@ -416,7 +581,7 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
/**
* Set tree elements based on the view (recent/active)
*/
public showFilteredTree(view: ServerTreeViewView): void {
public async showFilteredTree(view: ServerTreeViewView): Promise<void> {
hide(this.messages!);
this._viewKey.set(view);
const root = TreeUpdateUtils.getTreeInput(this._connectionManagementService);
@@ -430,24 +595,29 @@ export class ServerTreeView extends Disposable implements IServerTreeView {
} else {
treeInput = filteredResults[0];
}
this._tree!.setInput(treeInput!).then(async () => {
if (isHidden(this.messages!)) {
this._tree!.getFocus();
if (this._tree instanceof AsyncServerTree) {
await Promise.all(ConnectionProfileGroup.getSubgroups(treeInput!).map(subgroup => {
this._tree!.expand(subgroup);
}));
} else {
await this._tree!.expandAll(ConnectionProfileGroup.getSubgroups(treeInput!));
if (this._tree instanceof AsyncServerTree) {
await this._tree.setInput(treeInput!);
await this._tree.updateChildren(treeInput!);
return;
}
await this._tree.setInput(treeInput!);
if (isHidden(this.messages!)) {
this._tree.getFocus();
if (this._tree instanceof AsyncServerTree) {
for (const subgroup of ConnectionProfileGroup.getSubgroups(treeInput)) {
await this._tree.expand(subgroup);
}
} else {
if (this._tree instanceof AsyncServerTree) {
this._tree.setFocus([]);
} else {
this._tree!.clearFocus();
}
await this._tree!.expandAll(ConnectionProfileGroup.getSubgroups(treeInput!));
}
}, errors.onUnexpectedError);
} else {
if (this._tree instanceof AsyncServerTree) {
this._tree.setFocus([]);
} else {
this._tree!.clearFocus();
}
}
} else {
//no op
}