diff --git a/apps/api/src/app/workflows-v2/workflow.controller.ts b/apps/api/src/app/workflows-v2/workflow.controller.ts index 4328ae85fbf..4d05d99ec2f 100644 --- a/apps/api/src/app/workflows-v2/workflow.controller.ts +++ b/apps/api/src/app/workflows-v2/workflow.controller.ts @@ -1,4 +1,4 @@ -import { ApiTags } from '@nestjs/swagger'; +import { ClassSerializerInterceptor, HttpStatus, Patch } from '@nestjs/common'; import { Body, Controller, @@ -12,7 +12,8 @@ import { UseGuards, UseInterceptors, } from '@nestjs/common/decorators'; -import { ClassSerializerInterceptor, HttpStatus, Patch } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { DeleteWorkflowCommand, DeleteWorkflowUseCase, UserAuthGuard, UserSession } from '@novu/application-generic'; import { CreateWorkflowDto, DirectionEnum, @@ -30,20 +31,10 @@ import { WorkflowResponseDto, WorkflowTestDataResponseDto, } from '@novu/shared'; -import { DeleteWorkflowCommand, DeleteWorkflowUseCase, UserAuthGuard, UserSession } from '@novu/application-generic'; import { ApiCommonResponses } from '../shared/framework/response.decorator'; import { UserAuthentication } from '../shared/framework/swagger/api.key.security'; -import { GetWorkflowCommand } from './usecases/get-workflow/get-workflow.command'; -import { UpsertWorkflowUseCase } from './usecases/upsert-workflow/upsert-workflow.usecase'; -import { UpsertWorkflowCommand } from './usecases/upsert-workflow/upsert-workflow.command'; -import { GetWorkflowUseCase } from './usecases/get-workflow/get-workflow.usecase'; -import { ListWorkflowsUseCase } from './usecases/list-workflows/list-workflow.usecase'; -import { ListWorkflowsCommand } from './usecases/list-workflows/list-workflows.command'; -import { SyncToEnvironmentUseCase } from './usecases/sync-to-environment/sync-to-environment.usecase'; -import { SyncToEnvironmentCommand } from './usecases/sync-to-environment/sync-to-environment.command'; -import { GeneratePreviewUsecase } from './usecases/generate-preview/generate-preview.usecase'; -import { ParseSlugIdPipe } from './pipes/parse-slug-id.pipe'; import { ParseSlugEnvironmentIdPipe } from './pipes/parse-slug-env-id.pipe'; +import { ParseSlugIdPipe } from './pipes/parse-slug-id.pipe'; import { BuildStepDataCommand, BuildStepDataUsecase, @@ -51,9 +42,18 @@ import { WorkflowTestDataCommand, } from './usecases'; import { GeneratePreviewCommand } from './usecases/generate-preview/generate-preview.command'; +import { GeneratePreviewUsecase } from './usecases/generate-preview/generate-preview.usecase'; +import { GetWorkflowCommand } from './usecases/get-workflow/get-workflow.command'; +import { GetWorkflowUseCase } from './usecases/get-workflow/get-workflow.usecase'; +import { ListWorkflowsUseCase } from './usecases/list-workflows/list-workflow.usecase'; +import { ListWorkflowsCommand } from './usecases/list-workflows/list-workflows.command'; import { PatchStepCommand } from './usecases/patch-step-data'; -import { PatchWorkflowCommand, PatchWorkflowUsecase } from './usecases/patch-workflow'; import { PatchStepUsecase } from './usecases/patch-step-data/patch-step.usecase'; +import { PatchWorkflowCommand, PatchWorkflowUsecase } from './usecases/patch-workflow'; +import { SyncToEnvironmentCommand } from './usecases/sync-to-environment/sync-to-environment.command'; +import { SyncToEnvironmentUseCase } from './usecases/sync-to-environment/sync-to-environment.usecase'; +import { UpsertWorkflowCommand } from './usecases/upsert-workflow/upsert-workflow.command'; +import { UpsertWorkflowUseCase } from './usecases/upsert-workflow/upsert-workflow.usecase'; @ApiCommonResponses() @Controller({ path: `/workflows`, version: '2' }) diff --git a/apps/api/src/app/workflows-v2/workflow.module.ts b/apps/api/src/app/workflows-v2/workflow.module.ts index 89331019861..28a04687111 100644 --- a/apps/api/src/app/workflows-v2/workflow.module.ts +++ b/apps/api/src/app/workflows-v2/workflow.module.ts @@ -5,19 +5,20 @@ import { DeleteWorkflowUseCase, GetPreferences, GetWorkflowByIdsUseCase, + TierRestrictionsValidateUsecase, UpdateWorkflow, UpsertControlValuesUseCase, UpsertPreferences, - TierRestrictionsValidateUsecase, } from '@novu/application-generic'; import { CommunityOrganizationRepository } from '@novu/dal'; -import { SharedModule } from '../shared/shared.module'; -import { MessageTemplateModule } from '../message-template/message-template.module'; -import { ChangeModule } from '../change/change.module'; import { AuthModule } from '../auth/auth.module'; +import { BridgeModule } from '../bridge'; +import { ChangeModule } from '../change/change.module'; +import { HydrateEmailSchemaUseCase } from '../environments-v1/usecases/output-renderers'; import { IntegrationModule } from '../integrations/integrations.module'; -import { WorkflowController } from './workflow.controller'; +import { MessageTemplateModule } from '../message-template/message-template.module'; +import { SharedModule } from '../shared/shared.module'; import { BuildVariableSchemaUsecase, BuildStepDataUsecase, @@ -28,12 +29,11 @@ import { SyncToEnvironmentUseCase, UpsertWorkflowUseCase, } from './usecases'; -import { BridgeModule } from '../bridge'; -import { HydrateEmailSchemaUseCase } from '../environments-v1/usecases/output-renderers'; import { PatchWorkflowUsecase } from './usecases/patch-workflow'; import { PatchStepUsecase } from './usecases/patch-step-data/patch-step.usecase'; import { BuildPayloadSchema } from './usecases/build-payload-schema/build-payload-schema.usecase'; import { BuildStepIssuesUsecase } from './usecases/build-step-issues/build-step-issues.usecase'; +import { WorkflowController } from './workflow.controller'; const DAL_REPOSITORIES = [CommunityOrganizationRepository]; diff --git a/apps/dashboard/public/images/dots.svg b/apps/dashboard/public/images/dots.svg new file mode 100644 index 00000000000..3d26324aecb --- /dev/null +++ b/apps/dashboard/public/images/dots.svg @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/dashboard/src/components/create-workflow-button.tsx b/apps/dashboard/src/components/create-workflow-button.tsx index 96cf427cd45..5615896eba6 100644 --- a/apps/dashboard/src/components/create-workflow-button.tsx +++ b/apps/dashboard/src/components/create-workflow-button.tsx @@ -1,14 +1,4 @@ -import { createWorkflow } from '@/api/workflows'; import { Button } from '@/components/primitives/button'; -import { - Form, - FormControl, - FormField, - FormInput, - FormItem, - FormLabel, - FormMessage, -} from '@/components/primitives/form/form'; import { Separator } from '@/components/primitives/separator'; import { Sheet, @@ -20,61 +10,27 @@ import { SheetTitle, SheetTrigger, } from '@/components/primitives/sheet'; -import { TagInput } from '@/components/primitives/tag-input'; -import { Textarea } from '@/components/primitives/textarea'; import { ExternalLink } from '@/components/shared/external-link'; -import { useEnvironment } from '@/context/environment/hooks'; -import { useTags } from '@/hooks/use-tags'; -import { QueryKeys } from '@/utils/query-keys'; -import { buildRoute, ROUTES } from '@/utils/routes'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { type CreateWorkflowDto, slugify, WorkflowCreationSourceEnum } from '@novu/shared'; -import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { ComponentProps, useState } from 'react'; -import { useForm } from 'react-hook-form'; +import { CreateWorkflowForm } from '@/components/workflow-editor/create-workflow-form'; +import { useCreateWorkflow } from '@/hooks/use-create-workflow'; +import { ComponentProps, forwardRef, useState } from 'react'; import { RiArrowRightSLine } from 'react-icons/ri'; -import { useNavigate } from 'react-router-dom'; import { z } from 'zod'; -import { MAX_DESCRIPTION_LENGTH, MAX_TAG_ELEMENTS, workflowSchema } from './workflow-editor/schema'; - -type CreateWorkflowButtonProps = ComponentProps; +import { workflowSchema } from './workflow-editor/schema'; -export const CreateWorkflowButton = (props: CreateWorkflowButtonProps) => { - const queryClient = useQueryClient(); - const navigate = useNavigate(); - const { currentEnvironment } = useEnvironment(); +export const CreateWorkflowButton = forwardRef>((props, ref) => { const [isOpen, setIsOpen] = useState(false); - // TODO: Move to a use-create-workflow.ts hook - const { mutateAsync, isPending } = useMutation({ - mutationFn: async (workflow: CreateWorkflowDto) => createWorkflow({ environment: currentEnvironment!, workflow }), - onSuccess: async (result) => { - await queryClient.invalidateQueries({ queryKey: [QueryKeys.fetchWorkflows, currentEnvironment?._id] }); - await queryClient.invalidateQueries({ - queryKey: [QueryKeys.fetchWorkflow, currentEnvironment?._id, result.data.workflowId], - }); - queryClient.invalidateQueries({ - queryKey: [QueryKeys.fetchTags, currentEnvironment?._id], - }); - setIsOpen(false); - form.reset(); - navigate( - buildRoute(ROUTES.EDIT_WORKFLOW, { - environmentSlug: currentEnvironment?.slug ?? '', - workflowSlug: result.data.slug ?? '', - }) - ); - }, + const { submit, isLoading: isCreating } = useCreateWorkflow({ + onSuccess: () => setIsOpen(false), }); - const { tags } = useTags(); - const form = useForm>({ - resolver: zodResolver(workflowSchema), - defaultValues: { description: '', workflowId: '', name: '', tags: [] }, - }); + const handleSubmit = (values: z.infer) => { + submit(values); + }; return ( - + e.preventDefault()}> Create workflow @@ -87,113 +43,12 @@ export const CreateWorkflowButton = (props: CreateWorkflowButtonProps) => { -
- { - mutateAsync({ - name: values.name, - steps: [], - __source: WorkflowCreationSourceEnum.DASHBOARD, - workflowId: values.workflowId, - description: values.description || undefined, - tags: values.tags, - }); - })} - className="flex flex-col gap-4" - > - ( - - Name - - { - field.onChange(e); - form.setValue('workflowId', slugify(e.target.value)); - }} - /> - - - - )} - /> - - ( - - Identifier - - - - - - )} - /> - - - - ( - -
- - Add tags - -
- - tag.name)} - {...field} - value={field.value ?? []} - onChange={(tags) => { - field.onChange(tags); - form.setValue('tags', tags, { shouldValidate: true }); - }} - /> - - -
- )} - /> - - ( - -
- Description -
- -