Skip to content

Commit 8969db8

Browse files
authored
[Chat] Update stateful client to return an empty string in failure cases (#4230)
1 parent f5e7187 commit 8969db8

5 files changed

Lines changed: 40 additions & 29 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "minor",
3+
"area": "feature",
4+
"workstream": "InlineImages",
5+
"comment": "Chat Stateful Client now returns and empty string in cases of errors",
6+
"packageName": "@azure/communication-react",
7+
"email": "9044372+JoshuaLai@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "minor",
3+
"area": "feature",
4+
"workstream": "InlineImages",
5+
"comment": "Chat Stateful Client now returns and empty string in cases of errors",
6+
"packageName": "@azure/communication-react",
7+
"email": "9044372+JoshuaLai@users.noreply.github.com",
8+
"dependentChangeType": "patch"
9+
}

packages/chat-component-bindings/src/messageThreadSelector.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
getUserId
1212
} from './baseSelectors';
1313
import { toFlatCommunicationIdentifier } from '@internal/acs-ui-common';
14-
import { ChatClientState, ChatMessageWithStatus } from '@internal/chat-stateful-client';
14+
import { ChatClientState, ChatMessageWithStatus, ResourceFetchResult } from '@internal/chat-stateful-client';
1515
import { memoizeFnAll } from '@internal/acs-ui-common';
1616
import {
1717
ChatMessage,
@@ -158,8 +158,8 @@ const processChatMessageContent = (message: ChatMessageWithStatus): string | und
158158
document.querySelectorAll('img').forEach((img) => {
159159
const attachmentPreviewUrl = attachments.find((attachment) => attachment.id === img.id)?.previewUrl;
160160
if (attachmentPreviewUrl) {
161-
const src = message.resourceCache?.[attachmentPreviewUrl].sourceUrl ?? '';
162-
img.src = src;
161+
const resourceCache = message.resourceCache?.[attachmentPreviewUrl];
162+
img.src = getResourceSourceUrl(resourceCache);
163163
}
164164
});
165165
content = document.body.innerHTML;
@@ -185,13 +185,24 @@ const processChatMessageContent = (message: ChatMessageWithStatus): string | und
185185
const generateImageAttachmentImgHtml = (message: ChatMessageWithStatus, attachment: ChatAttachment): string => {
186186
if (attachment.previewUrl !== undefined) {
187187
const contentType = extractAttachmentContentTypeFromName(attachment.name);
188-
const src = message.resourceCache?.[attachment.previewUrl].sourceUrl ?? '';
188+
const resourceCache = message.resourceCache?.[attachment.previewUrl];
189+
const src = getResourceSourceUrl(resourceCache);
190+
189191
return `\r\n<p><img alt="image" src="${src}" itemscope="${contentType}" id="${attachment.id}"></p>`;
190192
}
191193

192194
return '';
193195
};
194196

197+
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
198+
const getResourceSourceUrl = (result?: ResourceFetchResult): string => {
199+
let src = 'blob://';
200+
if (result && result.error === undefined) {
201+
src = result.sourceUrl;
202+
}
203+
return src;
204+
};
205+
195206
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
196207
const extractAttachmentContentTypeFromName = (name?: string): string => {
197208
if (name === undefined) {

packages/chat-stateful-client/src/ResourceDownloadQueue.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { CommunicationTokenCredential } from '@azure/communication-common';
77
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
88
import { ChatContext } from './ChatContext';
99
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
10-
import { ResourceDownloadError, ResourceDownloadQueue } from './ResourceDownloadQueue';
10+
import { ResourceDownloadQueue } from './ResourceDownloadQueue';
1111
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
1212
import { messageTemplate } from './mocks/createMockChatThreadClient';
1313
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
@@ -224,8 +224,7 @@ describe('ResourceDownloadQueue api functions', () => {
224224

225225
const queue = new ResourceDownloadQueue(context, tokenCredential);
226226
const operation = jest.fn();
227-
const e = new ResourceDownloadError(first);
228-
operation.mockRejectedValueOnce(e);
227+
operation.mockRejectedValueOnce(new Error('mock error'));
229228
queue.addMessage(first);
230229
queue.addMessage(second);
231230
queue.addMessage(third);
@@ -282,6 +281,7 @@ describe('ResourceDownloadQueue api functions', () => {
282281
const resourceCache = context.getState().threads[threadId].chatMessages[messageId].resourceCache;
283282
expect(resourceCache).toBeDefined();
284283
expect(resourceCache?.['previewUrl1'].error).toBeDefined();
284+
expect(resourceCache?.['previewUrl1'].sourceUrl).toEqual('');
285285
});
286286
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
287287
test('if operation fails for first item, error should be in the cache only for first item', async () => {
@@ -322,6 +322,7 @@ describe('ResourceDownloadQueue api functions', () => {
322322
const resourceCache = context.getState().threads[threadId].chatMessages[messageId].resourceCache;
323323
expect(resourceCache).toBeDefined();
324324
expect(resourceCache?.['previewUrl1'].error).toBeDefined();
325+
expect(resourceCache?.['previewUrl1'].sourceUrl).toEqual('');
325326
expect(resourceCache?.['previewUrl2'].error).toBeUndefined();
326327
expect(resourceCache?.['previewUrl3'].error).toBeUndefined();
327328
});

packages/chat-stateful-client/src/ResourceDownloadQueue.ts

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export class ResourceDownloadQueue {
1818
private _context: ChatContext;
1919
private isActive = false;
2020
private _credential: CommunicationTokenCredential;
21-
private _errors: ResourceDownloadError[] = [];
2221

2322
constructor(context: ChatContext, credential: CommunicationTokenCredential) {
2423
this._context = context;
@@ -41,10 +40,6 @@ export class ResourceDownloadQueue {
4140
return contains;
4241
}
4342

44-
public get errors(): ResourceDownloadError[] {
45-
return this._errors;
46-
}
47-
4843
public addMessage(message: ChatMessageWithStatus): void {
4944
// make a copy of message and add to queue
5045
const copy = { ...message };
@@ -79,7 +74,7 @@ export class ResourceDownloadQueue {
7974
resourceUrl: string,
8075
operation: ImageRequest
8176
): Promise<ChatMessageWithStatus> {
82-
const response: ResourceFetchResult = { sourceUrl: URL.createObjectURL(new Blob()) };
77+
const response: ResourceFetchResult = { sourceUrl: '' };
8378
try {
8479
const blobUrl = await this.downloadResource(operation, resourceUrl);
8580
response.sourceUrl = blobUrl;
@@ -102,7 +97,7 @@ export class ResourceDownloadQueue {
10297
}
10398
for (const attachment of attachments) {
10499
if (attachment.previewUrl && attachment.attachmentType === 'image') {
105-
const response: ResourceFetchResult = { sourceUrl: URL.createObjectURL(new Blob()) };
100+
const response: ResourceFetchResult = { sourceUrl: '' };
106101
try {
107102
const blobUrl = await this.downloadResource(operation, attachment.previewUrl);
108103
response.sourceUrl = blobUrl;
@@ -118,8 +113,7 @@ export class ResourceDownloadQueue {
118113
}
119114

120115
private async downloadResource(operation: ImageRequest, url: string): Promise<string> {
121-
let blobUrl = URL.createObjectURL(new Blob());
122-
blobUrl = await operation(url, this._credential);
116+
const blobUrl = await operation(url, this._credential);
123117
return blobUrl;
124118
}
125119
}
@@ -164,16 +158,3 @@ export const fetchImageSource = async (src: string, credential: CommunicationTok
164158
interface ImageRequest {
165159
(request: string, credential: CommunicationTokenCredential): Promise<string>;
166160
}
167-
168-
/* @conditional-compile-remove(teams-inline-images-and-file-sharing) */
169-
/**
170-
* @private
171-
*/
172-
export class ResourceDownloadError extends Error {
173-
public chatMessageWithStatus: ChatMessageWithStatus;
174-
175-
constructor(chatMessageWithStatus: ChatMessageWithStatus) {
176-
super();
177-
this.chatMessageWithStatus = chatMessageWithStatus;
178-
}
179-
}

0 commit comments

Comments
 (0)