diff --git a/.cspell.json b/.cspell.json
index 25da9e54a74..0d43f085485 100644
--- a/.cspell.json
+++ b/.cspell.json
@@ -52,6 +52,7 @@
"bcast",
"behaviour",
"bestguess",
+ "tiptap",
"binipdisplay",
"bitauth",
"bitjson",
diff --git a/.source b/.source
index 576af8c50e1..1d76acb9fce 160000
--- a/.source
+++ b/.source
@@ -1 +1 @@
-Subproject commit 576af8c50e10b4e1b42ee7e39f84a7c4f8d5a8d0
+Subproject commit 1d76acb9fce3db9dfa13329488a8128bfdd748eb
diff --git a/apps/api/src/app/events/e2e/bridge-trigger.e2e.ts b/apps/api/src/app/events/e2e/bridge-trigger.e2e.ts
index 4f79ef9e201..562c0fa099a 100644
--- a/apps/api/src/app/events/e2e/bridge-trigger.e2e.ts
+++ b/apps/api/src/app/events/e2e/bridge-trigger.e2e.ts
@@ -583,7 +583,7 @@ contexts.forEach((context: Context) => {
controlSchema: {
type: 'object',
properties: {
- name: { type: 'string', default: 'Hello {{name}}' },
+ name: { type: 'string', default: 'Hello {{payload.name}}' },
},
} as const,
}
diff --git a/apps/web/src/components/layout/components/LocalStudioHeader/LocalStudioHeader.tsx b/apps/web/src/components/layout/components/LocalStudioHeader/LocalStudioHeader.tsx
index e17ff40125d..9fa41653478 100644
--- a/apps/web/src/components/layout/components/LocalStudioHeader/LocalStudioHeader.tsx
+++ b/apps/web/src/components/layout/components/LocalStudioHeader/LocalStudioHeader.tsx
@@ -21,6 +21,8 @@ export const LocalStudioHeader: FC = () => {
borderBottom: 'none !important',
zIndex: 'sticky',
padding: '50',
+ // TODO: because this component is directly from mantine, it doesn't respect layer styles
+ bgColor: 'surface.page !important',
})}
>
diff --git a/apps/web/src/components/layout/components/LocalStudioSidebar/LocalStudioSidebarOrganizationDisplay.tsx b/apps/web/src/components/layout/components/LocalStudioSidebar/LocalStudioSidebarOrganizationDisplay.tsx
index d67894fb205..20e328c79e5 100644
--- a/apps/web/src/components/layout/components/LocalStudioSidebar/LocalStudioSidebarOrganizationDisplay.tsx
+++ b/apps/web/src/components/layout/components/LocalStudioSidebar/LocalStudioSidebarOrganizationDisplay.tsx
@@ -2,7 +2,7 @@ import { LocalizedMessage, Text } from '@novu/novui';
import { Flex, Stack } from '@novu/novui/jsx';
import { FC } from 'react';
import { css } from '@novu/novui/css';
-import { Popover, Tooltip, useColorScheme } from '@novu/design-system';
+import { Popover, useColorScheme } from '@novu/design-system';
import { useDisclosure } from '@mantine/hooks';
type LocalStudioSidebarOrganizationDisplayProps = {
@@ -24,6 +24,9 @@ export const LocalStudioSidebarOrganizationDisplay: FC
{
diff --git a/apps/web/src/studio/components/workflows/node-view/WorkflowFloatingMenu.tsx b/apps/web/src/studio/components/workflows/node-view/WorkflowFloatingMenu.tsx
index b0a3a319658..7fec9b1939d 100644
--- a/apps/web/src/studio/components/workflows/node-view/WorkflowFloatingMenu.tsx
+++ b/apps/web/src/studio/components/workflows/node-view/WorkflowFloatingMenu.tsx
@@ -110,8 +110,7 @@ function WorkflowFloatingMenuButton({ Icon, tooltipLabel, onClick }: IWorkflowFl
padding: '75 !important',
borderRadius: '100',
_hover: {
- // TODO: this doesn't work due to all the !important in novui... need to fix layer styles
- bg: 'legacy.B30 !important',
+ bg: 'select.option.surface.selected',
'& svg': {
color: 'typography.text.main !important',
},
diff --git a/apps/web/src/studio/components/workflows/step-editor/WorkflowStepEditorControlsPanel.tsx b/apps/web/src/studio/components/workflows/step-editor/WorkflowStepEditorControlsPanel.tsx
index 0e566313cfc..e39cfd360f2 100644
--- a/apps/web/src/studio/components/workflows/step-editor/WorkflowStepEditorControlsPanel.tsx
+++ b/apps/web/src/studio/components/workflows/step-editor/WorkflowStepEditorControlsPanel.tsx
@@ -8,6 +8,7 @@ import { css } from '@novu/novui/css';
import { Container, Flex } from '@novu/novui/jsx';
import { useDebouncedCallback } from '@novu/novui';
import { useTelemetry } from '../../../../hooks/useNovuAPI';
+import { getSuggestionVariables, subscriberVariables } from '../../../utils';
export type OnChangeType = 'step' | 'payload';
@@ -43,6 +44,16 @@ export const WorkflowStepEditorControlsPanel: FC {
+ const payloadObject =
+ workflow?.payload?.schema?.properties ||
+ workflow?.options?.payloadSchema?.properties ||
+ workflow?.payloadSchema?.properties ||
+ {};
+
+ return getSuggestionVariables(payloadObject, 'payload');
+ }, [workflow?.payload?.schema, workflow?.options?.payloadSchema, workflow?.payloadSchema]);
+
const haveControlProperties = useMemo(() => {
return Object.keys(step?.controls?.schema?.properties || step?.inputs?.schema?.properties || {}).length > 0;
}, [step?.controls?.schema, step?.inputs?.schema]);
@@ -87,6 +98,7 @@ export const WorkflowStepEditorControlsPanel: FC handleOnChange('step', data, id)}
schema={step?.controls?.schema || step?.inputs?.schema || {}}
formData={defaultControls || {}}
+ variables={[...(subscriberVariables || []), ...(payloadProperties || [])]}
/>
diff --git a/apps/web/src/studio/utils/index.ts b/apps/web/src/studio/utils/index.ts
index 161ba393c74..7cd5e5a56c1 100644
--- a/apps/web/src/studio/utils/index.ts
+++ b/apps/web/src/studio/utils/index.ts
@@ -1 +1,2 @@
export * from './routing';
+export * from './variables';
diff --git a/apps/web/src/studio/utils/variables.ts b/apps/web/src/studio/utils/variables.ts
new file mode 100644
index 00000000000..98044aba704
--- /dev/null
+++ b/apps/web/src/studio/utils/variables.ts
@@ -0,0 +1,14 @@
+import { SystemVariablesWithTypes } from '@novu/shared';
+
+export function getSuggestionVariables(schemaObject, namespace: string) {
+ return Object.keys(schemaObject).flatMap((name) => {
+ const schemaItem = schemaObject[name];
+ if (schemaItem?.type === 'object') {
+ return getSuggestionVariables(schemaItem.properties, `${namespace}.${name}`);
+ }
+
+ return `${namespace}.${name}`;
+ });
+}
+
+export const subscriberVariables = getSuggestionVariables(SystemVariablesWithTypes.subscriber, 'subscriber');
diff --git a/libs/novui/package.json b/libs/novui/package.json
index 72fcb8fdaf7..6fbd93777a1 100644
--- a/libs/novui/package.json
+++ b/libs/novui/package.json
@@ -51,8 +51,7 @@
"require": "./styled-system/jsx/index.js",
"import": "./styled-system/jsx/index.js"
},
- "./styles.css": "./styled-system/styles.css",
- "./components.css": "./node_modules/@mantine/core/styles.layer.css"
+ "./styles.css": "./src/index.css"
},
"scripts": {
"dev": "pnpm build && pnpm storybook",
@@ -130,13 +129,21 @@
}
},
"dependencies": {
- "@mantine/code-highlight": "^7.10.2",
- "@mantine/core": "^7.10.0",
- "@mantine/hooks": "^7.10.0",
+ "@mantine/code-highlight": "^7.11.2",
+ "@mantine/core": "^7.11.2",
+ "@mantine/hooks": "^7.11.2",
+ "@mantine/tiptap": "^7.11.2",
"@rjsf/core": "^5.17.1",
"@rjsf/utils": "^5.17.1",
"@rjsf/validator-ajv8": "^5.17.1",
"@tanstack/react-table": "^8.17.3",
+ "@tiptap/extension-document": "^2.5.0",
+ "@tiptap/extension-mention": "^2.5.0",
+ "@tiptap/extension-paragraph": "^2.5.0",
+ "@tiptap/extension-text": "^2.5.0",
+ "@tiptap/pm": "^3.0.0",
+ "@tiptap/react": "^3.0.0",
+ "@tiptap/suggestion": "^2.5.0",
"react-icons": "^5.0.1"
}
}
diff --git a/libs/novui/src/index.css b/libs/novui/src/index.css
index ab87315d934..e294e60949e 100644
--- a/libs/novui/src/index.css
+++ b/libs/novui/src/index.css
@@ -1,3 +1,5 @@
@layer reset, base, mantine, tokens, recipes, utilities;
@import '@mantine/core/styles.layer.css';
+@import '@mantine/tiptap/styles.layer.css';
+@import '../styled-system/styles.css';
diff --git a/libs/novui/src/json-schema-components/JsonSchemaForm.stories.tsx b/libs/novui/src/json-schema-components/JsonSchemaForm.stories.tsx
index e63873cb187..4504715dccd 100644
--- a/libs/novui/src/json-schema-components/JsonSchemaForm.stories.tsx
+++ b/libs/novui/src/json-schema-components/JsonSchemaForm.stories.tsx
@@ -27,7 +27,18 @@ const Template: StoryFn = ({ colorPalette, ...args }) =>
Save
-
+
);
};
diff --git a/libs/novui/src/json-schema-components/JsonSchemaForm.tsx b/libs/novui/src/json-schema-components/JsonSchemaForm.tsx
index 4cfa5d9fe1e..828a9fef0a1 100644
--- a/libs/novui/src/json-schema-components/JsonSchemaForm.tsx
+++ b/libs/novui/src/json-schema-components/JsonSchemaForm.tsx
@@ -8,15 +8,15 @@ import { CoreProps } from '../types';
import { ArrayFieldItemTemplate, ArrayFieldTemplate, ArrayFieldTitleTemplate } from './templates/ArrayFieldTemplate';
import { AddButton, MoveDownButton, MoveUpButton, RemoveButton } from './templates/IconButton';
import { ObjectFieldTemplate } from './templates/ObjectFieldTemplate';
-import { CheckboxWidget, InputWidget, SelectWidget, TextareaWidget } from './widgets';
+import { CheckboxWidget, SelectWidget, InputEditorWidget } from './widgets';
import { JSON_SCHEMA_FORM_ID_DELIMITER } from './utils';
const WIDGETS: RegistryWidgetsType = {
CheckboxWidget: CheckboxWidget,
SelectWidget: SelectWidget,
- TextWidget: TextareaWidget,
- URLWidget: InputWidget,
- EmailWidget: InputWidget,
+ TextWidget: InputEditorWidget,
+ URLWidget: InputEditorWidget,
+ EmailWidget: InputEditorWidget,
};
const UI_SCHEMA: UiSchema = {
@@ -31,13 +31,15 @@ const UI_SCHEMA: UiSchema = {
export type JsonSchemaFormProps = JsxStyleProps &
CoreProps &
- Pick, 'onChange' | 'onSubmit' | 'onBlur' | 'schema' | 'formData' | 'tagName'>;
+ Pick, 'onChange' | 'onSubmit' | 'onBlur' | 'schema' | 'formData' | 'tagName'> & {
+ variables?: string[];
+ };
/**
* Specialized form editor for data passed as JSON.
*/
export function JsonSchemaForm(props: JsonSchemaFormProps) {
- const [cssProps, { className, ...formProps }] = splitCssProps(props);
+ const [cssProps, { className, variables, ...formProps }] = splitCssProps(props);
return (