Skip to content

Commit

Permalink
feat: add workflow creation from blueprint
Browse files Browse the repository at this point in the history
  • Loading branch information
djabarovgeorge authored and antonjoel82 committed Feb 14, 2024
1 parent d07447e commit 6ccea0b
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import { IconName } from '@fortawesome/fontawesome-svg-core';
import localforage from 'localforage';
import { addWeeks } from 'date-fns';
import { IGroupedBlueprint } from '@novu/shared';

import { getBlueprintsGroupedByCategory } from '../../notification-templates';
import { QueryKeys } from '../../query.keys';
import { IBlueprintTemplate } from '../../types';
import { getWorkflowBlueprintDetails } from '../../../utils';

export interface IBlueprintsGrouped {
name: string;
Expand All @@ -18,22 +18,10 @@ interface IBlueprintsGroupedAndPopular {
popular: IBlueprintsGrouped;
}

const getTemplateDetails = (templateName: string): { name: string; iconName: IconName } => {
const regexResult = /^:.{1,}:/.exec(templateName);
let name = '';
let iconName = 'fa-solid fa-question';
if (regexResult !== null) {
name = templateName.replace(regexResult[0], '').trim();
iconName = regexResult[0].replace(/:/g, '').trim();
}

return { name, iconName: iconName as IconName };
};

const mapGroup = (group: IGroupedBlueprint): IBlueprintsGrouped => ({
name: group.name,
blueprints: group.blueprints.map((template) => {
const { name, iconName } = getTemplateDetails(template.name);
const { name, iconName } = getWorkflowBlueprintDetails(template.name);

return {
...template,
Expand Down
73 changes: 73 additions & 0 deletions apps/web/src/pages/get-started/components/CreateWorkflowButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useQuery } from '@tanstack/react-query';
import styled from '@emotion/styled';

import { colors } from '@novu/design-system';

import { ROUTES } from '../../../constants/routes.enum';
import { useCreateTemplateFromBlueprint } from '../../../api/hooks';
import { errorMessage } from '../../../utils/notifications';
import { getBlueprintTemplateById } from '../../../api/notification-templates';
import { getWorkflowBlueprintDetails } from '../../../utils';
import { TemplateCreationSourceEnum } from '../../templates/shared';
import { useSegment } from '../../../components/providers/SegmentProvider';

export function CreateWorkflowButton({
blueprintIdentifier,
children,
}: {
blueprintIdentifier: string;
children: string;
}) {
const openNewTab = (route: ROUTES, param: string) =>
window.open(`${window.location.origin}${route.replace(':templateId', param)}`, '_blank', 'noreferrer noopener');

const { createTemplateFromBlueprint } = useCreateTemplateFromBlueprint({
onSuccess: (template) => {
openNewTab(ROUTES.WORKFLOWS_EDIT_TEMPLATEID, template._id ?? '');
},
onError: () => {
errorMessage('Something went wrong while creating template from blueprint, please try again later.');
},
});

const { refetch } = useQuery(
['blueprint', blueprintIdentifier],
() => getBlueprintTemplateById(blueprintIdentifier as string),
{
enabled: false,
refetchOnWindowFocus: false,

onSuccess: (data) => {
if (data) {
const { name: blueprintName } = getWorkflowBlueprintDetails(data.name);
createTemplateFromBlueprint({
blueprint: { ...data, name: blueprintName },
params: { __source: TemplateCreationSourceEnum.ONBOARDING_GET_STARTED },
});
}
},
}
);

const segment = useSegment();
const handleCreateTemplateClick = () => {
segment.track('[Template Store] Click Create Notification Template', {
templateIdentifier: blueprintIdentifier,
location: TemplateCreationSourceEnum.ONBOARDING_GET_STARTED,
});

refetch();
};

return <UnstyledButton onClick={() => handleCreateTemplateClick()}>{children}</UnstyledButton>;
}

export const UnstyledButton = styled.button`
background: none;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
outline: inherit;
color: ${colors.gradientEnd};
`;
5 changes: 4 additions & 1 deletion apps/web/src/pages/get-started/consts/DelayUseCase.const.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { CreateWorkflowButton } from '../components/CreateWorkflowButton';
import { Link, StepDescription, StepText } from './shared';
import { OnboardingUseCase } from './types';

const USECASE_BLUEPRINT_IDENTIFIER = 'get-started-delay';

export const DelayUseCaseConst: OnboardingUseCase = {
title: 'Delay step execution',
description: 'Introduces a specified time delay between workflow steps, ensuring a well-paced progression of events.',
Expand All @@ -25,7 +28,7 @@ export const DelayUseCaseConst: OnboardingUseCase = {
return (
<StepDescription>
<StepText>Novu pre-built workflow with a digest node.</StepText>
<Link children={' Customize '} href={'https://mantine.dev/core/timeline/'} />
<CreateWorkflowButton children={' Customize '} blueprintIdentifier={USECASE_BLUEPRINT_IDENTIFIER} />
<StepText>the workflow or create a new one on the Workflows page.</StepText>
</StepDescription>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Link, StepDescription, StepText } from './shared';
import { OnboardingUseCase } from './types';
import { CreateWorkflowButton } from '../components/CreateWorkflowButton';

const USECASE_BLUEPRINT_IDENTIFIER = 'get-started-digest';

export const DigestUseCaseConst: OnboardingUseCase = {
title: 'Digest multiple events',
Expand Down Expand Up @@ -27,7 +30,7 @@ export const DigestUseCaseConst: OnboardingUseCase = {
return (
<StepDescription>
<StepText>Novu pre-built workflow with a digest node.</StepText>
<Link children={' Customize '} href={'https://mantine.dev/core/timeline/'} />
<CreateWorkflowButton children={' Customize '} blueprintIdentifier={USECASE_BLUEPRINT_IDENTIFIER} />
<StepText>the workflow or create a new one on the Workflows page.</StepText>
</StepDescription>
);
Expand Down
5 changes: 4 additions & 1 deletion apps/web/src/pages/get-started/consts/InAppUseCase.const.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Link, StepDescription, StepText } from './shared';
import { OnboardingUseCase } from './types';
import { CreateWorkflowButton } from '../components/CreateWorkflowButton';

const USECASE_BLUEPRINT_IDENTIFIER = 'get-started-in-app';

export const InAppUseCaseConst: OnboardingUseCase = {
title: 'In-app notifications center',
Expand All @@ -26,7 +29,7 @@ export const InAppUseCaseConst: OnboardingUseCase = {
return (
<StepDescription>
<StepText>Novu pre-built a workflow for testing.</StepText>
<Link children={' Customize '} href={'https://mantine.dev/core/timeline/'} />
<CreateWorkflowButton children={' Customize '} blueprintIdentifier={USECASE_BLUEPRINT_IDENTIFIER} />
<StepText>it or create a new one on the Workflows page. </StepText>
</StepDescription>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Link, StepDescription, StepText } from './shared';
import { OnboardingUseCase } from './types';
import { CreateWorkflowButton } from '../components/CreateWorkflowButton';

const USECASE_BLUEPRINT_IDENTIFIER = 'get-started-multi-channel';

export const MultiChannelUseCaseConst: OnboardingUseCase = {
title: 'Multi-channel notifications',
Expand Down Expand Up @@ -28,7 +31,7 @@ export const MultiChannelUseCaseConst: OnboardingUseCase = {
return (
<StepDescription>
<StepText>Novu has prepared workflow templates.</StepText>
<Link children={' Customize '} href={'https://mantine.dev/core/timeline/'} />
<CreateWorkflowButton children={' Customize '} blueprintIdentifier={USECASE_BLUEPRINT_IDENTIFIER} />
<StepText> a Multi-Channel template or start with a blank workflow.</StepText>
</StepDescription>
);
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/pages/get-started/consts/shared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export function Link({ href, children }: { href: string; children: string }) {
</StyledLink>
);
}

export const StyledLink = styled.a`
color: ${colors.gradientEnd};
`;
1 change: 1 addition & 0 deletions apps/web/src/pages/templates/shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export enum TemplateCreationSourceEnum {
ONBOARDING_IN_APP = 'onboarding_in_app',
EMPTY_STATE = 'empty_state',
DROPDOWN = 'dropdown',
ONBOARDING_GET_STARTED = 'onboarding_get_started',
}
1 change: 1 addition & 0 deletions apps/web/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './utils';
export * from './pluralize';
export * from './templates';
13 changes: 13 additions & 0 deletions apps/web/src/utils/templates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { IconName } from '@fortawesome/fontawesome-svg-core';

export const getWorkflowBlueprintDetails = (templateName: string): { name: string; iconName: IconName } => {
const regexResult = /^:.{1,}:/.exec(templateName);
let name = '';
let iconName = 'fa-solid fa-question';
if (regexResult !== null) {
name = templateName.replace(regexResult[0], '').trim();
iconName = regexResult[0].replace(/:/g, '').trim();
}

return { name, iconName: iconName as IconName };
};
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export class NotificationTemplateRepository extends BaseRepository<
}

private get blueprintOrganizationId(): string | undefined {
return process.env.BLUEPRINT_CREATOR;
return NotificationTemplateRepository.getBlueprintOrganizationId();
}

public static getBlueprintOrganizationId(): string | undefined {
Expand Down

0 comments on commit 6ccea0b

Please sign in to comment.