diff --git a/src/web/client/WebExtensionContext.ts b/src/web/client/WebExtensionContext.ts index 53f02347..c54d7438 100644 --- a/src/web/client/WebExtensionContext.ts +++ b/src/web/client/WebExtensionContext.ts @@ -29,7 +29,7 @@ import { FileDataMap } from "./context/fileDataMap"; import { IAttributePath, IEntityInfo } from "./common/interfaces"; import { ConcurrencyHandler } from "./dal/concurrencyHandler"; import { getMailToPath, getTeamChatURL, isMultifileEnabled } from "./utilities/commonUtil"; -import { UserDataMap } from "./context/userDataMap"; +import { IConnectionData, UserDataMap } from "./context/userDataMap"; import { EntityForeignKeyDataMap } from "./context/entityForeignKeyDataMap"; import { QuickPickProvider } from "./webViews/QuickPickProvider"; import { UserCollaborationProvider } from "./webViews/userCollaborationProvider"; @@ -776,18 +776,20 @@ class WebExtensionContext implements IWebExtensionContext { containerId: string, userName: string, userId: string, - entityId: string[] + entityId: string[], + connectionData: IConnectionData[], ) { this.connectedUsers.setUserData( containerId, userName, userId, - entityId + entityId, + connectionData ); } - public async removeConnectedUserInContext(userId: string) { - this.connectedUsers.removeUser(userId); + public async removeConnectedUserInContext(userId: string, removeConnectionData: IConnectionData) { + this.connectedUsers.removeUser(userId, removeConnectionData); } public async getMail(userId: string): Promise { diff --git a/src/web/client/common/worker/webworker.js b/src/web/client/common/worker/webworker.js index 2451c4ac..813af596 100644 --- a/src/web/client/common/worker/webworker.js +++ b/src/web/client/common/worker/webworker.js @@ -120,6 +120,7 @@ async function loadContainer(config, swpId, entityInfo) { .get(user.userId).connections; const userEntityIdArray = []; + const userConnectionData = []; const connectionIdInContainer = await map .get("selection") @@ -129,6 +130,7 @@ async function loadContainer(config, swpId, entityInfo) { userEntityIdArray.push( connectionIdInContainer.get(connection.id) ); + userConnectionData.push({ connectionId: connection.id, entityId: connectionIdInContainer.get(connection.id) }); }); // aadObjectId is the unique identifier for a user @@ -138,6 +140,7 @@ async function loadContainer(config, swpId, entityInfo) { userName: user.userName, containerId: swpId, entityId: userEntityIdArray, + connectionData: userConnectionData, }); self.postMessage({ @@ -152,6 +155,8 @@ async function loadContainer(config, swpId, entityInfo) { self.postMessage({ type: "member-removed", userId: member.additionalDetails.AadObjectId, + entityInfo: entityInfo, + removeConnectionData: { connectionId: clientId, entityId: entityInfo.rootWebPageId }, }); self.postMessage({ type: "telemetry-info", @@ -176,6 +181,7 @@ async function loadContainer(config, swpId, entityInfo) { .get(user.userId).connections; const userEntityIdArray = []; + const userConnectionData = []; const connectionIdInContainer = await map .get("selection") @@ -185,6 +191,7 @@ async function loadContainer(config, swpId, entityInfo) { userEntityIdArray.push( connectionIdInContainer.get(connection.id) ); + userConnectionData.push({ connectionId: connection.id, entityId: connectionIdInContainer.get(connection.id) }); }); // aadObjectId is the unique identifier for a user @@ -194,6 +201,7 @@ async function loadContainer(config, swpId, entityInfo) { userName: user.userName, containerId: swpId, entityId: userEntityIdArray, + connectionData: userConnectionData, }); self.postMessage({ diff --git a/src/web/client/context/userDataMap.ts b/src/web/client/context/userDataMap.ts index 3e0d10cf..41d5f22d 100644 --- a/src/web/client/context/userDataMap.ts +++ b/src/web/client/context/userDataMap.ts @@ -9,11 +9,17 @@ export interface IUserData { userId: string; } +export interface IConnectionData { + connectionId: string; + entityId: string; +} + export class UserData implements IUserData { _containerId: string; _userName: string; _userId: string; _entityId: string[]; + _connectionData: IConnectionData[]; // Getters public get containerId(): string { @@ -28,17 +34,27 @@ export class UserData implements IUserData { public get entityId(): string[] { return this._entityId; } + public get connectionData(): IConnectionData[] { + return this._connectionData; + } + + // Setters + public setConnectionData(connectionData: IConnectionData[]): void { + this._connectionData = connectionData; + } constructor( containerId: string, userName: string, userId: string, - entityId: string[] + entityId: string[], + connectionData: IConnectionData[] ) { this._containerId = containerId; this._userName = userName; this._userId = userId; this._entityId = entityId; + this._connectionData = connectionData; } } @@ -53,19 +69,36 @@ export class UserDataMap { containerId: string, userName: string, userId: string, - entityId: string[] + entityId: string[], + connectionData: IConnectionData[] ) { const userData = new UserData( containerId, userName, userId, - entityId + entityId, + connectionData ); this.usersMap.set(userId, userData); } - public removeUser(userId: string) { - this.usersMap.delete(userId); + public removeUser(userId: string, removeConnectionData: IConnectionData) { + const connectionData = this.usersMap.get(userId)?.connectionData ?? []; + + // Remove the connection data from the user's connection data + const newConnectionData = connectionData.filter(connection => { + return !(connection.connectionId === removeConnectionData.connectionId && connection.entityId[0] === removeConnectionData.entityId); + }); + + const userData = this.usersMap.get(userId) as UserData; + userData.setConnectionData(newConnectionData); + + // If the user has no more connection data, remove the user from the map + if (newConnectionData.length === 0) { + this.usersMap.delete(userId); + } else { + this.usersMap.set(userId, userData); + } } } diff --git a/src/web/client/extension.ts b/src/web/client/extension.ts index f33aa5f2..dd5e82c3 100644 --- a/src/web/client/extension.ts +++ b/src/web/client/extension.ts @@ -385,7 +385,8 @@ export function createWebWorkerInstance( if (data.type === Constants.workerEventMessages.REMOVE_CONNECTED_USER) { WebExtensionContext.removeConnectedUserInContext( - data.userId + data.userId, + data.removeConnectionData ); WebExtensionContext.userCollaborationProvider.refresh(); WebExtensionContext.quickPickProvider.refresh(); @@ -395,7 +396,8 @@ export function createWebWorkerInstance( data.containerId, data.userName, data.userId, - data.entityId + data.entityId, + data.connectionData ); WebExtensionContext.userCollaborationProvider.refresh(); WebExtensionContext.quickPickProvider.refresh(); diff --git a/src/web/client/webViews/QuickPickProvider.ts b/src/web/client/webViews/QuickPickProvider.ts index 5601e3b5..33c415e8 100644 --- a/src/web/client/webViews/QuickPickProvider.ts +++ b/src/web/client/webViews/QuickPickProvider.ts @@ -42,9 +42,9 @@ export class QuickPickProvider { Array.from( connectedUsersMap.entries() ).map(([, value]) => { - if (value._entityId.length) { - value._entityId.forEach(async (entityId) => { - const contentPageId = WebExtensionContext.entityForeignKeyDataMap.getEntityForeignKeyMap.get(`${entityId}`); + if (value._connectionData.length) { + value._connectionData.forEach(async (connection) => { + const contentPageId = WebExtensionContext.entityForeignKeyDataMap.getEntityForeignKeyMap.get(`${connection.entityId[0]}`); if ( contentPageId &&