Skip to content

Commit b9543db

Browse files
committed
feat: Implement channel capabilities #63
1 parent 3b1090c commit b9543db

File tree

13 files changed

+178
-21
lines changed

13 files changed

+178
-21
lines changed

docusaurus/docs/Angular/components/message-input.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ If you want to create your own message input, you can use the [`ChannelService`]
2727

2828
### isFileUploadEnabled
2929

30-
If file upload is enabled, the user can open a file selector from the input.
30+
If file upload is enabled, the user can open a file selector from the input. Please note that the user also needs to have the necessary [channel capability](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript).
3131

3232
| Type | Default |
3333
| ------- | ------- |
34-
| boolean | false |
34+
| boolean | true |
3535

3636
### acceptedFileTypes
3737

docusaurus/docs/Angular/components/message-list.mdx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,19 @@ By default, the [default message component](./message.mdx) is used. To change th
5858
| Type |
5959
| ----------- |
6060
| TemplateRef |
61+
62+
### areReactionsEnabled
63+
64+
If true, the message reactions are displayed. Users can also react to messages if they have the necessary [channel capability](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript).
65+
66+
| Type | Default |
67+
| ------- | ------- |
68+
| boolean | true |
69+
70+
### enabledMessageActions
71+
72+
The list of [actions that are enabled](./message-actions.mdx), please note that the user also has to have the necessary [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) for actions to work. Unathorized actions won't be displayed on the UI.
73+
74+
| Type | Default |
75+
| --------------- | -------- |
76+
| MessageAction[] | ['flag'] |

docusaurus/docs/Angular/components/message.mdx

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,19 @@ The message list uses the `Message` component to display messages, if you want t
3737
<stream-message-input></stream-message-input>
3838
</stream-channel>
3939

40-
<ng-template #customMessageTemplate let-message="message">
41-
<app-custom-message [message]="message"></app-custom-message>
40+
<ng-template
41+
#customMessageTemplate
42+
let-message="message"
43+
let-enabledMessageActions="enabledMessageActions"
44+
let-areReactionsEnabled="areReactionsEnabled"
45+
let-canReactToMessage="canReactToMessage"
46+
>
47+
<app-custom-message
48+
[message]="message"
49+
[enabledMessageActions]="enabledMessageActions"
50+
[areReactionsEnabled]="areReactionsEnabled"
51+
[canReactToMessage]="canReactToMessage"
52+
></app-custom-message>
4253
</ng-template>
4354
```
4455

@@ -89,19 +100,33 @@ The `Message` component uses the [`Icon`](./icons.mdx) component to display icon
89100

90101
### enabledMessageActions
91102

92-
The list of [actions that are enabled](./message-actions.mdx).
103+
The list of [actions that are enabled](./message-actions.mdx), please note that the user also has to have the necessary [channel capabilities](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript) for actions to work. Unathorized actions won't be displayed on the UI.
93104

94-
| Type | Default |
95-
| --------------- | -------- |
96-
| MessageAction[] | ['flag'] |
105+
If you use the default chat UI you can also set this using the [`MessageList`](./message-list.mdx) component.
106+
107+
| Type |
108+
| --------------- |
109+
| MessageAction[] |
97110

98111
### areReactionsEnabled
99112

100-
If true, the message reactions are displayed, and the current user can react to messages.
113+
If true, the message reactions are displayed.
114+
115+
If you use the default chat UI you can also set this using the [`MessageList`](./message-list.mdx) component.
116+
117+
| Type |
118+
| ------- |
119+
| boolean |
120+
121+
### canReactToMessage
122+
123+
If true, the user can add reactions to the message.
124+
125+
If you use the default chat UI the [`MessageList`](./message-list.mdx) component automatically sets this based on [channel capability](https://getstream.io/chat/docs/javascript/channel_capabilities/?language=javascript).
101126

102-
| Type | Default |
103-
| ------- | ------- |
104-
| boolean | true |
127+
| Type |
128+
| ------ |
129+
| boolen |
105130

106131
### isLastSentMessage
107132

projects/stream-chat-angular/src/lib/message-input/message-input.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
></textarea>
141141
</div>
142142
<div
143-
*ngIf="isFileUploadEnabled"
143+
*ngIf="isFileUploadEnabled && isFileUploadAuthorized"
144144
class="str-chat__fileupload-wrapper"
145145
data-testid="file-upload-button"
146146
>

projects/stream-chat-angular/src/lib/message-input/message-input.component.spec.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,16 @@ describe('MessageInputComponent', () => {
158158
expect(textarea?.value).toBe('');
159159
});
160160

161-
it('should display file upload button, if #isFileUploadEnabled is true', () => {
161+
it('should display file upload button, if #isFileUploadEnabled is true and has permission to upload file', () => {
162162
expect(queryattachmentUploadButton()).not.toBeNull();
163+
164+
mockActiveChannel$.next({
165+
...channel,
166+
data: { own_capabilities: [] },
167+
} as any as Channel);
168+
fixture.detectChanges();
169+
170+
expect(queryattachmentUploadButton()).toBeNull();
163171
});
164172

165173
it(`shouldn't display file upload button, if #isFileUploadEnabled is false`, () => {

projects/stream-chat-angular/src/lib/message-input/message-input.component.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class MessageInputComponent implements OnDestroy {
2121
@Input() acceptedFileTypes: string[] | undefined;
2222
@Input() isMultipleFileUploadEnabled = true;
2323
attachmentUploads: AttachmentUpload[] = [];
24+
isFileUploadAuthorized: boolean | undefined;
2425
private attachmentUploadInProgressCounter = 0;
2526
@ViewChild('input') private messageInput!: ElementRef<HTMLInputElement>;
2627
@ViewChild('fileInput') private fileInput!: ElementRef<HTMLInputElement>;
@@ -32,11 +33,16 @@ export class MessageInputComponent implements OnDestroy {
3233
private notificationService: NotificationService
3334
) {
3435
this.subscriptions.push(
35-
this.channelService.activeChannel$.subscribe(() => {
36+
this.channelService.activeChannel$.subscribe((channel) => {
3637
if (this.messageInput) {
3738
this.messageInput.nativeElement.value = '';
3839
}
3940
this.attachmentUploads = [];
41+
const capabilities = channel?.data?.own_capabilities as string[];
42+
if (capabilities) {
43+
this.isFileUploadAuthorized =
44+
capabilities.indexOf('upload-file') !== -1;
45+
}
4046
})
4147
);
4248
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
messageTemplate;
2222
context: {
2323
message: message,
24+
areReactionsEnabled: areReactionsEnabled,
25+
canReactToMessage: canReactToMessage,
2426
lastSentMessageId: !!(
2527
lastSentMessageId && message?.id === lastSentMessageId
2628
)
@@ -31,9 +33,12 @@
3133
<ng-template #defaultMessageTemplate>
3234
<stream-message
3335
[message]="message"
36+
[areReactionsEnabled]="areReactionsEnabled"
37+
[canReactToMessage]="canReactToMessage"
3438
[isLastSentMessage]="
3539
!!(lastSentMessageId && message?.id === lastSentMessageId)
3640
"
41+
[enabledMessageActions]="enabledMessageActions"
3742
></stream-message>
3843
</ng-template>
3944
</li>

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { SimpleChange } from '@angular/core';
12
import {
23
ComponentFixture,
34
fakeAsync,
@@ -76,6 +77,10 @@ describe('MessageListComponent', () => {
7677
expect(m.isLastSentMessage).toBe(
7778
i === messages.length - 2 ? true : false
7879
);
80+
81+
expect(m.areReactionsEnabled).toBe(component.areReactionsEnabled);
82+
expect(m.canReactToMessage).toBe(component.canReactToMessage);
83+
expect(m.enabledMessageActions).toEqual(['flag']);
7984
});
8085
});
8186

@@ -268,4 +273,44 @@ describe('MessageListComponent', () => {
268273
);
269274
/* eslint-enable jasmine/new-line-before-expect */
270275
});
276+
277+
it('should only enable reactions if channel capabilites permit it', () => {
278+
channelServiceMock.activeChannel$.next({
279+
id: 'id',
280+
data: { own_capabilities: [] },
281+
} as any as Channel);
282+
fixture.detectChanges();
283+
284+
expect(component.canReactToMessage).toBeFalse();
285+
expect(queryMessageComponents()[0].canReactToMessage).toBeFalse();
286+
287+
channelServiceMock.activeChannel$.next({
288+
id: 'id',
289+
data: { own_capabilities: ['send-reaction'] },
290+
} as any as Channel);
291+
292+
expect(component.canReactToMessage).toBeTrue();
293+
});
294+
295+
it('should only enable flag action if channel capabilites permit it', () => {
296+
channelServiceMock.activeChannel$.next({
297+
id: 'id',
298+
data: { own_capabilities: [] },
299+
} as any as Channel);
300+
component.enabledMessageActionsInput = ['flag'];
301+
component.ngOnChanges({
302+
enabledMessageActionsInput: {} as any as SimpleChange,
303+
});
304+
fixture.detectChanges();
305+
306+
expect(queryMessageComponents()[0].enabledMessageActions).toEqual([]);
307+
308+
channelServiceMock.activeChannel$.next({
309+
id: 'id',
310+
data: { own_capabilities: ['flag-message'] },
311+
} as any as Channel);
312+
fixture.detectChanges();
313+
314+
expect(queryMessageComponents()[0].enabledMessageActions).toEqual(['flag']);
315+
});
271316
});

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import {
44
ElementRef,
55
HostBinding,
66
Input,
7+
OnChanges,
8+
SimpleChanges,
79
TemplateRef,
810
ViewChild,
911
} from '@angular/core';
@@ -14,14 +16,22 @@ import { StreamMessage } from '../types';
1416
import { ChatClientService } from '../chat-client.service';
1517
import { getGroupStyles, GroupStyle } from './group-styles';
1618
import { ImageLoadService } from './image-load.service';
19+
import { MessageActions } from '../message-actions-box/message-actions-box.component';
1720
@Component({
1821
selector: 'stream-message-list',
1922
templateUrl: './message-list.component.html',
2023
styles: [],
2124
})
22-
export class MessageListComponent implements AfterViewChecked {
25+
export class MessageListComponent implements AfterViewChecked, OnChanges {
2326
@Input() messageTemplate: TemplateRef<any> | undefined;
27+
@Input() areReactionsEnabled = true;
28+
/* eslint-disable-next-line @angular-eslint/no-input-rename */
29+
@Input('enabledMessageActions') enabledMessageActionsInput:
30+
| MessageActions[]
31+
| undefined;
2432
messages$!: Observable<StreamMessage[]>;
33+
canReactToMessage: boolean | undefined;
34+
enabledMessageActions: MessageActions[] = ['flag'];
2535
@HostBinding('class') private class =
2636
'str-chat-angular__main-panel-inner str-chat-angular__message-list-host';
2737
unreadMessageCount = 0;
@@ -36,14 +46,15 @@ export class MessageListComponent implements AfterViewChecked {
3646
private oldestMessageDate: Date | undefined;
3747
private olderMassagesLoaded: boolean | undefined;
3848
private isNewMessageSentByUser: boolean | undefined;
49+
private authorizedMessageActions: MessageActions[] = ['flag'];
3950
private readonly isUserScrolledUpThreshold = 300;
4051

4152
constructor(
4253
private channelService: ChannelService,
4354
private chatClientService: ChatClientService,
4455
private imageLoadService: ImageLoadService
4556
) {
46-
this.channelService.activeChannel$.subscribe(() => {
57+
this.channelService.activeChannel$.subscribe((channel) => {
4758
this.latestMessageDate = undefined;
4859
this.hasNewMessages = true;
4960
this.isUserScrolledUp = false;
@@ -52,6 +63,15 @@ export class MessageListComponent implements AfterViewChecked {
5263
this.oldestMessageDate = undefined;
5364
this.unreadMessageCount = 0;
5465
this.isNewMessageSentByUser = undefined;
66+
const capabilites = channel?.data?.own_capabilities as string[];
67+
if (capabilites) {
68+
this.canReactToMessage = capabilites.indexOf('send-reaction') !== -1;
69+
this.authorizedMessageActions = [];
70+
if (capabilites.indexOf('flag-message') !== -1) {
71+
this.authorizedMessageActions.push('flag');
72+
}
73+
this.setEnabledActions();
74+
}
5575
});
5676
this.messages$ = this.channelService.activeChannelMessages$.pipe(
5777
tap((messages) => {
@@ -110,6 +130,12 @@ export class MessageListComponent implements AfterViewChecked {
110130
});
111131
}
112132

133+
ngOnChanges(changes: SimpleChanges): void {
134+
if (changes.enabledMessageActionsInput) {
135+
this.setEnabledActions();
136+
}
137+
}
138+
113139
ngAfterViewChecked() {
114140
if (this.hasNewMessages) {
115141
if (!this.isUserScrolledUp || this.isNewMessageSentByUser) {
@@ -156,4 +182,17 @@ export class MessageListComponent implements AfterViewChecked {
156182
this.scrollContainer.nativeElement.scrollTop =
157183
this.scrollContainer.nativeElement.scrollHeight - this.containerHeight!;
158184
}
185+
186+
private setEnabledActions() {
187+
if (!this.enabledMessageActionsInput) {
188+
return;
189+
}
190+
this.enabledMessageActions = [];
191+
this.enabledMessageActionsInput.forEach((action) => {
192+
const isAuthorized = this.authorizedMessageActions.indexOf(action) !== -1;
193+
if (isAuthorized) {
194+
this.enabledMessageActions.push(action);
195+
}
196+
});
197+
}
159198
}

projects/stream-chat-angular/src/lib/message/message.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
></stream-icon>
6767
</div>
6868
<div
69-
*ngIf="areReactionsEnabled"
69+
*ngIf="areReactionsEnabled && canReactToMessage"
7070
class="
7171
str-chat__message-simple__actions__action
7272
str-chat__message-simple__actions__action--reactions

0 commit comments

Comments
 (0)