From 45f77c0c8e655d32edb9f78d12a82b6ead05384f Mon Sep 17 00:00:00 2001 From: Adam Chmara Date: Tue, 3 Dec 2024 09:45:50 +0100 Subject: [PATCH 1/6] fix(dashboard): don't use defaultValues for async content (#7187) --- .../workflow-editor/steps/configure-step-form.tsx | 12 +++++++++--- .../steps/configure-step-template-form.tsx | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx b/apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx index 174e1fa30e4..b2fbe7e1908 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx @@ -57,10 +57,16 @@ export const ConfigureStepForm = (props: ConfigureStepFormProps) => { navigate(buildRoute(ROUTES.EDIT_WORKFLOW, { environmentSlug: environment.slug!, workflowSlug: workflow.slug })); }; + const defaultValues = { + name: step.name, + stepId: step.stepId, + }; + const form = useForm>({ - defaultValues: { - name: step.name, - stepId: step.stepId, + defaultValues, + values: { + ...defaultValues, + ...step.controls.values, }, resolver: zodResolver(stepSchema), shouldFocusError: false, diff --git a/apps/dashboard/src/components/workflow-editor/steps/configure-step-template-form.tsx b/apps/dashboard/src/components/workflow-editor/steps/configure-step-template-form.tsx index 59898b51468..9232ca870fb 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/configure-step-template-form.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/configure-step-template-form.tsx @@ -60,6 +60,10 @@ export const ConfigureStepTemplateForm = (props: ConfigureStepTemplateFormProps) const form = useForm({ resolver: zodResolver(schema), defaultValues, + values: { + ...defaultValues, + ...step.controls.values, + }, shouldFocusError: false, }); From 3e196597b48f1f0b90a349bddc620804aea6e559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Tymczuk?= Date: Tue, 3 Dec 2024 09:53:36 +0100 Subject: [PATCH 2/6] fix(dashboard): in-app editor preview only call when tab is opened (#7186) --- .../in-app/configure-in-app-step-preview.tsx | 55 +++++++++--- .../steps/in-app/in-app-editor-preview.tsx | 84 +++++------------- .../steps/in-app/in-app-tabs.tsx | 28 +----- .../steps/in-app/inbox-preview.tsx | 87 +++++++++++++++++++ .../steps/use-debounced-preview.tsx | 66 -------------- .../steps/use-editor-preview.tsx | 59 +++++++++++++ apps/dashboard/src/hooks/use-preview-step.ts | 6 +- 7 files changed, 219 insertions(+), 166 deletions(-) create mode 100644 apps/dashboard/src/components/workflow-editor/steps/in-app/inbox-preview.tsx delete mode 100644 apps/dashboard/src/components/workflow-editor/steps/use-debounced-preview.tsx create mode 100644 apps/dashboard/src/components/workflow-editor/steps/use-editor-preview.tsx diff --git a/apps/dashboard/src/components/workflow-editor/steps/in-app/configure-in-app-step-preview.tsx b/apps/dashboard/src/components/workflow-editor/steps/in-app/configure-in-app-step-preview.tsx index b47034e9b30..125b9a1361c 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/in-app/configure-in-app-step-preview.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/in-app/configure-in-app-step-preview.tsx @@ -1,5 +1,8 @@ import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; +import * as Sentry from '@sentry/react'; +import { ChannelTypeEnum } from '@novu/shared'; + import { usePreviewStep } from '@/hooks'; import { InAppPreview, @@ -10,11 +13,18 @@ import { InAppPreviewNotificationContent, InAppPreviewSubject, } from '@/components/workflow-editor/in-app-preview'; -import { InAppRenderOutput } from '@novu/shared'; import { useStep } from '@/components/workflow-editor/steps/step-provider'; export function ConfigureInAppStepPreview() { - const { previewStep, data, isPending: isPreviewPending } = usePreviewStep(); + const { + previewStep, + data: previewData, + isPending: isPreviewPending, + } = usePreviewStep({ + onError: (error) => { + Sentry.captureException(error); + }, + }); const { step, isPending } = useStep(); const { workflowSlug, stepSlug } = useParams<{ @@ -32,24 +42,45 @@ export function ConfigureInAppStepPreview() { }); }, [workflowSlug, stepSlug, previewStep, step, isPending]); - if (!isPreviewPending && !data?.result) { - return null; + const previewResult = previewData?.result; + if (isPreviewPending || previewData === undefined) { + return ( + + + + + + + + + + + ); + } + + if (previewResult?.type === undefined || previewResult?.type !== ChannelTypeEnum.IN_APP) { + return ( + + + + + No preview available + + + + ); } - const preview = data?.result?.preview as InAppRenderOutput | undefined; + const preview = previewResult.preview; return ( - - - + - {preview?.subject} - - {preview?.body} - + {preview?.subject} + {preview?.body} diff --git a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-editor-preview.tsx b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-editor-preview.tsx index 449f13cda8b..e7000315c5b 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-editor-preview.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-editor-preview.tsx @@ -1,26 +1,15 @@ import { CSSProperties, useEffect, useRef, useState } from 'react'; -import { InAppRenderOutput } from '@novu/shared'; +import { type StepDataDto, type WorkflowResponseDto } from '@novu/shared'; import { Notification5Fill } from '@/components/icons'; import { Code2 } from '@/components/icons/code-2'; import { Button } from '@/components/primitives/button'; import { Editor } from '@/components/primitives/editor'; -import { - InAppPreview, - InAppPreviewActions, - InAppPreviewAvatar, - InAppPreviewBell, - InAppPreviewBody, - InAppPreviewHeader, - InAppPreviewNotification, - InAppPreviewNotificationContent, - InAppPreviewPrimaryAction, - InAppPreviewSecondaryAction, - InAppPreviewSubject, -} from '@/components/workflow-editor/in-app-preview'; import { loadLanguage } from '@uiw/codemirror-extensions-langs'; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/primitives/accordion'; import { InAppTabsSection } from '@/components/workflow-editor/steps/in-app/in-app-tabs-section'; +import { useEditorPreview } from '../use-editor-preview'; +import { InboxPreview } from './inbox-preview'; const getInitialAccordionValue = (value: string) => { try { @@ -31,22 +20,27 @@ const getInitialAccordionValue = (value: string) => { }; type InAppEditorPreviewProps = { - value: string; - onChange: (value: string) => void; - preview?: InAppRenderOutput; - applyPreview: () => void; - isPreviewPending?: boolean; + workflow: WorkflowResponseDto; + step: StepDataDto; + formValues: Record; }; -export const InAppEditorPreview = (props: InAppEditorPreviewProps) => { - const { value, onChange, preview, applyPreview, isPreviewPending } = props; - const [accordionValue, setAccordionValue] = useState(getInitialAccordionValue(value)); + +export const InAppEditorPreview = ({ workflow, step, formValues }: InAppEditorPreviewProps) => { + const workflowSlug = workflow.workflowId; + const stepSlug = step.stepId; + const { editorValue, setEditorValue, previewStep, previewData, isPreviewPending } = useEditorPreview({ + workflowSlug, + stepSlug, + controlValues: formValues, + }); + const [accordionValue, setAccordionValue] = useState(getInitialAccordionValue(editorValue)); const [payloadError, setPayloadError] = useState(''); const [height, setHeight] = useState(0); const contentRef = useRef(null); useEffect(() => { - setAccordionValue(getInitialAccordionValue(value)); - }, [value]); + setAccordionValue(getInitialAccordionValue(editorValue)); + }, [editorValue]); useEffect(() => { const timeout = setTimeout(() => { @@ -57,7 +51,7 @@ export const InAppEditorPreview = (props: InAppEditorPreviewProps) => { }, 0); return () => clearTimeout(timeout); - }, [value]); + }, [editorValue]); return ( @@ -66,39 +60,7 @@ export const InAppEditorPreview = (props: InAppEditorPreviewProps) => { In-app template editor - -
-
- - - - - - - - - - {preview?.subject} - - {preview?.body} - - - - - {preview?.primaryAction?.label} - - - - {preview?.secondaryAction?.label} - - - - - -
-
-
- + @@ -113,8 +75,8 @@ export const InAppEditorPreview = (props: InAppEditorPreviewProps) => { style={{ '--radix-collapsible-content-height': `${height}px` } as CSSProperties} > { className="self-end" onClick={() => { try { - applyPreview(); + previewStep(); setPayloadError(''); } catch (e) { setPayloadError(String(e)); diff --git a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-tabs.tsx b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-tabs.tsx index 374af7d3abe..7b281254d81 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-tabs.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/in-app/in-app-tabs.tsx @@ -1,6 +1,5 @@ -import { ChannelTypeEnum } from '@novu/shared'; import { Cross2Icon } from '@radix-ui/react-icons'; -import { FieldValues, useFormContext } from 'react-hook-form'; +import { useFormContext } from 'react-hook-form'; import { RiEdit2Line, RiPencilRuler2Line } from 'react-icons/ri'; import { useNavigate } from 'react-router-dom'; @@ -12,7 +11,6 @@ import { InAppEditor } from '@/components/workflow-editor/steps/in-app/in-app-ed import { InAppEditorPreview } from '@/components/workflow-editor/steps/in-app/in-app-editor-preview'; import { CustomStepControls } from '../controls/custom-step-controls'; import { StepEditorProps } from '@/components/workflow-editor/steps/configure-step-template-form'; -import { useDebouncedPreview } from '../use-debounced-preview'; const tabsContentClassName = 'h-full w-full overflow-y-auto'; @@ -21,10 +19,6 @@ export const InAppTabs = (props: StepEditorProps) => { const { dataSchema, uiSchema } = step.controls; const form = useFormContext(); const navigate = useNavigate(); - const { editorValue, setEditorValue, previewStep, previewData, isPreviewPending } = useDebouncedPreview({ - workflow, - step, - }); return ( @@ -64,25 +58,7 @@ export const InAppTabs = (props: StepEditorProps) => { - {previewData === undefined || - (previewData.result?.type === ChannelTypeEnum.IN_APP && ( - { - previewStep({ - stepSlug: step.stepId, - workflowSlug: workflow.workflowId, - data: { - controlValues: form.getValues() as FieldValues, - previewPayload: JSON.parse(editorValue), - }, - }); - }} - /> - ))} + diff --git a/apps/dashboard/src/components/workflow-editor/steps/in-app/inbox-preview.tsx b/apps/dashboard/src/components/workflow-editor/steps/in-app/inbox-preview.tsx new file mode 100644 index 00000000000..cb0cce3356a --- /dev/null +++ b/apps/dashboard/src/components/workflow-editor/steps/in-app/inbox-preview.tsx @@ -0,0 +1,87 @@ +import { ReactNode } from 'react'; +import { ChannelTypeEnum, type GeneratePreviewResponseDto } from '@novu/shared'; +import { + InAppPreview, + InAppPreviewActions, + InAppPreviewAvatar, + InAppPreviewBell, + InAppPreviewBody, + InAppPreviewHeader, + InAppPreviewNotification, + InAppPreviewNotificationContent, + InAppPreviewPrimaryAction, + InAppPreviewSecondaryAction, + InAppPreviewSubject, +} from '@/components/workflow-editor/in-app-preview'; + +const InboxPreviewContainer = ({ children }: { children: ReactNode }) => { + return ( +
+
+ + + + {children} + +
+
+
+ ); +}; + +export const InboxPreview = ({ + isPreviewPending, + previewData, +}: { + isPreviewPending: boolean; + previewData?: GeneratePreviewResponseDto; +}) => { + const previewResult = previewData?.result; + if (isPreviewPending || previewData === undefined) { + return ( + + + + + + + + + + + + + + ); + } + + if (previewResult?.type === undefined || previewResult?.type !== ChannelTypeEnum.IN_APP) { + return ( + + + + No preview available + + + + ); + } + + const preview = previewResult.preview; + + return ( + + + + + {preview?.subject} + {preview?.body} + + {preview?.primaryAction?.label} + {preview?.secondaryAction?.label} + + + + + ); +}; diff --git a/apps/dashboard/src/components/workflow-editor/steps/use-debounced-preview.tsx b/apps/dashboard/src/components/workflow-editor/steps/use-debounced-preview.tsx deleted file mode 100644 index f270a348935..00000000000 --- a/apps/dashboard/src/components/workflow-editor/steps/use-debounced-preview.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { useState } from 'react'; -import { useFormContext, useWatch } from 'react-hook-form'; -import type { StepDataDto, WorkflowResponseDto } from '@novu/shared'; - -import { usePreviewStep } from '@/hooks'; -import { NovuApiError } from '@/api/api.client'; -import useDebouncedEffect from '@/hooks/use-debounced-effect'; -import { ToastIcon } from '@/components/primitives/sonner'; -import { showToast } from '@/components/primitives/sonner-helpers'; - -export const useDebouncedPreview = ({ workflow, step }: { workflow: WorkflowResponseDto; step: StepDataDto }) => { - const [editorValue, setEditorValue] = useState('{}'); - const { previewStep, data: previewData, isPending: isPreviewPending } = usePreviewStep(); - - const preview = async (props: { - controlValues: Record; - previewPayload: Record; - }) => { - try { - const res = await previewStep({ - workflowSlug: workflow.workflowId, - stepSlug: step.stepId, - data: { controlValues: props.controlValues, previewPayload: props.previewPayload }, - }); - setEditorValue(JSON.stringify(res.previewPayloadExample, null, 2)); - } catch (err) { - if (err instanceof NovuApiError) { - showToast({ - children: () => ( - <> - - - Failed to preview step {step.name} with error: {err.message} - - - ), - options: { - position: 'bottom-right', - classNames: { - toast: 'ml-10 mb-4', - }, - }, - }); - } - } - }; - - const form = useFormContext(); - const formValues = useWatch(form); - useDebouncedEffect( - () => { - preview({ - controlValues: form.getValues() as Record, - /** - * Reset the preview payload to an empty object on form change - * to prevent showing the previous payload - */ - previewPayload: {}, - }); - }, - 2000, - [formValues] - ); - - return { editorValue, setEditorValue, previewStep, previewData, isPreviewPending }; -}; diff --git a/apps/dashboard/src/components/workflow-editor/steps/use-editor-preview.tsx b/apps/dashboard/src/components/workflow-editor/steps/use-editor-preview.tsx new file mode 100644 index 00000000000..c1132dbe3ea --- /dev/null +++ b/apps/dashboard/src/components/workflow-editor/steps/use-editor-preview.tsx @@ -0,0 +1,59 @@ +import { useCallback, useEffect, useState } from 'react'; +import * as Sentry from '@sentry/react'; + +import { usePreviewStep } from '@/hooks'; +import { useDataRef } from '@/hooks/use-data-ref'; + +export const useEditorPreview = ({ + workflowSlug, + stepSlug, + controlValues, +}: { + workflowSlug: string; + stepSlug: string; + controlValues: Record; +}) => { + const [editorValue, setEditorValue] = useState('{}'); + const { + previewStep, + data: previewData, + isPending: isPreviewPending, + } = usePreviewStep({ + onSuccess: (res) => { + setEditorValue(JSON.stringify(res.previewPayloadExample, null, 2)); + }, + onError: (error) => { + Sentry.captureException(error); + }, + }); + const dataRef = useDataRef({ + workflowSlug, + stepSlug, + controlValues, + editorValue, + }); + + useEffect(() => { + previewStep({ + workflowSlug: dataRef.current.workflowSlug, + stepSlug: dataRef.current.stepSlug, + data: { controlValues: dataRef.current.controlValues, previewPayload: JSON.parse(dataRef.current.editorValue) }, + }); + }, [dataRef, previewStep]); + + const previewStepCallback = useCallback(() => { + return previewStep({ + workflowSlug, + stepSlug, + data: { controlValues, previewPayload: JSON.parse(editorValue) }, + }); + }, [workflowSlug, stepSlug, controlValues, editorValue, previewStep]); + + return { + editorValue, + setEditorValue, + previewStep: previewStepCallback, + previewData, + isPreviewPending, + }; +}; diff --git a/apps/dashboard/src/hooks/use-preview-step.ts b/apps/dashboard/src/hooks/use-preview-step.ts index 3fb4f3aca37..cfadd85262c 100644 --- a/apps/dashboard/src/hooks/use-preview-step.ts +++ b/apps/dashboard/src/hooks/use-preview-step.ts @@ -2,10 +2,14 @@ import type { GeneratePreviewResponseDto } from '@novu/shared'; import { useMutation } from '@tanstack/react-query'; import { previewStep } from '@/api/workflows'; -export const usePreviewStep = ({ onSuccess }: { onSuccess?: (data: GeneratePreviewResponseDto) => void } = {}) => { +export const usePreviewStep = ({ + onSuccess, + onError, +}: { onSuccess?: (data: GeneratePreviewResponseDto) => void; onError?: (error: Error) => void } = {}) => { const { mutateAsync, isPending, error, data } = useMutation({ mutationFn: previewStep, onSuccess, + onError, }); return { From 496dbc2bb5227f22eec0e6495dc96811352f3718 Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Tue, 3 Dec 2024 11:12:54 +0200 Subject: [PATCH 3/6] feat(dashboard): signout from v2 should navigatefor new login page (#7196) --- apps/dashboard/src/components/user-profile.tsx | 2 -- apps/dashboard/src/context/clerk-provider.tsx | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/dashboard/src/components/user-profile.tsx b/apps/dashboard/src/components/user-profile.tsx index c602e516f40..39b0a2b28ed 100644 --- a/apps/dashboard/src/components/user-profile.tsx +++ b/apps/dashboard/src/components/user-profile.tsx @@ -1,14 +1,12 @@ import { UserButton } from '@clerk/clerk-react'; import { useNewDashboardOptIn } from '@/hooks/use-new-dashboard-opt-in'; import { RiSignpostFill } from 'react-icons/ri'; -import { LEGACY_DASHBOARD_URL } from '@/config'; export function UserProfile() { const { optOut } = useNewDashboardOptIn(); return ( { routerPush={(to) => navigate(to)} routerReplace={(to) => navigate(to, { replace: true })} publishableKey={CLERK_PUBLISHABLE_KEY} + afterSignOutUrl={ROUTES.SIGN_IN} appearance={{ userButton: { elements: { From c89d5d6ad94226b72e24c514ee2d413a90e90dff Mon Sep 17 00:00:00 2001 From: Dima Grossman Date: Tue, 3 Dec 2024 11:13:21 +0200 Subject: [PATCH 4/6] refactor(dashboard): use the update motion library instead of framer-motion (#7193) --- apps/dashboard/package.json | 2 +- .../src/components/animated-outlet.tsx | 2 +- .../configure-workflow-form.tsx | 2 +- .../steps/configure-step-form.tsx | 2 +- .../steps/configure-step-template.tsx | 2 +- .../src/pages/usecase-select-page.tsx | 2 +- pnpm-lock.yaml | 145 ++++++++++++------ 7 files changed, 101 insertions(+), 56 deletions(-) diff --git a/apps/dashboard/package.json b/apps/dashboard/package.json index fe06437380d..52b8c6f9d8c 100644 --- a/apps/dashboard/package.json +++ b/apps/dashboard/package.json @@ -65,7 +65,7 @@ "cmdk": "1.0.0", "date-fns": "^4.1.0", "flat": "^6.0.1", - "framer-motion": "^11.3.19", + "motion": "^11.12.0", "js-cookie": "^3.0.5", "lodash.debounce": "^4.0.8", "lodash.merge": "^4.6.2", diff --git a/apps/dashboard/src/components/animated-outlet.tsx b/apps/dashboard/src/components/animated-outlet.tsx index d2fe81de589..e25c91a3eee 100644 --- a/apps/dashboard/src/components/animated-outlet.tsx +++ b/apps/dashboard/src/components/animated-outlet.tsx @@ -1,6 +1,6 @@ import React, { useRef } from 'react'; import { useLocation, useOutlet } from 'react-router-dom'; -import { AnimatePresence } from 'framer-motion'; +import { AnimatePresence } from 'motion/react'; export const AnimatedOutlet = (): React.JSX.Element => { const { pathname, state } = useLocation(); diff --git a/apps/dashboard/src/components/workflow-editor/configure-workflow-form.tsx b/apps/dashboard/src/components/workflow-editor/configure-workflow-form.tsx index e9fd926334c..d8409e3a55f 100644 --- a/apps/dashboard/src/components/workflow-editor/configure-workflow-form.tsx +++ b/apps/dashboard/src/components/workflow-editor/configure-workflow-form.tsx @@ -1,4 +1,4 @@ -import { motion } from 'framer-motion'; +import { motion } from 'motion/react'; import { useState } from 'react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; diff --git a/apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx b/apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx index b2fbe7e1908..9e3b188a548 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/configure-step-form.tsx @@ -7,7 +7,7 @@ import { WorkflowOriginEnum, WorkflowResponseDto, } from '@novu/shared'; -import { motion } from 'framer-motion'; +import { motion } from 'motion/react'; import { useMemo, useState } from 'react'; import { useForm } from 'react-hook-form'; import { RiArrowLeftSLine, RiArrowRightSLine, RiCloseFill, RiDeleteBin2Line, RiPencilRuler2Fill } from 'react-icons/ri'; diff --git a/apps/dashboard/src/components/workflow-editor/steps/configure-step-template.tsx b/apps/dashboard/src/components/workflow-editor/steps/configure-step-template.tsx index 681d5642c9a..c7137455e1b 100644 --- a/apps/dashboard/src/components/workflow-editor/steps/configure-step-template.tsx +++ b/apps/dashboard/src/components/workflow-editor/steps/configure-step-template.tsx @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import { motion } from 'framer-motion'; +import { motion } from 'motion/react'; import { useNavigate, useParams } from 'react-router-dom'; import { diff --git a/apps/dashboard/src/pages/usecase-select-page.tsx b/apps/dashboard/src/pages/usecase-select-page.tsx index 89119615a52..baf52cd7d45 100644 --- a/apps/dashboard/src/pages/usecase-select-page.tsx +++ b/apps/dashboard/src/pages/usecase-select-page.tsx @@ -1,7 +1,7 @@ import { UsecaseSelectOnboarding } from '../components/auth/usecase-selector'; import { AuthCard } from '../components/auth/auth-card'; import { useState } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; +import { motion, AnimatePresence } from 'motion/react'; import { Button } from '../components/primitives/button'; import { ROUTES } from '../utils/routes'; import { useNavigate } from 'react-router-dom'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f518641b269..b6f796e7c77 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -793,9 +793,6 @@ importers: flat: specifier: ^6.0.1 version: 6.0.1 - framer-motion: - specifier: ^11.3.19 - version: 11.3.19(@emotion/is-prop-valid@1.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) js-cookie: specifier: ^3.0.5 version: 3.0.5 @@ -814,6 +811,9 @@ importers: mixpanel-browser: specifier: ^2.52.0 version: 2.53.0 + motion: + specifier: ^11.12.0 + version: 11.12.0(@emotion/is-prop-valid@1.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-themes: specifier: ^0.3.0 version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -3686,7 +3686,7 @@ importers: version: 5.3.0 compression-webpack-plugin: specifier: ^10.0.0 - version: 10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) + version: 10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)) concurrently: specifier: ^5.3.0 version: 5.3.0 @@ -3695,13 +3695,13 @@ importers: version: 7.0.4(postcss@8.4.38) esbuild-plugin-compress: specifier: ^1.0.1 - version: 1.0.1(esbuild@0.23.1) + version: 1.0.1(esbuild@0.21.5) esbuild-plugin-inline-import: specifier: ^1.0.4 version: 1.0.4 esbuild-plugin-solid: specifier: ^0.6.0 - version: 0.6.0(esbuild@0.23.1)(solid-js@1.8.17) + version: 0.6.0(esbuild@0.21.5)(solid-js@1.8.17) http-server: specifier: ^0.13.0 version: 0.13.0 @@ -3734,28 +3734,28 @@ importers: version: 1.0.7(tailwindcss@3.4.4(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))) terser-webpack-plugin: specifier: ^5.3.9 - version: 5.3.9(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) + version: 5.3.9(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)) tiny-glob: specifier: ^0.2.9 version: 0.2.9 ts-jest: specifier: ^29.0.3 - version: 29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.1)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) + version: 29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.21.5)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) ts-loader: specifier: ~9.4.0 - version: 9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) + version: 9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)) tsup: specifier: ^8.1.0 version: 8.1.0(@microsoft/api-extractor@7.47.7(@types/node@20.16.5))(@swc/core@1.7.26(@swc/helpers@0.5.12))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(typescript@5.6.2) tsup-preset-solid: specifier: ^2.2.0 - version: 2.2.0(esbuild@0.23.1)(solid-js@1.8.17)(tsup@8.1.0(@microsoft/api-extractor@7.47.7(@types/node@20.16.5))(@swc/core@1.7.26(@swc/helpers@0.5.12))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(typescript@5.6.2)) + version: 2.2.0(esbuild@0.21.5)(solid-js@1.8.17)(tsup@8.1.0(@microsoft/api-extractor@7.47.7(@types/node@20.16.5))(@swc/core@1.7.26(@swc/helpers@0.5.12))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(typescript@5.6.2)) typescript: specifier: 5.6.2 version: 5.6.2 webpack: specifier: ^5.74.0 - version: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + version: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) webpack-bundle-analyzer: specifier: ^4.9.0 version: 4.10.1 @@ -3914,7 +3914,7 @@ importers: version: 0.0.0 ts-jest: specifier: ^29.1.2 - version: 29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.1)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) + version: 29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.21.5)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2) typedoc: specifier: ^0.24.0 version: 0.24.6(typescript@5.6.2) @@ -23041,6 +23041,20 @@ packages: resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} engines: {node: '>=0.10.0'} + framer-motion@11.12.0: + resolution: {integrity: sha512-gZaZeqFM6pX9kMVti60hYAa75jGpSsGYWAHbBfIkuHN7DkVHVkxSxeNYnrGmHuM0zPkWTzQx10ZT+fDjn7N4SA==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + framer-motion@11.3.19: resolution: {integrity: sha512-+luuQdx4AsamyMcvzW7jUAJYIKvQs1KE7oHvKkW3eNzmo0S+3PSDWjBuQkuIP9WyneGnKGMLUSuHs8OP7jKpQg==} peerDependencies: @@ -27018,9 +27032,9 @@ packages: engines: {node: '>= 14.0.0'} hasBin: true - mocha@10.8.2: - resolution: {integrity: sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==} - engines: {node: '>= 14.0.0'} + mocha@11.0.1: + resolution: {integrity: sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true mocha@8.4.0: @@ -27125,6 +27139,20 @@ packages: resolution: {integrity: sha512-p6VSbYKvD4ZIabqo8C0kS5eKX1Xpji+opTAIJ9wyuPJ8Y/FblgXSMnFRXnB40bYZLKPQT089K5KU8+bqIXtFdw==} engines: {node: '>=16.20.1'} + motion@11.12.0: + resolution: {integrity: sha512-BFH9vwCs4dI9t1W1/1HonahOCnTxcKfzBR8D310wHFdx7oIwlP/51OqLNGO74lxOdCpTLf5BLe233k6yRqJo9Q==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + mpath@0.9.0: resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} engines: {node: '>=4.0.0'} @@ -58592,9 +58620,9 @@ snapshots: '@webcontainer/api@1.2.0': {} - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4))': @@ -58602,9 +58630,9 @@ snapshots: webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4))': @@ -58612,9 +58640,9 @@ snapshots: webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4))': dependencies: - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0) '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.9.0)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4))': @@ -61397,11 +61425,11 @@ snapshots: dependencies: mime-db: 1.52.0 - compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): + compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)): dependencies: schema-utils: 4.0.0 serialize-javascript: 6.0.1 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) compression-webpack-plugin@10.0.0(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: @@ -62362,7 +62390,7 @@ snapshots: cypress-intellij-reporter@0.0.7: dependencies: - mocha: 10.8.2 + mocha: 11.0.1 cypress-network-idle@1.14.2: {} @@ -63413,31 +63441,31 @@ snapshots: esbuild-plugin-alias@0.2.1: {} - esbuild-plugin-compress@1.0.1(esbuild@0.23.1): + esbuild-plugin-compress@1.0.1(esbuild@0.21.5): dependencies: chalk: 4.1.2 - esbuild: 0.23.1 + esbuild: 0.21.5 fs-extra: 10.1.0 micromatch: 4.0.5 esbuild-plugin-inline-import@1.0.4: {} - esbuild-plugin-solid@0.5.0(esbuild@0.23.1)(solid-js@1.8.17): + esbuild-plugin-solid@0.5.0(esbuild@0.21.5)(solid-js@1.8.17): dependencies: '@babel/core': 7.25.2 '@babel/preset-typescript': 7.23.2(@babel/core@7.25.2) babel-preset-solid: 1.8.17(@babel/core@7.25.2) - esbuild: 0.23.1 + esbuild: 0.21.5 solid-js: 1.8.17 transitivePeerDependencies: - supports-color - esbuild-plugin-solid@0.6.0(esbuild@0.23.1)(solid-js@1.8.17): + esbuild-plugin-solid@0.6.0(esbuild@0.21.5)(solid-js@1.8.17): dependencies: '@babel/core': 7.24.4 '@babel/preset-typescript': 7.23.2(@babel/core@7.24.4) babel-preset-solid: 1.8.17(@babel/core@7.24.4) - esbuild: 0.23.1 + esbuild: 0.21.5 solid-js: 1.8.17 transitivePeerDependencies: - supports-color @@ -65423,6 +65451,14 @@ snapshots: dependencies: map-cache: 0.2.2 + framer-motion@11.12.0(@emotion/is-prop-valid@1.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + tslib: 2.7.0 + optionalDependencies: + '@emotion/is-prop-valid': 1.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + framer-motion@11.3.19(@emotion/is-prop-valid@1.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: tslib: 2.7.0 @@ -71492,7 +71528,7 @@ snapshots: yargs-parser: 20.2.4 yargs-unparser: 2.0.0 - mocha@10.8.2: + mocha@11.0.1: dependencies: ansi-colors: 4.1.3 browser-stdout: 1.3.1 @@ -71501,7 +71537,7 @@ snapshots: diff: 5.2.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 - glob: 8.1.0 + glob: 10.4.5 he: 1.2.0 js-yaml: 4.1.0 log-symbols: 4.1.0 @@ -71679,6 +71715,15 @@ snapshots: - supports-color optional: true + motion@11.12.0(@emotion/is-prop-valid@1.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + framer-motion: 11.12.0(@emotion/is-prop-valid@1.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + tslib: 2.7.0 + optionalDependencies: + '@emotion/is-prop-valid': 1.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + mpath@0.9.0: {} mquery@5.0.0: @@ -78876,17 +78921,17 @@ snapshots: optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) - terser-webpack-plugin@5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.6 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.7.26(@swc/helpers@0.5.12) - esbuild: 0.23.1 + esbuild: 0.21.5 terser-webpack-plugin@5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: @@ -78944,17 +78989,17 @@ snapshots: optionalDependencies: '@swc/core': 1.3.107(@swc/helpers@0.5.12) - terser-webpack-plugin@5.3.9(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.9(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.1 terser: 5.22.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.7.26(@swc/helpers@0.5.12) - esbuild: 0.23.1 + esbuild: 0.21.5 terser@5.16.9: dependencies: @@ -79418,7 +79463,7 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.25.2) - ts-jest@29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.23.1)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): + ts-jest@29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.21.5)(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -79434,7 +79479,7 @@ snapshots: '@babel/core': 7.25.2 '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.25.2) - esbuild: 0.23.1 + esbuild: 0.21.5 ts-jest@29.1.2(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@20.16.5)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.3.107(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2)))(typescript@5.6.2): dependencies: @@ -79462,14 +79507,14 @@ snapshots: typescript: 5.6.2 webpack: 5.94.0(@swc/core@1.7.26(@swc/helpers@0.5.12)) - ts-loader@9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)): + ts-loader@9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)): dependencies: chalk: 4.1.2 enhanced-resolve: 5.17.1 micromatch: 4.0.8 semver: 7.6.3 typescript: 5.6.2 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) ts-loader@9.4.4(typescript@5.6.2)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(webpack-cli@5.1.4)): dependencies: @@ -79796,9 +79841,9 @@ snapshots: tslib@2.7.0: {} - tsup-preset-solid@2.2.0(esbuild@0.23.1)(solid-js@1.8.17)(tsup@8.1.0(@microsoft/api-extractor@7.47.7(@types/node@20.16.5))(@swc/core@1.7.26(@swc/helpers@0.5.12))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(typescript@5.6.2)): + tsup-preset-solid@2.2.0(esbuild@0.21.5)(solid-js@1.8.17)(tsup@8.1.0(@microsoft/api-extractor@7.47.7(@types/node@20.16.5))(@swc/core@1.7.26(@swc/helpers@0.5.12))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(typescript@5.6.2)): dependencies: - esbuild-plugin-solid: 0.5.0(esbuild@0.23.1)(solid-js@1.8.17) + esbuild-plugin-solid: 0.5.0(esbuild@0.21.5)(solid-js@1.8.17) tsup: 8.1.0(@microsoft/api-extractor@7.47.7(@types/node@20.16.5))(@swc/core@1.7.26(@swc/helpers@0.5.12))(postcss@8.4.38)(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.12))(@types/node@20.16.5)(typescript@5.6.2))(typescript@5.6.2) transitivePeerDependencies: - esbuild @@ -81530,9 +81575,9 @@ snapshots: webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.1)(webpack@5.78.0))(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -81541,7 +81586,7 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4) + webpack: 5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4) webpack-merge: 5.9.0 optionalDependencies: webpack-bundle-analyzer: 4.10.1 @@ -81863,7 +81908,7 @@ snapshots: - esbuild - uglify-js - webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4): + webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.4 '@types/estree': 0.0.51 @@ -81886,7 +81931,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.23.1)(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.10(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack@5.78.0(@swc/core@1.7.26(@swc/helpers@0.5.12))(esbuild@0.21.5)(webpack-cli@5.1.4)) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: From 4b0e6e204b06634c8f2cb715552c8472531aa0bc Mon Sep 17 00:00:00 2001 From: George Djabarov <39195835+djabarovgeorge@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:30:44 +0200 Subject: [PATCH 5/6] feat(api): gracefully preview (#7190) --- .../workflows-v2/e2e/generate-preview.e2e.ts | 22 +++-- .../generate-preview.usecase.ts | 89 ++++++++++++------- 2 files changed, 75 insertions(+), 36 deletions(-) diff --git a/apps/api/src/app/workflows-v2/e2e/generate-preview.e2e.ts b/apps/api/src/app/workflows-v2/e2e/generate-preview.e2e.ts index 0f77275dd73..236c38d7ddb 100644 --- a/apps/api/src/app/workflows-v2/e2e/generate-preview.e2e.ts +++ b/apps/api/src/app/workflows-v2/e2e/generate-preview.e2e.ts @@ -424,7 +424,7 @@ describe('Workflow Step Preview - POST /:workflowId/step/:stepId/preview', () => }); }); - it('should return 404 for non-existent workflow', async () => { + it('should return 201 for non-existent workflow', async () => { const pay = { type: 'object', properties: { @@ -450,11 +450,16 @@ describe('Workflow Step Preview - POST /:workflowId/step/:stepId/preview', () => controlValues: {}, }); - expect(response.status).to.equal(404); - expect(response.body.message).to.contain('Workflow cannot be found'); + expect(response.status).to.equal(201); + expect(response.body.data).to.deep.equal({ + result: { + preview: {}, + }, + previewPayloadExample: {}, + }); }); - it('should return 400 for non-existent step', async () => { + it('should return 201 for non-existent step', async () => { const pay = { type: 'object', properties: { @@ -478,8 +483,13 @@ describe('Workflow Step Preview - POST /:workflowId/step/:stepId/preview', () => controlValues: {}, }); - expect(response.status).to.equal(400); - expect(response.body.message).to.contain('No step found'); + expect(response.status).to.equal(201); + expect(response.body.data).to.deep.equal({ + result: { + preview: {}, + }, + previewPayloadExample: {}, + }); }); async function createWorkflow(overrides: Partial = {}): Promise { diff --git a/apps/api/src/app/workflows-v2/usecases/generate-preview/generate-preview.usecase.ts b/apps/api/src/app/workflows-v2/usecases/generate-preview/generate-preview.usecase.ts index daec6244c01..6ba1be7b38b 100644 --- a/apps/api/src/app/workflows-v2/usecases/generate-preview/generate-preview.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/generate-preview/generate-preview.usecase.ts @@ -1,4 +1,4 @@ -import { Injectable, InternalServerErrorException } from '@nestjs/common'; +import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common'; import _ from 'lodash'; import { ChannelTypeEnum, @@ -14,7 +14,9 @@ import { WorkflowInternalResponseDto, Instrument, InstrumentUsecase, + PinoLogger, } from '@novu/application-generic'; +import { captureException } from '@sentry/node'; import { PreviewStep, PreviewStepCommand } from '../../../bridge/usecases/preview-step'; import { FrameworkPreviousStepsOutputState } from '../../../bridge/usecases/preview-step/preview-step.command'; import { BuildStepDataUsecase } from '../build-step-data'; @@ -24,48 +26,75 @@ import { pathsToObject } from '../../util/path-to-object'; import { createMockPayloadFromSchema, flattenObjectValues } from '../../util/utils'; import { PrepareAndValidateContentUsecase } from '../validate-content/prepare-and-validate-content/prepare-and-validate-content.usecase'; +const LOG_CONTEXT = 'GeneratePreviewUsecase'; + @Injectable() export class GeneratePreviewUsecase { constructor( private legacyPreviewStepUseCase: PreviewStep, private buildStepDataUsecase: BuildStepDataUsecase, private getWorkflowByIdsUseCase: GetWorkflowByIdsUseCase, + private readonly logger: PinoLogger, private prepareAndValidateContentUsecase: PrepareAndValidateContentUsecase ) {} @InstrumentUsecase() async execute(command: GeneratePreviewCommand): Promise { - const { previewPayload: commandVariablesExample, controlValues: commandControlValues } = - command.generatePreviewRequestDto; - const stepData = await this.getStepData(command); - const workflow = await this.findWorkflow(command); - const preparedAndValidatedContent = await this.prepareAndValidateContentUsecase.execute({ - user: command.user, - previewPayloadFromDto: commandVariablesExample, - controlValues: commandControlValues || stepData.controls.values || {}, - controlDataSchema: stepData.controls.dataSchema || {}, - variableSchema: stepData.variables, - }); - const variablesExample = this.buildVariablesExample( - workflow, - preparedAndValidatedContent.finalPayload, - commandVariablesExample - ); + try { + const { previewPayload: commandVariablesExample, controlValues: commandControlValues } = + command.generatePreviewRequestDto; + const stepData = await this.getStepData(command); + const workflow = await this.findWorkflow(command); + const preparedAndValidatedContent = await this.prepareAndValidateContentUsecase.execute({ + user: command.user, + previewPayloadFromDto: commandVariablesExample, + controlValues: commandControlValues || stepData.controls.values || {}, + controlDataSchema: stepData.controls.dataSchema || {}, + variableSchema: stepData.variables, + }); + const variablesExample = this.buildVariablesExample( + workflow, + preparedAndValidatedContent.finalPayload, + commandVariablesExample + ); - const executeOutput = await this.executePreviewUsecase( - command, - stepData, - variablesExample, - preparedAndValidatedContent.finalControlValues - ); + const executeOutput = await this.executePreviewUsecase( + command, + stepData, + variablesExample, + preparedAndValidatedContent.finalControlValues + ); - return { - result: { - preview: executeOutput.outputs as any, - type: stepData.type as unknown as ChannelTypeEnum, - }, - previewPayloadExample: variablesExample, - }; + return { + result: { + preview: executeOutput.outputs as any, + type: stepData.type as unknown as ChannelTypeEnum, + }, + previewPayloadExample: variablesExample, + }; + } catch (error) { + this.logger.error( + { + err: error, + workflowIdOrInternalId: command.identifierOrInternalId, + stepIdOrInternalId: command.stepDatabaseId, + }, + `Unexpected error while generating preview`, + LOG_CONTEXT + ); + + if (process.env.SENTRY_DSN) { + captureException(error); + } + + return { + result: { + preview: {}, + type: undefined, + }, + previewPayloadExample: {}, + } as any; + } } @Instrument() From 32b40a1b7f90a57eabdc8b3b61e63c85bf2ca157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Tymczuk?= Date: Tue, 3 Dec 2024 11:31:19 +0100 Subject: [PATCH 6/6] chore(dashboard): beta label (#7197) --- .../src/components/primitives/badge.tsx | 15 +++++--- .../src/components/primitives/tag-input.tsx | 2 +- .../workflow-editor/add-step-menu.tsx | 2 +- .../workflow-editor/editor-breadcrumbs.tsx | 34 ++++++++++++++----- .../dashboard/src/components/workflow-row.tsx | 2 +- apps/dashboard/src/pages/workflows.tsx | 17 ++++++++-- 6 files changed, 53 insertions(+), 19 deletions(-) diff --git a/apps/dashboard/src/components/primitives/badge.tsx b/apps/dashboard/src/components/primitives/badge.tsx index d8e4b050482..c7b269096b3 100644 --- a/apps/dashboard/src/components/primitives/badge.tsx +++ b/apps/dashboard/src/components/primitives/badge.tsx @@ -3,26 +3,31 @@ import { cva, type VariantProps } from 'class-variance-authority'; import * as React from 'react'; const badgeVariants = cva( - 'inline-flex items-center [&>svg]:shrink-0 gap-1 h-fit border text-xs transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', + 'inline-flex items-center [&>svg]:shrink-0 gap-1 h-fit border transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', { variants: { variant: { - neutral: 'border-neutral-500 bg-neutral-500', + neutral: 'border-neutral-100 bg-neutral-100 text-neutral-500', destructive: 'border-transparent bg-destructive/10 text-destructive', success: 'border-transparent bg-success/10 text-success', warning: 'border-transparent bg-warning/10 text-warning', soft: 'bg-neutral-alpha-200 text-foreground-500 border-transparent', outline: 'border-neutral-alpha-200 bg-transparent font-normal text-foreground-600 shadow-sm', }, - size: { + kind: { default: 'rounded-md px-2 py-1', pill: 'rounded-full px-2', 'pill-stroke': 'rounded-full px-2', tag: 'rounded-md py-0.5 px-2', }, + size: { + default: 'text-xs', + '2xs': 'text-[10px] leading-[14px] font-medium', + }, }, defaultVariants: { variant: 'neutral', + kind: 'default', size: 'default', }, } @@ -30,8 +35,8 @@ const badgeVariants = cva( export interface BadgeProps extends React.HTMLAttributes, VariantProps {} -function Badge({ className, variant, size, ...props }: BadgeProps) { - return
; +function Badge({ className, variant, kind, size, ...props }: BadgeProps) { + return
; } export { Badge }; diff --git a/apps/dashboard/src/components/primitives/tag-input.tsx b/apps/dashboard/src/components/primitives/tag-input.tsx index e71877e1c36..f604b6a44b1 100644 --- a/apps/dashboard/src/components/primitives/tag-input.tsx +++ b/apps/dashboard/src/components/primitives/tag-input.tsx @@ -77,7 +77,7 @@ const TagInput = forwardRef((props, ref) => {
{tags.map((tag, index) => ( - + {tag} - {breadcrumbs.map(({ label, href }) => ( + {breadcrumbs.map(({ label, href, node }) => ( - + {label} + {node} ))} - - -
- {workflow?.name} -
-
+ {workflow && ( + + {workflow.origin === WorkflowOriginEnum.EXTERNAL ? ( + + + + ) : ( + + )} +
+ {workflow?.name} +
+
+ )}
diff --git a/apps/dashboard/src/components/workflow-row.tsx b/apps/dashboard/src/components/workflow-row.tsx index 4f4ca82441b..68ce9d852b6 100644 --- a/apps/dashboard/src/components/workflow-row.tsx +++ b/apps/dashboard/src/components/workflow-row.tsx @@ -163,7 +163,7 @@ export const WorkflowRow = ({ workflow }: WorkflowRowProps) => {
{workflow.origin === WorkflowOriginEnum.EXTERNAL && ( - + )} diff --git a/apps/dashboard/src/pages/workflows.tsx b/apps/dashboard/src/pages/workflows.tsx index f7aaf78959f..155f04f11d5 100644 --- a/apps/dashboard/src/pages/workflows.tsx +++ b/apps/dashboard/src/pages/workflows.tsx @@ -1,14 +1,16 @@ +import { useEffect } from 'react'; +import { RiSearch2Line } from 'react-icons/ri'; + import { WorkflowList } from '@/components/workflow-list'; import { DashboardLayout } from '@/components/dashboard-layout'; import { Input } from '@/components/primitives/input'; import { Button } from '@/components/primitives/button'; -import { RiSearch2Line } from 'react-icons/ri'; import { CreateWorkflowButton } from '@/components/create-workflow-button'; import { OptInModal } from '@/components/opt-in-modal'; import { PageMeta } from '@/components/page-meta'; import { useTelemetry } from '../hooks'; import { TelemetryEvent } from '../utils/telemetry'; -import { useEffect } from 'react'; +import { Badge } from '@/components/primitives/badge'; export const WorkflowsPage = () => { const track = useTelemetry(); @@ -20,7 +22,16 @@ export const WorkflowsPage = () => { return ( <> - Workflows}> + + Workflows + + BETA + + + } + >