Skip to content

Commit

Permalink
Merge branch 'next' into feat-package-class-validator-support
Browse files Browse the repository at this point in the history
  • Loading branch information
paulwer authored Nov 8, 2024
2 parents 5d2b8e9 + b494633 commit 2b8f000
Show file tree
Hide file tree
Showing 39 changed files with 1,904 additions and 1,188 deletions.
25 changes: 16 additions & 9 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"adresses",
"africas",
"africastalking",
"Aland",
"alanturing",
"alexjoverm",
"alist",
Expand Down Expand Up @@ -68,6 +69,7 @@
"buildscript",
"buildx",
"bullmq",
"Burkina",
"bzrignore",
"cacheable",
"cafebabe",
Expand All @@ -92,6 +94,7 @@
"Clicksend",
"clonedeep",
"clsx",
"cmdk",
"cnamek",
"cnames",
"codecov",
Expand Down Expand Up @@ -188,6 +191,7 @@
"exponentiate",
"externaldb",
"externalredis",
"Faso",
"Fdfdf",
"fieldname",
"fieldtype",
Expand Down Expand Up @@ -274,6 +278,7 @@
"kannel",
"kebabcase",
"keybase",
"Keymap",
"keyrings",
"keysize",
"kitterma",
Expand All @@ -287,6 +292,7 @@
"lastindex",
"Lato",
"Lentczner",
"lezer"
"libarary",
"libauth",
"libspf",
Expand Down Expand Up @@ -342,14 +348,15 @@
"mlen",
"mobishastra",
"Mobishastra",
"Mobishatra",
"moby",
"Modiin",
"modlen",
"Mobishatra",
"mongod",
"mongosh",
"monokai",
"monorepository",
"motionone",
"mpeltonen",
"mpim",
"MPIMs",
Expand Down Expand Up @@ -399,6 +406,8 @@
"NOTZONE",
"Novu's",
"novu",
"Novu",
"NOVU",
"novuapp",
"novuhq",
"novui",
Expand Down Expand Up @@ -521,6 +530,7 @@
"RETRYABLE",
"revlookup",
"revlookupall",
"Rica",
"righthand",
"rimraf",
"ringcentral",
Expand Down Expand Up @@ -567,6 +577,8 @@
"softfail",
"softwareupdate",
"sonarjs",
"sonner",
"Sonner",
"sortlist",
"sourcemaps",
"spamassassin",
Expand Down Expand Up @@ -603,6 +615,7 @@
"supernet",
"supertest",
"suported",
"Syncable",
"tabnannied",
"tailwindcss",
"tanstack",
Expand Down Expand Up @@ -652,6 +665,7 @@
"Udnw",
"unarchived",
"Unarchived",
"Unavalidated",
"Unfetch",
"unplugin",
"Unpromoted",
Expand Down Expand Up @@ -685,16 +699,9 @@
"whatsappbusiness",
"xcodebuild",
"xkeysib",
"xyflow",
"zulip",
"zwnj",
"motionone",
"xyflow",
"Sonner",
"sonner",
"cmdk",
"Keymap",
"Syncable",
"lezer"
],
"flagWords": [],
"patterns": [
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/dev-deploy-webhook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ env:
jobs:
test_webhook:
uses: ./.github/workflows/reusable-webhook-e2e.yml
secrets: inherit

publish_docker_image_webhook:
if: "!contains(github.event.head_commit.message, 'ci skip')"
Expand Down
2 changes: 2 additions & 0 deletions apps/api/src/app/events/e2e/bridge-trigger.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,8 @@ describe('Novu-Hosted Bridge Trigger', () => {

it('should execute a Novu-managed workflow', async () => {
const createWorkflowDto: CreateWorkflowDto = {
tags: [],
active: true,
name: 'Test Workflow',
description: 'Test Workflow',
__source: WorkflowCreationSourceEnum.DASHBOARD,
Expand Down
49 changes: 13 additions & 36 deletions apps/api/src/app/subscribers/e2e/bulk-create-subscribers.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ describe('Bulk create subscribers - /v1/subscribers/bulk (POST)', function () {
}
});

it('should allow recreate deleted subscribers', async function () {
it('should recreate deleted subscribers', async function () {
const existingSubscriber = { subscriberId: subscriber.subscriberId, firstName: 'existingSubscriber' };
const newSubscriber1 = {
subscriberId: 'test1',
Expand All @@ -153,7 +153,7 @@ describe('Bulk create subscribers - /v1/subscribers/bulk (POST)', function () {
firstName: 'sub2',
email: '[email protected]',
};
const { data: body } = await axiosInstance.post(
const { data: firstResponseData } = await axiosInstance.post(
`${session.serverUrl}${BULK_API_ENDPOINT}`,
{
subscribers: [existingSubscriber, newSubscriber1, newSubscriber2],
Expand All @@ -164,19 +164,13 @@ describe('Bulk create subscribers - /v1/subscribers/bulk (POST)', function () {
},
}
);
expect(body.data).to.be.ok;

const {
data: { updated, created },
} = body;
expect(firstResponseData.data.created?.length).to.equal(2);
expect(firstResponseData.data.updated?.length).to.equal(1);
expect(firstResponseData.data.created[0].subscriberId).to.equal(newSubscriber1.subscriberId);
expect(firstResponseData.data.created[1].subscriberId).to.equal(newSubscriber2.subscriberId);
expect(firstResponseData.data.updated[0].subscriberId).to.equal(existingSubscriber.subscriberId);

expect(updated?.length).to.equal(1);
expect(created?.length).to.equal(2);
expect(updated[0].subscriberId).to.equal(existingSubscriber.subscriberId);
expect(created[0].subscriberId).to.equal(newSubscriber1.subscriberId);
expect(created[1].subscriberId).to.equal(newSubscriber2.subscriberId);

// delete the two created subscribers
await axiosInstance.delete(`${session.serverUrl}/v1/subscribers/${newSubscriber1.subscriberId}`, {
headers: {
authorization: `ApiKey ${session.apiKey}`,
Expand All @@ -188,8 +182,7 @@ describe('Bulk create subscribers - /v1/subscribers/bulk (POST)', function () {
},
});

// recreate the deleted subscribers
const { data: recreateBody } = await axiosInstance.post(
const { data: secondResponseData } = await axiosInstance.post(
`${session.serverUrl}${BULK_API_ENDPOINT}`,
{
subscribers: [existingSubscriber, newSubscriber1, newSubscriber2],
Expand All @@ -201,26 +194,10 @@ describe('Bulk create subscribers - /v1/subscribers/bulk (POST)', function () {
}
);

expect(recreateBody.data).to.be.ok;
const {
data: { updated: updatedAgain },
} = recreateBody;

expect(updatedAgain?.length).to.equal(3);
expect(updatedAgain[0].subscriberId).to.equal(existingSubscriber.subscriberId);
expect(updatedAgain[1].subscriberId).to.equal(newSubscriber1.subscriberId);
expect(updatedAgain[2].subscriberId).to.equal(newSubscriber2.subscriberId);

// check that they are not marked as deleted
const recreatedSubscriber1 = await subscriberRepository.findBySubscriberId(
session.environment._id,
newSubscriber1.subscriberId
);
const recreatedSubscriber2 = await subscriberRepository.findBySubscriberId(
session.environment._id,
newSubscriber2.subscriberId
);
expect(recreatedSubscriber1.deleted).to.be.false;
expect(recreatedSubscriber2.deleted).to.be.false;
expect(secondResponseData.data.created?.length).to.equal(2);
expect(secondResponseData.data.updated?.length).to.equal(1);
expect(secondResponseData.data.created[0].subscriberId).to.equal(newSubscriber1.subscriberId);
expect(secondResponseData.data.created[1].subscriberId).to.equal(newSubscriber2.subscriberId);
expect(secondResponseData.data.updated[0].subscriberId).to.equal(existingSubscriber.subscriberId);
});
});
1 change: 1 addition & 0 deletions apps/api/src/app/workflows-v2/generate-preview.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ describe('Generate Preview', () => {
}
async function createWorkflowWithDigest() {
const createWorkflowDto: CreateWorkflowDto = {
tags: [],
__source: WorkflowCreationSourceEnum.EDITOR,
name: 'John',
workflowId: `john:${randomUUID()}`,
Expand Down
3 changes: 3 additions & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
"@radix-ui/react-switch": "^1.1.1",
"@radix-ui/react-tabs": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.3",
"@rjsf/core": "^5.22.3",
"@rjsf/utils": "^5.20.0",
"@rjsf/validator-ajv8": "^5.17.1",
"@segment/analytics-next": "^1.73.0",
"@sentry/react": "^8.35.0",
"@tanstack/react-query": "^5.59.6",
Expand Down
10 changes: 5 additions & 5 deletions apps/dashboard/src/api/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,17 @@ export const updateWorkflow = async ({

export const previewStep = async ({
workflowSlug,
payload,
data,
stepSlug,
}: {
workflowSlug: string;
stepSlug: string;
payload?: GeneratePreviewRequestDto;
data?: GeneratePreviewRequestDto;
}): Promise<GeneratePreviewResponseDto> => {
const { data } = await postV2<{ data: GeneratePreviewResponseDto }>(
const res = await postV2<{ data: GeneratePreviewResponseDto }>(
`/workflows/${workflowSlug}/step/${stepSlug}/preview`,
payload
data
);

return data;
return res.data;
};
8 changes: 4 additions & 4 deletions apps/dashboard/src/components/workflow-editor/nodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const EmailNode = ({ data }: NodeProps<NodeType>) => {
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.EMAIL];

return (
<Link to={`step/${data.stepSlug}`}>
<Link to={buildRoute(ROUTES.CONFIGURE_STEP, { stepSlug: data.stepSlug ?? '' })}>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.EMAIL}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.EMAIL]}>
Expand All @@ -79,7 +79,7 @@ export const SmsNode = (props: NodeProps<NodeType>) => {
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.SMS];

return (
<Link to={`step/${data.stepSlug}`}>
<Link to={buildRoute(ROUTES.CONFIGURE_STEP, { stepSlug: data.stepSlug ?? '' })}>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.SMS}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.SMS]}>
Expand Down Expand Up @@ -123,7 +123,7 @@ export const PushNode = (props: NodeProps<NodeType>) => {
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.PUSH];

return (
<Link to={`step/${data.stepSlug}`}>
<Link to={buildRoute(ROUTES.CONFIGURE_STEP, { stepSlug: data.stepSlug ?? '' })}>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.PUSH}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.PUSH]}>
Expand All @@ -145,7 +145,7 @@ export const ChatNode = (props: NodeProps<NodeType>) => {
const Icon = STEP_TYPE_TO_ICON[StepTypeEnum.CHAT];

return (
<Link to={`step/${data.stepSlug}`}>
<Link to={buildRoute(ROUTES.CONFIGURE_STEP, { stepSlug: data.stepSlug ?? '' })}>
<StepNode data={data}>
<NodeHeader type={StepTypeEnum.CHAT}>
<NodeIcon variant={STEP_TYPE_TO_COLOR[StepTypeEnum.CHAT]}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useState } from 'react';
import { RJSFSchema } from '@rjsf/utils';
import { RiArrowDownSLine, RiArrowUpSLine, RiInputField } from 'react-icons/ri';
import { type ControlsMetadata } from '@novu/shared';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/primitives/collapsible';
import { JsonForm } from './json-form';

export function CustomStepControls({ dataSchema }: { dataSchema: ControlsMetadata['dataSchema'] }) {
const [isEditorOpen, setIsEditorOpen] = useState(true);

if (!dataSchema) {
return null;
}

return (
<Collapsible
open={isEditorOpen}
onOpenChange={setIsEditorOpen}
className="bg-neutral-alpha-50 border-neutral-alpha-200 flex w-full flex-col gap-2 rounded-lg border p-2"
>
<CollapsibleTrigger className="flex w-full items-center justify-between text-sm">
<div className="flex items-center gap-1">
<RiInputField className="text-feature size-5" />
<span className="text-sm font-medium">Custom steps controls</span>
</div>

{isEditorOpen ? (
<RiArrowUpSLine className="text-neutral-alpha-400 size-5" />
) : (
<RiArrowDownSLine className="text-neutral-alpha-400 size-5" />
)}
</CollapsibleTrigger>

<CollapsibleContent>
<div className="bg-background rounded-md border border-dashed px-3 py-0">
<JsonForm schema={(dataSchema as RJSFSchema) || {}} variables={[]} />
</div>
</CollapsibleContent>
</Collapsible>
);
}
Loading

0 comments on commit 2b8f000

Please sign in to comment.