Skip to content

Commit 66227c6

Browse files
committed
feat: drop generics for custom typing
BREAKING CHANGE: stream-chat types are no longer generic, see how you can type your custom types in the SDK v6 upgrade guide
1 parent a473196 commit 66227c6

File tree

54 files changed

+805
-887
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+805
-887
lines changed

package-lock.json

Lines changed: 159 additions & 87 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@
118118
"pretty-bytes": "^6.1.1",
119119
"rxjs": "~7.4.0",
120120
"starwars-names": "^1.6.0",
121-
"stream-chat": "^8.44.0",
121+
"stream-chat": "9.0.0-rc.3",
122122
"ts-node": "^10.9.2",
123123
"tslib": "^2.3.0",
124124
"uuid": "^9.0.1",

projects/customizations-example/src/app/message-action/message-action.component.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Component, Input } from '@angular/core';
22
import {
3-
DefaultStreamChatGenerics,
43
MessageActionHandlerExtraParams,
54
StreamMessage,
65
} from 'stream-chat-angular';
@@ -13,9 +12,9 @@ import {
1312
export class MessageActionComponent {
1413
@Input() actionName!: 'quote' | 'pin' | 'flag' | 'edit' | 'delete';
1514
@Input() actionLabelOrTranslationKey!:
16-
| ((m: StreamMessage<DefaultStreamChatGenerics>) => string)
15+
| ((m: StreamMessage) => string)
1716
| string;
18-
@Input() message!: StreamMessage<DefaultStreamChatGenerics>;
17+
@Input() message!: StreamMessage;
1918
@Input() extraParams!: MessageActionHandlerExtraParams;
2019
@Input() actionHandler!: (
2120
message: StreamMessage,
@@ -36,9 +35,7 @@ export class MessageActionComponent {
3635
}
3736

3837
getActionLabel(
39-
actionLabelOrTranslationKey:
40-
| ((m: StreamMessage<DefaultStreamChatGenerics>) => string)
41-
| string
38+
actionLabelOrTranslationKey: ((m: StreamMessage) => string) | string
4239
) {
4340
return typeof actionLabelOrTranslationKey === 'string'
4441
? actionLabelOrTranslationKey

projects/customizations-example/src/app/message-text/message-text.component.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import { Component, Input } from '@angular/core';
2-
import { MessageResponseBase } from 'stream-chat';
3-
import { DefaultStreamChatGenerics, StreamMessage } from 'stream-chat-angular';
2+
import { StreamMessage } from 'stream-chat-angular';
43

54
@Component({
65
selector: 'app-message-text',
76
templateUrl: './message-text.component.html',
87
styleUrls: ['./message-text.component.scss'],
98
})
109
export class MessageTextComponent {
11-
@Input() message:
12-
| StreamMessage<DefaultStreamChatGenerics>
13-
| undefined
14-
| MessageResponseBase<DefaultStreamChatGenerics>;
10+
@Input() message: StreamMessage | undefined | StreamMessage['quoted_message'];
1511
@Input() isQuoted: boolean = false;
1612
@Input() shouldTranslate: boolean = false;
1713
isExpanded = false;

projects/stream-chat-angular/src/lib/attachment-configuration.service.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { Injectable } from '@angular/core';
22
import { Attachment } from 'stream-chat';
33
import {
44
AttachmentConfigration,
5-
DefaultStreamChatGenerics,
65
ImageAttachmentConfiguration,
76
VideoAttachmentConfiguration,
87
} from './types';
@@ -13,35 +12,33 @@ import {
1312
@Injectable({
1413
providedIn: 'root',
1514
})
16-
export class AttachmentConfigurationService<
17-
T extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
18-
> {
15+
export class AttachmentConfigurationService {
1916
/**
2017
* A custom handler can be provided to override the default image attachment (images uploaded from files) configuration. By default the SDK uses fixed image height (a size that's known before image is loaded), if you override that with dynamic image height (for example: height: 100%) the scrolling logic inside the message list can break.
2118
*/
2219
customImageAttachmentConfigurationHandler?: (
23-
a: Attachment<T>,
20+
a: Attachment,
2421
type: 'gallery' | 'single' | 'carousel',
2522
containerElement: HTMLElement
2623
) => ImageAttachmentConfiguration;
2724
/**
2825
* A custom handler can be provided to override the default video attachment (videos uploaded from files) configuration. By default the SDK uses fixed height (a size that's known before video is loaded), if you override that with dynamic height (for example: height: 100%) the scrolling logic inside the message list can break.
2926
*/
3027
customVideoAttachmentConfigurationHandler?: (
31-
a: Attachment<T>,
28+
a: Attachment,
3229
containerElement: HTMLElement
3330
) => VideoAttachmentConfiguration;
3431
/**
3532
* A custom handler can be provided to override the default giphy attachment (GIFs sent with the /giphy command) configuration. By default the SDK uses fixed height (a size that's known before the GIF is loaded), if you override that with dynamic height (for example: height: 100%) the scrolling logic inside the message list can break.
3633
*/
3734
customGiphyAttachmentConfigurationHandler?: (
38-
a: Attachment<T>
35+
a: Attachment
3936
) => AttachmentConfigration;
4037
/**
4138
* A custom handler can be provided to override the default scraped image attachment (images found in links inside messages) configuration. By default the SDK uses fixed height (a size that's known before image is loaded), if you override that with dynamic height (for example: height: 100%) the scrolling logic inside the message list can break.
4239
*/
4340
customScrapedImageAttachmentConfigurationHandler?: (
44-
a: Attachment<T>
41+
a: Attachment
4542
) => AttachmentConfigration;
4643
/**
4744
* You can turn on/off thumbnail generation for video attachments
@@ -55,7 +52,7 @@ export class AttachmentConfigurationService<
5552
* @param element The default resizing logics reads the height/max-height and max-width propperties of this element and reduces file size based on the given values. File size reduction is done by Stream's CDN.
5653
*/
5754
getImageAttachmentConfiguration(
58-
attachment: Attachment<T>,
55+
attachment: Attachment,
5956
location: 'gallery' | 'single' | 'carousel',
6057
element: HTMLElement
6158
): ImageAttachmentConfiguration {
@@ -68,10 +65,8 @@ export class AttachmentConfigurationService<
6865
}
6966

7067
const defaultOriginalDimension = 1000000;
71-
const urlString = (attachment.img_url ||
72-
attachment.thumb_url ||
73-
attachment.image_url ||
74-
'') as string;
68+
const urlString =
69+
attachment.img_url || attachment.thumb_url || attachment.image_url || '';
7570
let url: URL;
7671
try {
7772
url = new URL(urlString);
@@ -121,7 +116,7 @@ export class AttachmentConfigurationService<
121116
* @param element The default resizing logics reads the height/max-height and max-width propperties of this element and reduces file size based on the given values. File size reduction is done by Stream's CDN.
122117
*/
123118
getVideoAttachmentConfiguration(
124-
attachment: Attachment<T>,
119+
attachment: Attachment,
125120
element: HTMLElement
126121
): VideoAttachmentConfiguration {
127122
if (this.customVideoAttachmentConfigurationHandler) {
@@ -178,7 +173,7 @@ export class AttachmentConfigurationService<
178173
* @param attachment The attachment to configure
179174
*/
180175
getGiphyAttachmentConfiguration(
181-
attachment: Attachment<T>
176+
attachment: Attachment
182177
): AttachmentConfigration {
183178
if (this.customGiphyAttachmentConfigurationHandler) {
184179
return this.customGiphyAttachmentConfigurationHandler(attachment);
@@ -198,7 +193,7 @@ export class AttachmentConfigurationService<
198193
* @param attachment The attachment to configure
199194
*/
200195
getScrapedImageAttachmentConfiguration(
201-
attachment: Attachment<T>
196+
attachment: Attachment
202197
): AttachmentConfigration {
203198
if (this.customScrapedImageAttachmentConfigurationHandler) {
204199
return this.customScrapedImageAttachmentConfigurationHandler(attachment);

projects/stream-chat-angular/src/lib/attachment-list/attachment-list.component.html

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
isVoiceMessage(attachment)
2222
"
2323
[class.str-chat__message-attachment-with-actions]="
24-
attachment.actions && attachment.actions.length > 0
24+
!isGalleryType(attachment) &&
25+
attachment.actions &&
26+
attachment.actions.length > 0
2527
"
2628
[class.str-chat__message-attachment--svg-image]="isSvg(attachment)"
2729
>
@@ -406,7 +408,13 @@
406408
</div>
407409
</ng-template>
408410
</ng-container>
409-
<ng-container *ngIf="attachment.actions && attachment.actions.length > 0">
411+
<ng-container
412+
*ngIf="
413+
!isGalleryType(attachment) &&
414+
attachment.actions &&
415+
attachment.actions.length > 0
416+
"
417+
>
410418
<ng-container
411419
*ngTemplateOutlet="
412420
(customTemplatesService.attachmentActionsTemplate$ | async) ||

projects/stream-chat-angular/src/lib/attachment-list/attachment-list.component.spec.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ import { ChannelService } from '../channel.service';
1111
import { StreamI18nService } from '../stream-i18n.service';
1212
import { AttachmentListComponent } from './attachment-list.component';
1313
import { Attachment } from 'stream-chat';
14-
import {
15-
CustomAttachmentListContext,
16-
DefaultStreamChatGenerics,
17-
} from '../types';
14+
import { CustomAttachmentListContext, GalleryAttachment } from '../types';
1815
import { AttachmentConfigurationService } from '../attachment-configuration.service';
1916
import {
2017
AfterViewInit,
@@ -195,6 +192,7 @@ describe('AttachmentListComponent', () => {
195192
it('should filter custom attachments', () => {
196193
const messageService = TestBed.inject(MessageService);
197194
messageService.filterCustomAttachment = (attachment: Attachment) =>
195+
// @ts-expect-error custom property
198196
!attachment.customLink;
199197
const imageAttachment = {
200198
type: 'image',
@@ -276,8 +274,12 @@ describe('AttachmentListComponent', () => {
276274

277275
expect(orderedAttachments.length).toBe(2);
278276
expect(orderedAttachments[0].type).toBe('gallery');
279-
expect(orderedAttachments[0].images![0].img_url).toBe('http://url1');
280-
expect(orderedAttachments[0].images![1].img_url).toBe('http://url2');
277+
expect((orderedAttachments[0] as GalleryAttachment).images[0].img_url).toBe(
278+
'http://url1'
279+
);
280+
expect((orderedAttachments[0] as GalleryAttachment).images[1].img_url).toBe(
281+
'http://url2'
282+
);
281283
});
282284

283285
it('should display gallery', () => {
@@ -380,7 +382,7 @@ describe('AttachmentListComponent', () => {
380382
frames: '6',
381383
},
382384
},
383-
} as any as Attachment<DefaultStreamChatGenerics>;
385+
} as any as Attachment;
384386
component.attachments = [attachment];
385387
component.ngOnChanges({ attachments: {} as SimpleChange });
386388
fixture.detectChanges();
@@ -435,7 +437,7 @@ describe('AttachmentListComponent', () => {
435437
frames: '6',
436438
},
437439
},
438-
} as any as Attachment<DefaultStreamChatGenerics>;
440+
} as any as Attachment;
439441
component.messageId = 'message-id';
440442
component.attachments = [attachment];
441443
component.parentMessageId = 'parent-id';

projects/stream-chat-angular/src/lib/attachment-list/attachment-list.component.ts

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import {
1414
import { Action, Attachment } from 'stream-chat';
1515
import {
1616
ModalContext,
17-
DefaultStreamChatGenerics,
1817
AttachmentConfigration,
1918
VideoAttachmentConfiguration,
2019
ImageAttachmentConfiguration,
2120
AttachmentContext,
2221
CustomAttachmentListContext,
22+
GalleryAttachment,
2323
} from '../types';
2424
import prettybytes from 'pretty-bytes';
2525
import { isImageAttachment } from '../is-image-attachment';
@@ -49,17 +49,17 @@ export class AttachmentListComponent implements OnChanges, OnInit, OnDestroy {
4949
/**
5050
* The attachments to display
5151
*/
52-
@Input() attachments: Attachment<DefaultStreamChatGenerics>[] = [];
52+
@Input() attachments: Attachment[] = [];
5353
/**
5454
* Emits the state of the image carousel window
5555
*/
5656
@Output() readonly imageModalStateChange = new EventEmitter<
5757
'opened' | 'closed'
5858
>();
5959
@HostBinding() class = 'str-chat__attachment-list-angular-host';
60-
orderedAttachments: Attachment<DefaultStreamChatGenerics>[] = [];
61-
customAttachments: Attachment<DefaultStreamChatGenerics>[] = [];
62-
imagesToView: Attachment<DefaultStreamChatGenerics>[] = [];
60+
orderedAttachments: (Attachment | GalleryAttachment)[] = [];
61+
customAttachments: Attachment[] = [];
62+
imagesToView: Attachment[] = [];
6363
imagesToViewCurrentIndex = 0;
6464
customAttachmentsTemplate?: TemplateRef<CustomAttachmentListContext>;
6565
@ViewChild('modalContent', { static: true })
@@ -79,6 +79,12 @@ export class AttachmentListComponent implements OnChanges, OnInit, OnDestroy {
7979
private messageService: MessageService
8080
) {}
8181

82+
trackByUrl = (_: number, attachment: Attachment | GalleryAttachment) => {
83+
return this.isGalleryType(attachment)
84+
? attachment.images.map(this.getAttachmentUrl).join(',')
85+
: this.getAttachmentUrl(attachment);
86+
};
87+
8288
ngOnInit(): void {
8389
this.subscriptions.push(
8490
this.customTemplatesService.customAttachmentListTemplate$.subscribe(
@@ -122,15 +128,6 @@ export class AttachmentListComponent implements OnChanges, OnInit, OnDestroy {
122128
this.subscriptions.forEach((s) => s.unsubscribe());
123129
}
124130

125-
trackByUrl(_: number, attachment: Attachment) {
126-
return (
127-
attachment.image_url ||
128-
attachment.img_url ||
129-
attachment.asset_url ||
130-
attachment.thumb_url
131-
);
132-
}
133-
134131
isImage(attachment: Attachment) {
135132
return isImageAttachment(attachment);
136133
}
@@ -169,13 +166,13 @@ export class AttachmentListComponent implements OnChanges, OnInit, OnDestroy {
169166
return attachment.type === 'voiceRecording';
170167
}
171168

172-
hasFileSize(attachment: Attachment<DefaultStreamChatGenerics>) {
169+
hasFileSize(attachment: Attachment) {
173170
return (
174171
attachment.file_size && Number.isFinite(Number(attachment.file_size))
175172
);
176173
}
177174

178-
getFileSize(attachment: Attachment<DefaultStreamChatGenerics>) {
175+
getFileSize(attachment: Attachment) {
179176
return prettybytes(Number(attachment.file_size!));
180177
}
181178

@@ -226,9 +223,7 @@ export class AttachmentListComponent implements OnChanges, OnInit, OnDestroy {
226223
return item.image_url || item.img_url || item.thumb_url;
227224
}
228225

229-
getAttachmentContext(
230-
attachment: Attachment<DefaultStreamChatGenerics>
231-
): AttachmentContext {
226+
getAttachmentContext(attachment: Attachment): AttachmentContext {
232227
return { attachment };
233228
}
234229

@@ -298,6 +293,12 @@ export class AttachmentListComponent implements OnChanges, OnInit, OnDestroy {
298293
}
299294
}
300295

296+
isGalleryType(
297+
attachment: Attachment | GalleryAttachment
298+
): attachment is GalleryAttachment {
299+
return attachment.type === 'gallery';
300+
}
301+
301302
get isImageModalPrevButtonVisible() {
302303
return this.imagesToViewCurrentIndex !== 0;
303304
}
@@ -306,7 +307,7 @@ export class AttachmentListComponent implements OnChanges, OnInit, OnDestroy {
306307
return this.imagesToViewCurrentIndex !== this.imagesToView.length - 1;
307308
}
308309

309-
private createGallery(images: Attachment[]) {
310+
private createGallery(images: Attachment[]): GalleryAttachment[] {
310311
return [
311312
{
312313
type: 'gallery',
@@ -319,4 +320,13 @@ export class AttachmentListComponent implements OnChanges, OnInit, OnDestroy {
319320
this.imageModalStateChange.next('closed');
320321
this.imagesToView = [];
321322
}
323+
324+
private getAttachmentUrl(attachment: Attachment) {
325+
return (
326+
attachment.image_url ||
327+
attachment.img_url ||
328+
attachment.asset_url ||
329+
attachment.thumb_url
330+
);
331+
}
322332
}

projects/stream-chat-angular/src/lib/attachment.service.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { AppSettings, Attachment } from 'stream-chat';
44
import { AttachmentService } from './attachment.service';
55
import { ChannelService } from './channel.service';
66
import { NotificationService } from './notification.service';
7-
import { AttachmentUpload, DefaultStreamChatGenerics } from './types';
7+
import { AttachmentUpload } from './types';
88
import { Subject } from 'rxjs';
99
import { ChatClientService } from './chat-client.service';
1010
import { MessageService } from './message.service';
1111

1212
describe('AttachmentService', () => {
13-
let service: AttachmentService<DefaultStreamChatGenerics>;
13+
let service: AttachmentService;
1414
let uploadAttachmentsSpy: jasmine.Spy;
1515
let deleteAttachmentSpy: jasmine.Spy;
1616
let readAsDataURLSpy: jasmine.Spy;
@@ -534,6 +534,7 @@ describe('AttachmentService', () => {
534534

535535
const customPaymentAttachment: Attachment = {
536536
type: 'custom',
537+
// @ts-expect-error testing custom proerpty
537538
subtype: 'payment',
538539
value: '30$',
539540
link: 'pay/me/or/else',

0 commit comments

Comments
 (0)