Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docusaurus/docs/Angular/basics/upgrade-v2.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,17 @@ The `notification$` stream on the [`ChatClientService`](../services/ChatClientSe
The `events$` stream emits the received [client, notification and user presence events](https://getstream.io/chat/docs/javascript/event_object/?language=javascript).

The payload of this Observable was renamed from `Notification` to `ClientEvent`.

## Custom action names removed

Use our [permission framework](https://getstream.io/chat/docs/javascript/chat_permission_policies/?language=javascript&q=slow%20mode) to control the authorization of the following message actions:

| Custom action name | Channel capability | Comment |
| ------------------ | -------------------- | -------------------------------------------- |
| `quote` | `quote-message` | |
| `pin` | `pin-message` | Currently turned off because not implemented |
| `flag` | `flag-message` | |
| `edit` | `update-own-message` | |
| `edit-any` | `update-any-message` | |

The `mute` action is removed.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Component, Input } from '@angular/core';
styleUrls: ['./message-action.component.scss'],
})
export class MessageActionComponent {
@Input() actionName!: 'quote' | 'pin' | 'flag' | 'mute' | 'edit' | 'delete';
@Input() actionName!: 'quote' | 'pin' | 'flag' | 'edit' | 'delete';
@Input() actionLabelOrTranslationKey!: (() => string) | string;
@Input() actionHandler!: () => any;

Expand All @@ -19,7 +19,6 @@ export class MessageActionComponent {
delete: 'delete',
flag: 'flag',
pin: 'push_pin',
mute: 'volume_mute',
};
return iconMapping[this.actionName];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,19 +154,23 @@ describe('MessageActionsBoxComponent', () => {
expect(queryFlagAction()).toBeNull();
expect(queryQuoteAction()).toBeNull();

component.enabledActions = ['pin', 'edit-any', 'delete-any'];
component.enabledActions = [
'pin-message',
'update-any-message',
'delete-any',
];
component.ngOnChanges({ enabledActions: {} as SimpleChange });
fixture.detectChanges();

expect(queryDeleteAction()).not.toBeNull();
expect(queryEditAction()).not.toBeNull();
expect(queryPinAction()).not.toBeNull();
expect(queryPinAction()).toBeNull();
expect(queryMuteAction()).toBeNull();
expect(queryFlagAction()).toBeNull();
expect(queryQuoteAction()).toBeNull();
});

it(`should only display 'flag' action for other user's messages`, () => {
it(`should only display 'flag-message' action for other user's messages`, () => {
component.enabledActions = ['flag-message'];
component.isMine = false;
component.ngOnChanges({
Expand All @@ -187,7 +191,7 @@ describe('MessageActionsBoxComponent', () => {
});

it('should handle quote action', () => {
component.enabledActions = ['quote'];
component.enabledActions = ['quote-message'];
component.ngOnChanges({ enabledActions: {} as SimpleChange });
fixture.detectChanges();
const spy = TestBed.inject(ChannelService).selectMessageToQuote;
Expand All @@ -211,7 +215,7 @@ describe('MessageActionsBoxComponent', () => {
...component.message!,
quoted_message: mockMessage() as any as MessageResponseBase,
};
component.enabledActions = ['quote'];
component.enabledActions = ['quote-message'];
component.ngOnChanges({
message: {} as SimpleChange,
enabledActions: {} as SimpleChange,
Expand All @@ -221,9 +225,10 @@ describe('MessageActionsBoxComponent', () => {
expect(queryQuoteAction()).toBeNull();
});

it('should display the pin action label correctly', () => {
// eslint-disable-next-line jasmine/no-disabled-tests
xit('should display the pin action label correctly', () => {
component.message = { ...message, ...{ pinned: false } };
component.enabledActions = ['pin'];
component.enabledActions = ['pin-message'];
component.ngOnChanges({
message: {} as SimpleChange,
enabledActions: {} as SimpleChange,
Expand All @@ -240,8 +245,9 @@ describe('MessageActionsBoxComponent', () => {
expect(pinAction?.textContent).toContain('Unpin');
});

it('should handle pin action', () => {
component.enabledActions = ['pin'];
// eslint-disable-next-line jasmine/no-disabled-tests
xit('should handle pin action', () => {
component.enabledActions = ['pin-message'];
component.ngOnChanges({ enabledActions: {} as SimpleChange });
fixture.detectChanges();
spyOn(window, 'alert').and.callThrough();
Expand All @@ -252,24 +258,10 @@ describe('MessageActionsBoxComponent', () => {
expect(window.alert).toHaveBeenCalledWith(jasmine.anything());
});

it('should handle mute action', () => {
component.enabledActions = ['mute'];
component.ngOnChanges({
enabledActions: {} as SimpleChange,
});
fixture.detectChanges();
spyOn(window, 'alert').and.callThrough();
const action = queryMuteAction();
action?.click();
fixture.detectChanges();

expect(window.alert).toHaveBeenCalledWith(jasmine.anything());
});

it('should handle flag action', async () => {
const notificationService = TestBed.inject(NotificationService);
spyOn(notificationService, 'addTemporaryNotification');
component.enabledActions = ['flag'];
component.enabledActions = ['flag-message'];
component.ngOnChanges({ enabledActions: {} as SimpleChange });
fixture.detectChanges();
const action = queryFlagAction();
Expand All @@ -288,7 +280,7 @@ describe('MessageActionsBoxComponent', () => {
const notificationService = TestBed.inject(NotificationService);
spyOn(notificationService, 'addTemporaryNotification');
mockChatClient.flagMessage.and.rejectWith();
component.enabledActions = ['flag'];
component.enabledActions = ['flag-message'];
component.ngOnChanges({ enabledActions: {} as SimpleChange });
fixture.detectChanges();
const action = queryFlagAction();
Expand All @@ -304,10 +296,10 @@ describe('MessageActionsBoxComponent', () => {

it('should emit the number of displayed actions', () => {
component.enabledActions = [
'pin',
'pin-message',
'update-own-message',
'delete-own-message',
'flag',
'flag-message',
];
component.isMine = true;
const spy = jasmine.createSpy();
Expand All @@ -318,16 +310,15 @@ describe('MessageActionsBoxComponent', () => {
});
fixture.detectChanges();

expect(spy).toHaveBeenCalledWith(3);
expect(spy).toHaveBeenCalledWith(2);

spy.calls.reset();
component.enabledActions = [
'pin',
'pin-message',
'update-any-message',
'delete',
'flag',
'quote',
'mute',
'flag-message',
'quote-message',
];
component.isMine = false;
component.ngOnChanges({
Expand All @@ -336,12 +327,12 @@ describe('MessageActionsBoxComponent', () => {
});
fixture.detectChanges();

expect(spy).toHaveBeenCalledWith(5);
expect(spy).toHaveBeenCalledWith(3);
});

describe('should display edit action', () => {
it('if #enabledActions contains "edit" and #isMine', () => {
component.enabledActions = ['edit'];
component.enabledActions = ['update-own-message'];
component.isMine = false;
component.ngOnChanges({
enabledActions: {} as SimpleChange,
Expand All @@ -359,7 +350,7 @@ describe('MessageActionsBoxComponent', () => {
});

it('if #enabledActions contains "edit-any"', () => {
component.enabledActions = ['edit-any'];
component.enabledActions = ['update-any-message'];
component.isMine = false;
component.ngOnChanges({
enabledActions: {} as SimpleChange,
Expand Down Expand Up @@ -408,7 +399,12 @@ describe('MessageActionsBoxComponent', () => {
it('should emit #isEditing if user starts to edit', () => {
const spy = jasmine.createSpy();
component.isEditing.subscribe(spy);
component.enabledActions = ['pin', 'edit-any', 'delete', 'flag'];
component.enabledActions = [
'pin-message',
'update-any-message',
'delete',
'flag-message',
];
component.ngOnChanges({
enabledActions: {} as SimpleChange,
});
Expand All @@ -420,7 +416,7 @@ describe('MessageActionsBoxComponent', () => {
});

it('should open modal if user starts to edit', () => {
component.enabledActions = ['edit'];
component.enabledActions = ['update-own-message'];
component.isMine = true;
component.ngOnChanges({
enabledActions: {} as SimpleChange,
Expand All @@ -434,7 +430,7 @@ describe('MessageActionsBoxComponent', () => {
});

it('should display message input if user starts to edit', () => {
component.enabledActions = ['edit-any'];
component.enabledActions = ['update-any-message'];
component.ngOnChanges({
enabledActions: {} as SimpleChange,
});
Expand All @@ -446,7 +442,7 @@ describe('MessageActionsBoxComponent', () => {
});

it('should call update message if "Send" button is clicked', () => {
component.enabledActions = ['edit-any'];
component.enabledActions = ['update-any-message'];
component.isEditModalOpen = true;
component.ngOnChanges({
enabledActions: {} as SimpleChange,
Expand All @@ -463,7 +459,7 @@ describe('MessageActionsBoxComponent', () => {
});

it('should close modal with "Cancel" button', () => {
component.enabledActions = ['edit'];
component.enabledActions = ['update-own-message'];
component.isMine = true;
component.ngOnChanges({
enabledActions: {} as SimpleChange,
Expand All @@ -482,7 +478,7 @@ describe('MessageActionsBoxComponent', () => {
});

it('should update #isEditModalOpen if modal is closed', () => {
component.enabledActions = ['edit'];
component.enabledActions = ['update-own-message'];
component.isMine = true;
component.isEditModalOpen = true;
component.ngOnChanges({
Expand All @@ -502,7 +498,7 @@ describe('MessageActionsBoxComponent', () => {
});

it('should close modal if message was updated successfully', () => {
component.enabledActions = ['edit'];
component.enabledActions = ['update-own-message'];
component.isMine = true;
component.ngOnChanges({
enabledActions: {} as SimpleChange,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,15 @@ export class MessageActionsBoxComponent implements OnChanges, OnDestroy {
isMine: boolean,
message: StreamMessage
) =>
(enabledActions.indexOf('quote') !== -1 ||
enabledActions.indexOf('quote-message') !== -1) &&
enabledActions.indexOf('quote-message') !== -1 &&
!message?.quoted_message,
},
{
actionName: 'pin',
actionLabelOrTranslationKey: () =>
this.message?.pinned ? 'streamChat.Unpin' : 'streamChat.Pin',
actionHandler: () => alert('Feature not yet implemented'),
isVisible: (enabledActions: string[]) =>
enabledActions.indexOf('pin') !== -1,
isVisible: () => false,
},
{
actionName: 'flag',
Expand All @@ -130,16 +128,7 @@ export class MessageActionsBoxComponent implements OnChanges, OnDestroy {
}
},
isVisible: (enabledActions: string[], isMine: boolean) =>
(enabledActions.indexOf('flag') !== -1 ||
enabledActions.indexOf('flag-message') !== -1) &&
!isMine,
},
{
actionName: 'mute',
actionLabelOrTranslationKey: 'streamChat.Mute',
actionHandler: () => alert('Feature not yet implemented'),
isVisible: (enabledActions: string[]) =>
enabledActions.indexOf('mute') !== -1,
enabledActions.indexOf('flag-message') !== -1 && !isMine,
},
{
actionName: 'edit',
Expand All @@ -149,10 +138,7 @@ export class MessageActionsBoxComponent implements OnChanges, OnDestroy {
this.isEditModalOpen = true;
},
isVisible: (enabledActions: string[], isMine: boolean) =>
((enabledActions.indexOf('edit') !== -1 ||
enabledActions.indexOf('update-own-message') !== -1) &&
isMine) ||
enabledActions.indexOf('edit-any') !== -1 ||
(enabledActions.indexOf('update-own-message') !== -1 && isMine) ||
enabledActions.indexOf('update-any-message') !== -1,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,14 +456,14 @@ describe('MessageComponent', () => {
});

it(`shouldn't display message actions if there is no visible message action`, () => {
component.enabledMessageActions = ['flag'];
component.enabledMessageActions = ['flag-message'];
fixture.detectChanges();

expect(queryActionIcon()).toBeNull();
});

it('should open and close message actions box', () => {
component.enabledMessageActions = ['edit', 'flag'];
component.enabledMessageActions = ['update-own-message', 'flag-message'];
fixture.detectChanges();

expect(messageActionsBoxComponent.isOpen).toBeFalse();
Expand All @@ -475,7 +475,7 @@ describe('MessageComponent', () => {
});

it('should close message actions box on mouseleave event', () => {
component.enabledMessageActions = ['edit', 'flag'];
component.enabledMessageActions = ['update-own-message', 'flag-message'];
component.isActionBoxOpen = true;
fixture.detectChanges();

Expand Down Expand Up @@ -906,7 +906,7 @@ describe('MessageComponent', () => {
describe('in thread mode', () => {
beforeEach(() => {
component.mode = 'thread';
component.enabledMessageActions = ['edit', 'delete'];
component.enabledMessageActions = ['update-own-message', 'delete'];
component.ngOnChanges({
enabledMessageActions: {} as SimpleChange,
});
Expand Down
4 changes: 2 additions & 2 deletions projects/stream-chat-angular/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,13 @@ export type MessageActionsBoxContext = {
};

export type MessageActionBoxItemContext = {
actionName: 'quote' | 'pin' | 'flag' | 'mute' | 'edit' | 'delete';
actionName: 'quote' | 'pin' | 'flag' | 'edit' | 'delete';
actionLabelOrTranslationKey: (() => string) | string;
actionHandler: () => any;
};

export type MessageActionItem = {
actionName: 'quote' | 'pin' | 'flag' | 'mute' | 'edit' | 'delete';
actionName: 'quote' | 'pin' | 'flag' | 'edit' | 'delete';
actionLabelOrTranslationKey: (() => string) | string;
isVisible: (
enabledActions: string[],
Expand Down