Skip to content

Commit

Permalink
Merge pull request novuhq#1089 from jainpawan21/feature/update-notifi…
Browse files Browse the repository at this point in the history
…cation-identifier-feature

feat: support for notification identifier update
  • Loading branch information
scopsy authored Aug 30, 2022
2 parents a50d626 + b61cf50 commit 64373b2
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export class UpdateNotificationTemplateRequestDto implements ICreateNotification
@MaxLength(100)
description: string;

@ApiPropertyOptional()
@IsString()
@IsOptional()
identifier?: string;

@ApiPropertyOptional()
@IsArray()
@IsOptional()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from 'chai';
import { UserSession, NotificationTemplateService } from '@novu/testing';
import { ChannelTypeEnum, StepTypeEnum, INotificationTemplate, IUpdateNotificationTemplate } from '@novu/shared';
import { StepTypeEnum, INotificationTemplate, IUpdateNotificationTemplateDto } from '@novu/shared';
import { ChangeRepository } from '@novu/dal';
import { CreateNotificationTemplateRequestDto } from '../dto/create-notification-template.request.dto';
import { UpdateNotificationTemplateRequestDto } from '../dto/update-notification-template-request.dto';
Expand All @@ -21,7 +21,7 @@ describe('Update notification template by id - /notification-templates/:template
session.environment._id
);
const template = await notificationTemplateService.createTemplate();
const update: IUpdateNotificationTemplate = {
const update: IUpdateNotificationTemplateDto = {
name: 'new name for notification',
steps: [
{
Expand All @@ -47,6 +47,54 @@ describe('Update notification template by id - /notification-templates/:template
expect(change._entityId).to.eq(foundTemplate._id);
});

it('should throw error if trigger identifier already exists', async function () {
const notificationTemplateService = new NotificationTemplateService(
session.user._id,
session.organization._id,
session.environment._id
);
const template1 = await notificationTemplateService.createTemplate();
const template2 = await notificationTemplateService.createTemplate();
const update: IUpdateNotificationTemplateDto = {
identifier: template1.triggers[0].identifier,
};

const { body } = await session.testAgent.put(`/v1/notification-templates/${template2._id}`).send(update);

expect(body.statusCode).to.equal(400);
expect(body.message).to.equal(
`Notification template with identifier ${template1.triggers[0].identifier} already exists`
);
expect(body.error).to.equal('Bad Request');
});

it('should update the trigger identifier', async function () {
const notificationTemplateService = new NotificationTemplateService(
session.user._id,
session.organization._id,
session.environment._id
);
const template = await notificationTemplateService.createTemplate();
const newIdentifier = `${template.triggers[0].identifier}-new`;
const update: IUpdateNotificationTemplateDto = {
identifier: newIdentifier,
};

const { body } = await session.testAgent.put(`/v1/notification-templates/${template._id}`).send(update);

const foundTemplate: INotificationTemplate = body.data;

expect(foundTemplate._id).to.equal(template._id);
expect(foundTemplate.description).to.equal(template.description);
expect(foundTemplate.name).to.equal(template.name);
expect(foundTemplate.triggers[0].identifier).to.equal(newIdentifier);

const change = await changeRepository.findOne({
_entityId: foundTemplate._id,
});
expect(change._entityId).to.eq(foundTemplate._id);
});

it('should generate new variables on update', async function () {
const notificationTemplateService = new NotificationTemplateService(
session.user._id,
Expand All @@ -63,7 +111,7 @@ describe('Update notification template by id - /notification-templates/:template
],
});

const update: IUpdateNotificationTemplate = {
const update: IUpdateNotificationTemplateDto = {
steps: [
{
template: {
Expand Down Expand Up @@ -97,7 +145,7 @@ describe('Update notification template by id - /notification-templates/:template
],
});

const update: IUpdateNotificationTemplate = {
const update: IUpdateNotificationTemplateDto = {
steps: [
{
active: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export class NotificationTemplateController {
name: body.name,
tags: body.tags,
description: body.description,
identifier: body.identifier,
critical: body.critical,
preferenceSettings: body.preferenceSettings,
steps: body.steps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export class UpdateNotificationTemplateCommand extends EnvironmentWithUserComman
@IsOptional()
description: string;

@IsString()
@IsOptional()
identifier: string;

@IsBoolean()
@IsOptional()
critical: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ export class UpdateNotificationTemplate {
updatePayload.description = command.description;
}

if (command.identifier) {
const isExistingIdentifier = await this.notificationTemplateRepository.findByTriggerIdentifier(
command.environmentId,
command.identifier
);

if (isExistingIdentifier && isExistingIdentifier._id !== command.templateId) {
throw new BadRequestException(`Notification template with identifier ${command.identifier} already exists`);
} else {
updatePayload['triggers.0.identifier'] = command.identifier;
}
}

if (command.notificationGroupId) {
updatePayload._notificationGroupId = command.notificationGroupId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export const NotificationSettingsForm = ({
mb={30}
data-test-id="title"
disabled={readonly}
required
required={!editMode}
value={field.value || ''}
error={errors.name?.message}
label="Notification Name"
Expand Down Expand Up @@ -106,21 +106,27 @@ export const NotificationSettingsForm = ({
</Grid.Col>
<Grid.Col md={6} sm={12}>
{trigger && (
<Input
mb={30}
data-test-id="trigger-id"
disabled={true}
value={trigger.identifier || ''}
error={errors.name?.message}
label="Notification Identifier"
description="This will be used to identify the notification template using the API."
rightSection={
<Tooltip data-test-id={'Tooltip'} label={idClipboard.copied ? 'Copied!' : 'Copy Key'}>
<ActionIcon variant="transparent" onClick={() => idClipboard.copy(trigger.identifier)}>
{idClipboard.copied ? <Check /> : <Copy />}
</ActionIcon>
</Tooltip>
}
<Controller
name="identifier"
control={control}
render={({ field }) => (
<Input
{...field}
mb={30}
data-test-id="trigger-id"
value={field.value || ''}
error={errors.name?.message}
label="Notification Identifier"
description="This will be used to identify the notification template using the API."
rightSection={
<Tooltip data-test-id={'Tooltip'} label={idClipboard.copied ? 'Copied!' : 'Copy Key'}>
<ActionIcon variant="transparent" onClick={() => idClipboard.copy(field.value)}>
{idClipboard.copied ? <Check /> : <Copy />}
</ActionIcon>
</Tooltip>
}
/>
)}
/>
)}
<Controller
Expand All @@ -137,7 +143,7 @@ export const NotificationSettingsForm = ({
disabled={readonly}
creatable
searchable
required
required={!editMode}
description="Categorize notifications into groups for unified settings control"
error={errors.notificationGroup?.message}
getCreateLabel={(newGroup) => (
Expand Down
22 changes: 15 additions & 7 deletions apps/web/src/components/templates/use-template-controller.hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
ICreateNotificationTemplateDto,
IMessageTemplate,
INotificationTemplate,
IUpdateNotificationTemplate,
IUpdateNotificationTemplateDto,
StepTypeEnum,
IPreferenceChannels,
} from '@novu/shared';
Expand Down Expand Up @@ -67,7 +67,7 @@ export function useTemplateController(templateId: string) {
const { isLoading: isUpdateLoading, mutateAsync: updateNotification } = useMutation<
INotificationTemplate,
{ error: string; message: string; statusCode: number },
{ id: string; data: Partial<IUpdateNotificationTemplate> }
{ id: string; data: Partial<IUpdateNotificationTemplateDto> }
>(({ id, data }) => updateTemplate(id, data));

useEffect(() => {
Expand All @@ -80,6 +80,7 @@ export function useTemplateController(templateId: string) {
name: template.name,
description: template.description as string,
tags: template.tags,
identifier: template.triggers[0].identifier,
critical: template.critical,
preferenceSettings: template.preferenceSettings,
steps: [],
Expand Down Expand Up @@ -129,7 +130,8 @@ export function useTemplateController(templateId: string) {

return step;
});
const payload: ICreateNotificationTemplateDto = {

const payloadToCreate: ICreateNotificationTemplateDto = {
notificationGroupId: data.notificationGroup,
name: data.name,
description: data.description,
Expand All @@ -139,15 +141,20 @@ export function useTemplateController(templateId: string) {
steps: stepsToSave,
};

const payloadToUpdate: IUpdateNotificationTemplateDto = {
...payloadToCreate,
identifier: data.identifier,
};

try {
if (editMode) {
await updateNotification({
id: templateId,
data: payload,
data: payloadToUpdate,
});

refetch();
reset(payload);
reset(payloadToUpdate);
setIsDirty(false);

await client.refetchQueries(QueryKeys.changesCount);
Expand All @@ -156,11 +163,11 @@ export function useTemplateController(templateId: string) {
color: 'green',
});
} else {
const response = await createNotification({ ...payload, active: true, draft: false });
const response = await createNotification({ ...payloadToCreate, active: true, draft: false });

setTrigger(response.triggers[0]);
setIsEmbedModalVisible(true);
reset(payload);
reset(payloadToCreate);
setIsDirty(false);
await client.refetchQueries(QueryKeys.changesCount);
successMessage('Template saved successfully');
Expand Down Expand Up @@ -250,6 +257,7 @@ export interface IForm {
notificationGroup: string;
name: string;
description: string;
identifier: string;
tags: string[];
critical: boolean;
steps: StepEntity[];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { NotificationStepDto } from './notification-template.dto';

export interface IUpdateNotificationTemplate {
export interface IUpdateNotificationTemplateDto {
name?: string;

tags?: string[];

description?: string;

identifier?: string;

critical?: boolean;

steps?: NotificationStepDto[];
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"start:docs": "cross-env nx run @novu/docs:start",
"start:widget": "cross-env nx run @novu/widget:start",
"start:api": "cross-env nx run @novu/api:start",
"start:api:dev": "cross-env nx run @novu/api:start:dev",
"start:dal": "cross-env nx run @novu/dal:start",
"start:node": "cross-env nx run @novu/node:start",
"start:shared": "cross-env nx run @novu/shared:start",
Expand Down

0 comments on commit 64373b2

Please sign in to comment.