Skip to content

Commit

Permalink
chore(root): Release 2024-12-10 14:49 (#7266)
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] authored Dec 10, 2024
2 parents 3d98aa1 + fea1f31 commit d34dff0
Show file tree
Hide file tree
Showing 52 changed files with 1,948 additions and 1,425 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ services:
# (Adding the "ports" property to this file will not forward from a Codespace.)

db:
image: mongo:latest
image: mongo:8.0.3
restart: unless-stopped
volumes:
- mongodb-content:/data/db
Expand Down
413 changes: 319 additions & 94 deletions apps/api/src/app/workflows-v2/generate-preview.e2e.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
PreferencesResponseDto,
RuntimeIssue,
ShortIsPrefixEnum,
StepResponseDto,
StepDataDto,
StepTypeEnum,
WorkflowCreateAndUpdateKeys,
WorkflowListResponseDto,
Expand All @@ -15,7 +15,10 @@ import { NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal';
import { WorkflowInternalResponseDto } from '@novu/application-generic';
import { buildSlug } from '../../shared/helpers/build-slug';

export function toResponseWorkflowDto(workflow: WorkflowInternalResponseDto): WorkflowResponseDto {
export function toResponseWorkflowDto(
workflow: WorkflowInternalResponseDto,
steps: StepDataDto[]
): WorkflowResponseDto {
const preferencesDto: PreferencesResponseDto = {
user: workflow.userPreferences,
default: workflow.defaultPreferences,
Expand All @@ -30,7 +33,7 @@ export function toResponseWorkflowDto(workflow: WorkflowInternalResponseDto): Wo
tags: workflow.tags,
active: workflow.active,
preferences: preferencesDto,
steps: getSteps(workflow),
steps,
description: workflow.description,
origin: computeOrigin(workflow),
updatedAt: workflow.updatedAt || 'Missing Updated At',
Expand All @@ -40,16 +43,6 @@ export function toResponseWorkflowDto(workflow: WorkflowInternalResponseDto): Wo
};
}

function getSteps(template: NotificationTemplateEntity) {
const steps: StepResponseDto[] = [];
for (const step of template.steps) {
const stepResponseDto = toStepResponseDto(step);
steps.push(stepResponseDto);
}

return steps;
}

function toMinifiedWorkflowDto(template: NotificationTemplateEntity): WorkflowListResponseDto {
const workflowName = template.name || 'Missing Name';

Expand All @@ -71,19 +64,6 @@ export function toWorkflowsMinifiedDtos(templates: NotificationTemplateEntity[])
return templates.map(toMinifiedWorkflowDto);
}

function toStepResponseDto(persistedStep: NotificationStepEntity): StepResponseDto {
const stepName = persistedStep.name || 'Missing Name';

return {
_id: persistedStep._templateId,
slug: buildSlug(stepName, ShortIsPrefixEnum.STEP, persistedStep._templateId),
name: stepName,
stepId: persistedStep.stepId || 'Missing Step Id',
type: persistedStep.template?.type || StepTypeEnum.EMAIL,
issues: persistedStep.issues,
} satisfies StepResponseDto;
}

function buildStepTypeOverview(step: NotificationStepEntity): StepTypeEnum | undefined {
return step.template?.type;
}
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/app/workflows-v2/shared/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './map-step-type-to-output.mapper';
export * from './step-type-to-control.mapper';
export * from './map-step-type-to-result.mapper';
export * from './schemas';
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';

import { JSONSchemaDto, UiComponentEnum, UiSchema, UiSchemaGroupEnum } from '@novu/shared';

export const ChatStepControlZodSchema = z
.object({
body: z.string(),
})
.strict();

export type ChatStepControlType = z.infer<typeof ChatStepControlZodSchema>;

export const chatStepControlSchema = zodToJsonSchema(ChatStepControlZodSchema) as JSONSchemaDto;
export const chatStepUiSchema: UiSchema = {
group: UiSchemaGroupEnum.CHAT,
properties: {
body: {
component: UiComponentEnum.CHAT_BODY,
},
},
};

export const chatStepControl = {
uiSchema: chatStepUiSchema,
schema: chatStepControlSchema,
};
27 changes: 27 additions & 0 deletions apps/api/src/app/workflows-v2/shared/schemas/sms-control.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { z } from 'zod';
import { zodToJsonSchema } from 'zod-to-json-schema';

import { JSONSchemaDto, UiComponentEnum, UiSchema, UiSchemaGroupEnum } from '@novu/shared';

export const SmsStepControlZodSchema = z
.object({
body: z.string(),
})
.strict();

export type SmsStepControlType = z.infer<typeof SmsStepControlZodSchema>;

export const smsStepControlSchema = zodToJsonSchema(SmsStepControlZodSchema) as JSONSchemaDto;
export const smsStepUiSchema: UiSchema = {
group: UiSchemaGroupEnum.SMS,
properties: {
body: {
component: UiComponentEnum.SMS_BODY,
},
},
};

export const smsStepControl = {
uiSchema: smsStepUiSchema,
schema: smsStepControlSchema,
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { ControlSchemas, JSONSchemaDto } from '@novu/shared';
import { emailStepControlSchema, emailStepUiSchema, inAppControlSchema, inAppUiSchema } from './schemas';
import { DelayTimeControlSchema, delayUiSchema } from './schemas/delay-control.schema';
import { DigestOutputJsonSchema, digestUiSchema } from './schemas/digest-control.schema';
import { smsStepControl } from './schemas/sms-control.schema';
import { chatStepControl } from './schemas/chat-control.schema';

export const PERMISSIVE_EMPTY_SCHEMA = {
type: 'object',
Expand All @@ -11,7 +13,7 @@ export const PERMISSIVE_EMPTY_SCHEMA = {
additionalProperties: true,
} as JSONSchemaDto;

export const stepTypeToDefaultDashboardControlSchema: Record<ChannelStepEnum | ActionStepEnum, ControlSchemas> = {
export const stepTypeToControlSchema: Record<ChannelStepEnum | ActionStepEnum, ControlSchemas> = {
[ChannelStepEnum.IN_APP]: {
schema: inAppControlSchema,
uiSchema: inAppUiSchema,
Expand All @@ -21,13 +23,15 @@ export const stepTypeToDefaultDashboardControlSchema: Record<ChannelStepEnum | A
uiSchema: emailStepUiSchema,
},
[ChannelStepEnum.SMS]: {
schema: channelStepSchemas[ChannelStepEnum.SMS].output as unknown as JSONSchemaDto,
schema: smsStepControl.schema,
uiSchema: smsStepControl.uiSchema,
},
[ChannelStepEnum.PUSH]: {
schema: channelStepSchemas[ChannelStepEnum.PUSH].output as unknown as JSONSchemaDto,
},
[ChannelStepEnum.CHAT]: {
schema: channelStepSchemas[ChannelStepEnum.CHAT].output as unknown as JSONSchemaDto,
schema: chatStepControl.schema,
uiSchema: chatStepControl.uiSchema,
},
[ActionStepEnum.DELAY]: {
schema: DelayTimeControlSchema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export class BuildPayloadSchema {
private extractTemplateVariables(controlValues: Record<string, unknown>[]): string[] {
const controlValuesString = controlValues.map(flattenObjectValues).flat().join(' ');

return extractLiquidTemplateVariables(controlValuesString).validVariables.map((variable) => variable.name);
const test = extractLiquidTemplateVariables(controlValuesString);
const test2 = test.validVariables.map((variable) => variable.name);

return test2;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { ControlValuesLevelEnum, StepDataDto, WorkflowOriginEnum } from '@novu/shared';
import { ControlValuesLevelEnum, ShortIsPrefixEnum, StepDataDto, WorkflowOriginEnum } from '@novu/shared';
import { ControlValuesRepository, NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal';
import { GetWorkflowByIdsUseCase, Instrument, InstrumentUsecase } from '@novu/application-generic';
import { BuildStepDataCommand } from './build-step-data.command';
import { InvalidStepException } from '../../exceptions/invalid-step.exception';
import { BuildAvailableVariableSchemaUsecase } from '../build-variable-schema';
import { buildSlug } from '../../../shared/helpers/build-slug';

@Injectable()
export class BuildStepDataUsecase {
Expand All @@ -19,15 +20,12 @@ export class BuildStepDataUsecase {
const workflow = await this.fetchWorkflow(command);

const { currentStep } = await this.loadStepsFromDb(command, workflow);
if (
currentStep.name === undefined ||
!currentStep._templateId ||
currentStep.stepId === undefined ||
!currentStep.template?.type
) {

if (!currentStep._templateId || !currentStep.template?.type) {
throw new InvalidStepException(currentStep);
}
const controlValues = await this.getValues(command, currentStep, workflow._id);
const stepName = currentStep.name || 'Missing Step Name';

return {
controls: {
Expand All @@ -42,9 +40,10 @@ export class BuildStepDataUsecase {
stepInternalId: currentStep._templateId,
workflow,
}),
name: currentStep.name,
name: stepName,
slug: buildSlug(stepName, ShortIsPrefixEnum.STEP, currentStep._templateId),
_id: currentStep._templateId,
stepId: currentStep.stepId,
stepId: currentStep.stepId || 'Missing Step Id',
type: currentStep.template?.type,
origin: workflow.origin || WorkflowOriginEnum.EXTERNAL,
workflowId: workflow.triggers[0].identifier,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common
import _ from 'lodash';
import {
ChannelTypeEnum,
createMockObjectFromSchema,
GeneratePreviewResponseDto,
JobStatusEnum,
JSONSchemaDto,
Expand All @@ -22,7 +23,6 @@ import { PreviewStep, PreviewStepCommand } from '../../../bridge/usecases/previe
import { FrameworkPreviousStepsOutputState } from '../../../bridge/usecases/preview-step/preview-step.command';
import { BuildStepDataUsecase } from '../build-step-data';
import { GeneratePreviewCommand } from './generate-preview.command';
import { createMockPayloadFromSchema } from '../../util/utils';
import { PrepareAndValidateContentUsecase } from '../validate-content/prepare-and-validate-content/prepare-and-validate-content.usecase';
import { BuildPayloadSchemaCommand } from '../build-payload-schema/build-payload-schema.command';
import { BuildPayloadSchema } from '../build-payload-schema/build-payload-schema.usecase';
Expand Down Expand Up @@ -58,13 +58,13 @@ export class GeneratePreviewUsecase {
})
);

const res = this.buildVariablesSchema(stepData.variables, payloadSchema);
const variableSchema = this.buildVariablesSchema(stepData.variables, payloadSchema);
const preparedAndValidatedContent = await this.prepareAndValidateContentUsecase.execute({
user: command.user,
previewPayloadFromDto: commandVariablesExample,
controlValues,
controlDataSchema: stepData.controls.dataSchema || {},
variableSchema: res,
variableSchema,
});
const variablesExample = this.buildVariablesExample(
workflow,
Expand Down Expand Up @@ -134,17 +134,16 @@ export class GeneratePreviewUsecase {
return finalPayload;
}

const examplePayloadSchema = createMockPayloadFromSchema(workflow.payloadSchema);
const examplePayloadSchema = createMockObjectFromSchema({
type: 'object',
properties: { payload: workflow.payloadSchema },
});

if (!examplePayloadSchema || Object.keys(examplePayloadSchema).length === 0) {
return finalPayload;
}

return _.merge(
finalPayload as Record<string, unknown>,
{ payload: examplePayloadSchema },
commandVariablesExample || {}
);
return _.merge(finalPayload as Record<string, unknown>, examplePayloadSchema, commandVariablesExample || {});
}

@Instrument()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import { Injectable } from '@nestjs/common';
import { Injectable, InternalServerErrorException } from '@nestjs/common';

import { WorkflowResponseDto } from '@novu/shared';
import { GetWorkflowByIdsCommand, GetWorkflowByIdsUseCase, InstrumentUsecase } from '@novu/application-generic';
import { StepDataDto, UserSessionData, WorkflowResponseDto } from '@novu/shared';
import {
GetWorkflowByIdsCommand,
GetWorkflowByIdsUseCase,
InstrumentUsecase,
WorkflowInternalResponseDto,
} from '@novu/application-generic';

import { NotificationStepEntity } from '@novu/dal';
import { GetWorkflowCommand } from './get-workflow.command';
import { toResponseWorkflowDto } from '../../mappers/notification-template-mapper';
import { BuildStepDataUsecase } from '../build-step-data/build-step-data.usecase';
import { BuildStepDataCommand } from '../build-step-data/build-step-data.command';

@Injectable()
export class GetWorkflowUseCase {
constructor(private getWorkflowByIdsUseCase: GetWorkflowByIdsUseCase) {}
constructor(
private getWorkflowByIdsUseCase: GetWorkflowByIdsUseCase,
private buildStepDataUsecase: BuildStepDataUsecase
) {}

@InstrumentUsecase()
async execute(command: GetWorkflowCommand): Promise<WorkflowResponseDto> {
Expand All @@ -21,6 +32,42 @@ export class GetWorkflowUseCase {
})
);

return toResponseWorkflowDto(workflowEntity);
const fullSteps = await this.getFullWorkflowSteps(workflowEntity, command.user);

return toResponseWorkflowDto(workflowEntity, fullSteps);
}

private async getFullWorkflowSteps(
workflow: WorkflowInternalResponseDto,
user: UserSessionData
): Promise<StepDataDto[]> {
const stepPromises = workflow.steps.map((step: NotificationStepEntity & { _id: string }) =>
this.buildStepForWorkflow(workflow, step, user)
);

return Promise.all(stepPromises);
}

private async buildStepForWorkflow(
workflow: WorkflowInternalResponseDto,
step: NotificationStepEntity & { _id: string },
user: UserSessionData
): Promise<StepDataDto> {
try {
return await this.buildStepDataUsecase.execute(
BuildStepDataCommand.create({
workflowIdOrInternalId: workflow._id,
stepIdOrInternalId: step._id,
user,
})
);
} catch (error) {
throw new InternalServerErrorException({
message: 'Failed to build workflow step',
workflowId: workflow._id,
stepId: step._id,
error: error.message,
});
}
}
}
Loading

0 comments on commit d34dff0

Please sign in to comment.