From 6bc1abc2154418c3d23dda8331e5aa39ed32e78b Mon Sep 17 00:00:00 2001 From: ainouzgali Date: Mon, 4 Sep 2023 12:38:57 +0300 Subject: [PATCH 1/2] feat: wip conditions component --- .../src/components/conditions/Conditions.tsx | 767 ++++++++++++++++++ .../icons/actions/ConditionPlus.tsx | 29 + .../design-system/icons/actions/Duplicate.tsx | 12 + .../icons/actions/PlusFilled.tsx | 10 +- .../design-system/icons/general/Condition.tsx | 4 +- apps/web/src/design-system/icons/index.ts | 2 + .../web/src/design-system/sidebar/Sidebar.tsx | 8 +- .../CreateProviderInstanceSidebar.tsx | 65 +- .../multi-provider/UpdateProviderSidebar.tsx | 31 + apps/web/src/pages/integrations/types.ts | 15 + .../src/pages/integrations/useProviders.ts | 16 + .../templates/editor/TemplateEditorPage.tsx | 10 +- .../templates/workflow/SideBar/Sidebar.tsx | 2 +- .../workflow/SideBar/StepSettings.tsx | 73 +- .../templates/workflow/WorkflowEditor.tsx | 1 + libs/shared/src/consts/filters/filters.ts | 1 + .../construct-integration.interface.ts | 7 + 17 files changed, 1016 insertions(+), 37 deletions(-) create mode 100644 apps/web/src/components/conditions/Conditions.tsx create mode 100644 apps/web/src/design-system/icons/actions/ConditionPlus.tsx create mode 100644 apps/web/src/design-system/icons/actions/Duplicate.tsx diff --git a/apps/web/src/components/conditions/Conditions.tsx b/apps/web/src/components/conditions/Conditions.tsx new file mode 100644 index 00000000000..f83df40a908 --- /dev/null +++ b/apps/web/src/components/conditions/Conditions.tsx @@ -0,0 +1,767 @@ +import { Button, colors, Dropdown, Input, Select, Sidebar, Text, Title, Tooltip } from '../../design-system'; +import { Grid, Group, ActionIcon, Center } from '@mantine/core'; +import { FILTER_TO_LABEL, FilterPartTypeEnum } from '@novu/shared'; +import { ConditionPlus, DotsHorizontal, Duplicate, Trash, Condition, ErrorIcon } from '../../design-system/icons'; +import { Controller, useFieldArray, useForm, useWatch } from 'react-hook-form'; +import styled from '@emotion/styled'; +import { useEffect } from 'react'; + +export function Conditions({ + isOpened, + conditions, + onClose, + setConditions, +}: { + isOpened: boolean; + onClose: () => void; + setConditions: (data: any) => void; + conditions: any; +}) { + const { + control, + setValue, + getValues, + handleSubmit: handleSubmit1, + watch, + } = useForm({ + defaultValues: { conditions }, + }); + const { fields, append, update, remove, insert } = useFieldArray({ + control, + name: `conditions.0.children`, + }); + + const watchConditions = watch(`conditions.0.children`); + + const FilterPartTypeList = [ + { value: FilterPartTypeEnum.TENANT, label: FILTER_TO_LABEL[FilterPartTypeEnum.TENANT] }, + { value: FilterPartTypeEnum.SUBSCRIBER, label: FILTER_TO_LABEL[FilterPartTypeEnum.SUBSCRIBER] }, + ]; + function handleOnChildOnChange(index: number) { + return (data) => { + const newField = Object.assign({}, fields[index], { on: data }); + update(index, newField); + }; + } + + useEffect(() => { + console.log(watchConditions); + }, [watchConditions]); + // console.log('conditions', conditions); + + function updateConditions(data) { + console.log('data 1', data); + setConditions(data); + } + + return ( + { + e.stopPropagation(); + e.preventDefault(); + console.log(e); + handleSubmit1(updateConditions)(e); + onClose(); + + // e.stopPropagation(); + }} + customHeader={ +
+ + + Condition for + +
+ } + customFooter={ + + + + + } + > + {fields.map((item, index) => { + const filterFieldOn = (fields[index] as any).on; + console.log('item', item); + + return ( +
+ + + {index > 0 ? ( + + { + return ( + + ); + }} + /> + + + { + return ( + + ); + }} + /> + + + { + return ( + +
+ +
+ + } + required + disabled={field.value === 'IS_DEFINED'} + error={fieldState.error?.message} + placeholder="Value" + data-test-id="filter-value-input" + /> + ); + }} + /> +
+ + + + + } + middlewares={{ flip: false, shift: false }} + position="bottom-end" + > + { + insert(index + 1, getValues(`conditions.0.children.${index}`)); + }} + icon={} + > + Duplicate + + { + remove(index); + }} + icon={} + > + Delete + + + +
+
+ ); + })} + + + + +
+ ); +} +export function Conditions1({ + isOpened, + conditions, + onClose, + setConditions, +}: { + isOpened: boolean; + onClose: () => void; + setConditions: (data: any) => void; + conditions: any; +}) { + const { + control, + setValue, + getValues, + handleSubmit: handleSubmit1, + watch, + } = useForm({ + defaultValues: { conditions }, + }); + const { fields, append, update, remove, insert } = useFieldArray({ + control, + name: `conditions.0.children`, + }); + + const watchConditions = watch(`conditions.0.children`); + + const FilterPartTypeList = [ + { value: FilterPartTypeEnum.TENANT, label: FILTER_TO_LABEL[FilterPartTypeEnum.TENANT] }, + { value: FilterPartTypeEnum.SUBSCRIBER, label: FILTER_TO_LABEL[FilterPartTypeEnum.SUBSCRIBER] }, + ]; + function handleOnChildOnChange(index: number) { + return (data) => { + const newField = Object.assign({}, fields[index], { on: data }); + update(index, newField); + }; + } + + useEffect(() => { + console.log(watchConditions); + }, [watchConditions]); + // console.log('conditions', conditions); + + function updateConditions(data) { + console.log('data 1', data); + setConditions(data); + } + + return ( + { + e.preventDefault(); + console.log(e); + handleSubmit1(updateConditions)(e); + onClose(); + + // e.stopPropagation(); + }} + customHeader={ +
+ + + Condition for + +
+ } + customFooter={ + + + + + } + > + {fields.map((item, index) => { + const filterFieldOn = (fields[index] as any).on; + console.log('item', item); + + return ( +
+ + + {index > 0 ? ( + + { + return ( + + ); + }} + /> + + + { + return ( + + ); + }} + /> + + + { + return ( + +
+ +
+ + } + required + disabled={field.value === 'IS_DEFINED'} + error={fieldState.error?.message} + placeholder="Value" + data-test-id="filter-value-input" + /> + ); + }} + /> +
+ + + + + } + middlewares={{ flip: false, shift: false }} + position="bottom-end" + > + { + insert(index + 1, getValues(`conditions.0.children.${index}`)); + }} + icon={} + > + Duplicate + + { + remove(index); + }} + icon={} + > + Delete + + + +
+
+ ); + })} + + + + +
+ ); +} +export function Conditions2({ + isOpened, + onClose, + control, + setValue, + getValues, +}: { + isOpened: boolean; + onClose: () => void; + control: any; + setValue: any; + getValues: any; +}) { + const { fields, append, update, remove, insert } = useFieldArray({ + control, + name: `conditions.0.children`, + }); + + const FilterPartTypeList = [ + { value: FilterPartTypeEnum.TENANT, label: FILTER_TO_LABEL[FilterPartTypeEnum.TENANT] }, + { value: FilterPartTypeEnum.SUBSCRIBER, label: FILTER_TO_LABEL[FilterPartTypeEnum.SUBSCRIBER] }, + ]; + console.log(28 / 4); + function handleOnChildOnChange(index: number) { + return (data) => { + const newField = Object.assign({}, fields[index], { on: data }); + update(index, newField); + }; + } + + return ( + + + + Condition for + + + } + customFooter={ + + + + + } + > + {fields.map((item, index) => { + const filterFieldOn = (fields[index] as any).on; + + return ( +
+ + + {index > 0 ? ( + + { + return ( + + ); + }} + /> + + + { + return ( + + ); + }} + /> + + + { + return ( + + ); + }} + /> + + + + + + } + middlewares={{ flip: false, shift: false }} + position="bottom-end" + > + { + insert(index + 1, getValues(`conditions.0.children.${index}`)); + }} + icon={} + > + Duplicate + + { + remove(index); + }} + icon={} + > + Delete + + + + +
+ ); + })} + + + + +
+ ); +} + +const ItemName = () => { + return
bla
; +}; + +const Wrapper = styled.div` + .mantine-Select-wrapper:not(:hover) { + .mantine-Select-input { + border-color: transparent; + color: ${colors.B60}; + } + .mantine-Input-rightSection.mantine-Select-rightSection { + svg { + display: none; + } + } + } +`; diff --git a/apps/web/src/design-system/icons/actions/ConditionPlus.tsx b/apps/web/src/design-system/icons/actions/ConditionPlus.tsx new file mode 100644 index 00000000000..1877a995c0b --- /dev/null +++ b/apps/web/src/design-system/icons/actions/ConditionPlus.tsx @@ -0,0 +1,29 @@ +import React from 'react'; + +export function ConditionPlus(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + + + + + + + + + ); +} diff --git a/apps/web/src/design-system/icons/actions/Duplicate.tsx b/apps/web/src/design-system/icons/actions/Duplicate.tsx new file mode 100644 index 00000000000..10eee70d2ca --- /dev/null +++ b/apps/web/src/design-system/icons/actions/Duplicate.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +/* eslint-disable */ +export function Duplicate(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + + + ); +} diff --git a/apps/web/src/design-system/icons/actions/PlusFilled.tsx b/apps/web/src/design-system/icons/actions/PlusFilled.tsx index 6087e41ca02..8c1eac0e7ea 100644 --- a/apps/web/src/design-system/icons/actions/PlusFilled.tsx +++ b/apps/web/src/design-system/icons/actions/PlusFilled.tsx @@ -7,14 +7,14 @@ export function PlusFilled(props: React.ComponentPropsWithoutRef<'svg'>) { - - + + diff --git a/apps/web/src/design-system/icons/general/Condition.tsx b/apps/web/src/design-system/icons/general/Condition.tsx index 73ec7b5f743..1593e16d602 100644 --- a/apps/web/src/design-system/icons/general/Condition.tsx +++ b/apps/web/src/design-system/icons/general/Condition.tsx @@ -1,5 +1,5 @@ import React from 'react'; -/* eslint-disable */ + export function Condition(props: React.ComponentPropsWithoutRef<'svg'>) { return ( @@ -19,7 +19,7 @@ export function Condition(props: React.ComponentPropsWithoutRef<'svg'>) { - + diff --git a/apps/web/src/design-system/icons/index.ts b/apps/web/src/design-system/icons/index.ts index dcc7189b1c6..a209a84f806 100644 --- a/apps/web/src/design-system/icons/index.ts +++ b/apps/web/src/design-system/icons/index.ts @@ -94,6 +94,8 @@ export { Edit } from './actions/Edit'; export { Upload } from './actions/Upload'; export { Invite } from './actions/Invite'; export { PlusFilled } from './actions/PlusFilled'; +export { ConditionPlus } from './actions/ConditionPlus'; +export { Duplicate } from './actions/Duplicate'; export { ArrowDown } from './arrows/ArrowDown'; export { DoubleArrowRight } from './arrows/DoubleArrowRight'; diff --git a/apps/web/src/design-system/sidebar/Sidebar.tsx b/apps/web/src/design-system/sidebar/Sidebar.tsx index 59508b2f91f..20f7f4485ad 100644 --- a/apps/web/src/design-system/sidebar/Sidebar.tsx +++ b/apps/web/src/design-system/sidebar/Sidebar.tsx @@ -1,5 +1,5 @@ import styled from '@emotion/styled'; -import { ActionIcon, createStyles, Drawer, Loader, MantineTheme, Stack } from '@mantine/core'; +import { ActionIcon, Box, createStyles, Drawer, Loader, MantineTheme, Stack } from '@mantine/core'; import { ReactNode } from 'react'; import { HEADER_HEIGHT } from '../../components/layout/constants'; @@ -46,10 +46,11 @@ const useDrawerStyles = createStyles((theme: MantineTheme) => { return { root: { position: 'absolute', - zIndex: 1, + // zIndex: 1, }, drawer: { position: 'fixed', + // zIndex: 9999, top: `${INTEGRATION_SETTING_TOP}px`, right: 0, bottom: 0, @@ -122,11 +123,12 @@ export const Sidebar = ({ closeOnEscape={false} withinPortal={false} trapFocus={false} + zIndex={999} data-expanded={isExpanded} >
- {isExpanded && ( + {isExpanded && onBack && ( diff --git a/apps/web/src/pages/integrations/components/multi-provider/CreateProviderInstanceSidebar.tsx b/apps/web/src/pages/integrations/components/multi-provider/CreateProviderInstanceSidebar.tsx index 39f08a02096..ebd17b528a1 100644 --- a/apps/web/src/pages/integrations/components/multi-provider/CreateProviderInstanceSidebar.tsx +++ b/apps/web/src/pages/integrations/components/multi-provider/CreateProviderInstanceSidebar.tsx @@ -1,12 +1,21 @@ import { ActionIcon, Group, Radio, Text } from '@mantine/core'; -import { useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Controller, useForm } from 'react-hook-form'; import styled from '@emotion/styled'; -import { ChannelTypeEnum, ICreateIntegrationBodyDto, InAppProviderIdEnum, providers } from '@novu/shared'; +import { + BuilderFieldType, + BuilderGroupValues, + ChannelTypeEnum, + FilterParts, + FilterPartTypeEnum, + ICreateIntegrationBodyDto, + InAppProviderIdEnum, + providers, +} from '@novu/shared'; import { Button, colors, NameInput, Sidebar } from '../../../../design-system'; -import { ArrowLeft } from '../../../../design-system/icons'; +import { ArrowLeft, ConditionPlus } from '../../../../design-system/icons'; import { inputStyles } from '../../../../design-system/config/inputs.styles'; import { useFetchEnvironments } from '../../../../hooks/useFetchEnvironments'; import { useSegment } from '../../../../components/providers/SegmentProvider'; @@ -19,10 +28,17 @@ import { CHANNEL_TYPE_TO_STRING } from '../../../../utils/channels'; import type { IntegrationEntity } from '../../types'; import { useProviders } from '../../useProviders'; import { When } from '../../../../components/utils/When'; +import { Conditions } from '../../../../components/conditions/Conditions'; interface ICreateProviderInstanceForm { name: string; environmentId: string; + conditions: { + isNegated?: boolean; + type?: BuilderFieldType; + value?: BuilderGroupValues; + children?: FilterParts[]; + }[]; } export function CreateProviderInstanceSidebar({ @@ -42,6 +58,7 @@ export function CreateProviderInstanceSidebar({ }) { const { environments, isLoading: areEnvironmentsLoading } = useFetchEnvironments(); const { isLoading: areIntegrationsLoading, providers: integrations } = useProviders(); + const [openConditions, setOpenConditions] = useState(false); const isLoading = areEnvironmentsLoading || areIntegrationsLoading; const queryClient = useQueryClient(); const segment = useSegment(); @@ -57,15 +74,17 @@ export function CreateProviderInstanceSidebar({ ICreateIntegrationBodyDto >(createIntegration); - const { handleSubmit, control, reset, watch } = useForm({ + const { handleSubmit, control, reset, watch, setValue, getValues } = useForm({ shouldUseNativeValidation: false, defaultValues: { name: '', environmentId: '', + conditions: [], }, }); const selectedEnvironmentId = watch('environmentId'); + const conditions = watch('conditions'); const showInAppErrorMessage = useMemo(() => { if (!provider || integrations.length === 0 || provider.id !== InAppProviderIdEnum.Novu) { @@ -86,7 +105,8 @@ export function CreateProviderInstanceSidebar({ } const { channel: selectedChannel } = provider; - const { environmentId } = data; + const { environmentId, conditions: cond } = data; + console.log('data', cond); const { _id: integrationId } = await createIntegrationApi({ providerId: provider.id, @@ -95,6 +115,7 @@ export function CreateProviderInstanceSidebar({ credentials: {}, active: provider.channel === ChannelTypeEnum.IN_APP ? true : false, check: false, + conditions: cond, _environmentId: environmentId, }); @@ -124,6 +145,21 @@ export function CreateProviderInstanceSidebar({ reset({ name: provider?.displayName ?? '', environmentId: environments.find((env) => env.name === 'Development')?._id || '', + conditions: [ + { + isNegated: false, + type: 'GROUP', + value: 'AND', + children: [ + { + on: FilterPartTypeEnum.TENANT, + field: 'identifier', + value: 'pawan', + operator: 'EQUAL', + }, + ], + }, + ], }); }, [environments, provider]); @@ -131,6 +167,21 @@ export function CreateProviderInstanceSidebar({ return null; } + console.log(conditions); + + if (openConditions) { + return ( + { + setValue('conditions', data.conditions); + }} + onClose={() => setOpenConditions(false)} + /> + ); + } + return ( + + You can only create one {provider.displayName} per environment. diff --git a/apps/web/src/pages/integrations/components/multi-provider/UpdateProviderSidebar.tsx b/apps/web/src/pages/integrations/components/multi-provider/UpdateProviderSidebar.tsx index 6580f2c836d..4b32a8089e5 100644 --- a/apps/web/src/pages/integrations/components/multi-provider/UpdateProviderSidebar.tsx +++ b/apps/web/src/pages/integrations/components/multi-provider/UpdateProviderSidebar.tsx @@ -5,9 +5,12 @@ import slugify from 'slugify'; import { Controller, FormProvider, useForm, useWatch } from 'react-hook-form'; import { useIntercom } from 'react-use-intercom'; import { + BuilderFieldType, + BuilderGroupValues, CHANNELS_WITH_PRIMARY, CredentialsKeyEnum, EmailProviderIdEnum, + FilterParts, IConfigCredentials, IConstructIntegrationDto, ICredentialsDto, @@ -36,12 +39,20 @@ import { NovuInAppSetupWarning } from '../NovuInAppSetupWarning'; import { NovuProviderSidebarContent } from './NovuProviderSidebarContent'; import { useSelectPrimaryIntegrationModal } from './useSelectPrimaryIntegrationModal'; import { ShareableUrl } from '../Modal/ConnectIntegrationForm'; +import { Conditions } from '../../../../components/conditions/Conditions'; +import { ConditionPlus } from '../../../../design-system/icons'; interface IProviderForm { name: string; credentials: ICredentialsDto; active: boolean; identifier: string; + conditions: { + isNegated?: boolean; + type?: BuilderFieldType; + value?: BuilderGroupValues; + children?: FilterParts[]; + }[]; } enum SidebarStateEnum { @@ -62,6 +73,7 @@ export function UpdateProviderSidebar({ const { isLoading: areEnvironmentsLoading } = useFetchEnvironments(); const [selectedProvider, setSelectedProvider] = useState(null); const [sidebarState, setSidebarState] = useState(SidebarStateEnum.NORMAL); + const [openConditions, setOpenConditions] = useState(false); const [framework, setFramework] = useState(null); const { providers, isLoading: areProvidersLoading } = useProviders(); const isNovuInAppProvider = selectedProvider?.providerId === InAppProviderIdEnum.Novu; @@ -79,6 +91,7 @@ export function UpdateProviderSidebar({ credentials: {}, active: false, identifier: '', + conditions: [], }, }); const { @@ -87,6 +100,7 @@ export function UpdateProviderSidebar({ reset, watch, setValue, + getValues, formState: { errors, isDirty, dirtyFields }, } = methods; @@ -138,6 +152,7 @@ export function UpdateProviderSidebar({ return prev; }, {} as any), + conditions: foundProvider.conditions, active: foundProvider.active, }); }, [integrationId, providers]); @@ -206,6 +221,19 @@ export function UpdateProviderSidebar({ name: `credentials.${CredentialsKeyEnum.Hmac}`, }); + if (openConditions) { + return ( + { + setValue('conditions', data.conditions); + }} + onClose={() => setOpenConditions(false)} + /> + ); + } + if ( SmsProviderIdEnum.Novu === selectedProvider?.providerId || EmailProviderIdEnum.Novu === selectedProvider?.providerId @@ -326,6 +354,9 @@ export function UpdateProviderSidebar({ + diff --git a/apps/web/src/pages/integrations/types.ts b/apps/web/src/pages/integrations/types.ts index 3439cc75579..8ee50d1fc59 100644 --- a/apps/web/src/pages/integrations/types.ts +++ b/apps/web/src/pages/integrations/types.ts @@ -1,5 +1,8 @@ import type { + BuilderFieldType, + BuilderGroupValues, ChannelTypeEnum, + FilterParts, IConfigCredentials, ICredentials, ILogoFileName, @@ -33,6 +36,12 @@ export interface IIntegratedProvider { comingSoon: boolean; active: boolean; connected: boolean; + conditions?: { + isNegated?: boolean; + type?: BuilderFieldType; + value?: BuilderGroupValues; + children?: FilterParts[]; + }[]; logoFileName: ILogoFileName; betaVersion: boolean; novu?: boolean; @@ -51,6 +60,12 @@ export interface IntegrationEntity { providerId: ProvidersIdEnum; channel: ChannelTypeEnum; credentials: ICredentials; + conditions?: { + isNegated?: boolean; + type?: BuilderFieldType; + value?: BuilderGroupValues; + children?: FilterParts[]; + }[]; active: boolean; deleted: boolean; order: number; diff --git a/apps/web/src/pages/integrations/useProviders.ts b/apps/web/src/pages/integrations/useProviders.ts index 923970872df..64ecbb4d9a4 100644 --- a/apps/web/src/pages/integrations/useProviders.ts +++ b/apps/web/src/pages/integrations/useProviders.ts @@ -2,6 +2,7 @@ import { useMemo } from 'react'; import * as cloneDeep from 'lodash.clonedeep'; import { ChannelTypeEnum, + FilterPartTypeEnum, IConfigCredentials, IProviderConfig, NOVU_SMS_EMAIL_PROVIDERS, @@ -116,6 +117,21 @@ function initializeProvidersByIntegration(integrations: IntegrationEntity[]): II name: integrationItem?.name, identifier: integrationItem?.identifier, primary: integrationItem?.primary ?? false, + conditions: integrationItem?.conditions ?? [ + { + isNegated: false, + type: 'GROUP', + value: 'AND', + children: [ + { + on: FilterPartTypeEnum.TENANT, + field: 'identifier', + value: 'pawan', + operator: 'EQUAL', + }, + ], + }, + ], }; }); } diff --git a/apps/web/src/pages/templates/editor/TemplateEditorPage.tsx b/apps/web/src/pages/templates/editor/TemplateEditorPage.tsx index 63555093811..4a62f010910 100644 --- a/apps/web/src/pages/templates/editor/TemplateEditorPage.tsx +++ b/apps/web/src/pages/templates/editor/TemplateEditorPage.tsx @@ -82,11 +82,11 @@ function BaseTemplateEditorPage() { - + {/**/} ); } diff --git a/apps/web/src/pages/templates/workflow/SideBar/Sidebar.tsx b/apps/web/src/pages/templates/workflow/SideBar/Sidebar.tsx index 8b4a57b6e31..d60a41667ca 100644 --- a/apps/web/src/pages/templates/workflow/SideBar/Sidebar.tsx +++ b/apps/web/src/pages/templates/workflow/SideBar/Sidebar.tsx @@ -40,5 +40,5 @@ const SideBarWrapper = styled.div<{ dark: boolean }>` background: transparent; height: 100%; right: 8px; - z-index: 9999; + z-index: 5; `; diff --git a/apps/web/src/pages/templates/workflow/SideBar/StepSettings.tsx b/apps/web/src/pages/templates/workflow/SideBar/StepSettings.tsx index aec4e688048..c27c95a7fb8 100644 --- a/apps/web/src/pages/templates/workflow/SideBar/StepSettings.tsx +++ b/apps/web/src/pages/templates/workflow/SideBar/StepSettings.tsx @@ -1,5 +1,5 @@ import { Group } from '@mantine/core'; -import { useFormContext } from 'react-hook-form'; +import { useFieldArray, useFormContext } from 'react-hook-form'; import { Button } from '../../../../design-system'; import type { IForm } from '../../components/formTypes'; @@ -7,7 +7,7 @@ import { StepActiveSwitch } from '../StepActiveSwitch'; import { useEnvController } from '../../../../hooks'; import { ShouldStopOnFailSwitch } from '../ShouldStopOnFailSwitch'; import { ReplyCallback, ReplyCallbackSwitch } from '../ReplyCallback'; -import { useParams } from 'react-router-dom'; +import { useParams, Outlet } from 'react-router-dom'; import { StepTypeEnum } from '@novu/shared'; import { When } from '../../../../components/utils/When'; import { FilterModal } from '../../filter/FilterModal'; @@ -15,18 +15,43 @@ import { useState } from 'react'; import { Filter } from '../../../../design-system/icons/actions/Filter'; import { FilterGradient } from '../../../../design-system/icons/gradient/FilterGradient'; import { FilterOutlined } from '../../../../design-system/icons/gradient/FilterOutlined'; +import { Conditions } from '../../../../components/conditions/Conditions'; export function StepSettings({ index }: { index: number }) { const { readonly } = useEnvController(); - const { control, watch, setValue } = useFormContext(); + const { control, watch, setValue, getValues } = useFormContext(); const [filterOpen, setFilterOpen] = useState(false); const { channel } = useParams<{ channel: StepTypeEnum; }>(); const [filterHover, setFilterHover] = useState(false); - + const { fields, replace, update, remove } = useFieldArray({ + control, + name: `steps.${index}.filters.0.children`, + }); const filters = watch(`steps.${index}.filters.0.children`); + console.log('fields', fields); + + /* + * if (filterOpen) { + * return ( + * { + * setFilterOpen(false); + * }} + * setConditions={(data) => { + * console.log(data); + * replace(data.conditions[0].children); + * setValue(`steps.${index}.filters.0.children`, fields); + * }} + * conditions={getValues(`steps.${index}.filters`)} + * /> + * ); + * } + */ + return ( <> @@ -79,18 +104,34 @@ export function StepSettings({ index }: { index: number }) { - { - setFilterOpen(false); - }} - confirm={() => { - setFilterOpen(false); - }} - control={control} - stepIndex={index} - setValue={setValue} - /> + {filterOpen && ( + <> + { + setFilterOpen(false); + }} + setConditions={(data) => { + console.log(data); + replace(data.conditions[0].children); + setValue(`steps.${index}.filters.0.children`, fields); + }} + conditions={getValues(`steps.${index}.filters`)} + /> + + )} + {/* {*/} + {/* setFilterOpen(false);*/} + {/* }}*/} + {/* confirm={() => {*/} + {/* setFilterOpen(false);*/} + {/* }}*/} + {/* control={control}*/} + {/* stepIndex={index}*/} + {/* setValue={setValue}*/} + {/*/>*/} ); } diff --git a/apps/web/src/pages/templates/workflow/WorkflowEditor.tsx b/apps/web/src/pages/templates/workflow/WorkflowEditor.tsx index bc055ab8fc4..1b5472f720c 100644 --- a/apps/web/src/pages/templates/workflow/WorkflowEditor.tsx +++ b/apps/web/src/pages/templates/workflow/WorkflowEditor.tsx @@ -61,6 +61,7 @@ const WorkflowEditor = () => { event.preventDefault(); if (node.type === 'channelNode') { + console.log('node.data.uuid', node.data.uuid); navigate(basePath + `/${node.data.channelType}/${node.data.uuid}`); } if (node.type === 'triggerNode') { diff --git a/libs/shared/src/consts/filters/filters.ts b/libs/shared/src/consts/filters/filters.ts index 9a7eac4db05..1bc00920ad3 100644 --- a/libs/shared/src/consts/filters/filters.ts +++ b/libs/shared/src/consts/filters/filters.ts @@ -2,6 +2,7 @@ import { FilterPartTypeEnum } from '../../types'; export const FILTER_TO_LABEL = { [FilterPartTypeEnum.PAYLOAD]: 'Payload', + [FilterPartTypeEnum.TENANT]: 'Tenant', [FilterPartTypeEnum.SUBSCRIBER]: 'Subscriber', [FilterPartTypeEnum.WEBHOOK]: 'Webhook', [FilterPartTypeEnum.IS_ONLINE]: 'Online right now', diff --git a/libs/shared/src/dto/integration/construct-integration.interface.ts b/libs/shared/src/dto/integration/construct-integration.interface.ts index 5754dd8dc37..8b3cc2c02ff 100644 --- a/libs/shared/src/dto/integration/construct-integration.interface.ts +++ b/libs/shared/src/dto/integration/construct-integration.interface.ts @@ -1,5 +1,6 @@ import { ICredentials } from '../../entities/integration'; import type { EnvironmentId } from '../../types'; +import { BuilderFieldType, BuilderGroupValues, FilterParts } from '../../types'; export type ICredentialsDto = ICredentials; @@ -10,4 +11,10 @@ export interface IConstructIntegrationDto { credentials?: ICredentialsDto; active?: boolean; check?: boolean; + conditions?: { + isNegated?: boolean; + type?: BuilderFieldType; + value?: BuilderGroupValues; + children?: FilterParts[]; + }[]; } From 7d8d0987e7110b4fd2df6cd06e18dd64d562822d Mon Sep 17 00:00:00 2001 From: ainouzgali Date: Mon, 4 Sep 2023 18:37:00 +0300 Subject: [PATCH 2/2] feat(wip): conditions component --- .../src/components/conditions/Conditions.tsx | 651 +++--------------- .../web/src/design-system/sidebar/Sidebar.tsx | 8 +- .../integrations/components/ConditionCell.tsx | 6 +- .../CreateProviderInstanceSidebar.tsx | 47 +- .../multi-provider/UpdateProviderSidebar.tsx | 15 +- apps/web/src/pages/integrations/types.ts | 23 +- .../src/pages/integrations/useProviders.ts | 17 +- apps/web/src/pages/integrations/utils.ts | 1 + .../templates/editor/TemplateEditorPage.tsx | 10 +- .../templates/workflow/SideBar/Sidebar.tsx | 2 +- .../workflow/SideBar/StepSettings.tsx | 81 +-- .../templates/workflow/WorkflowEditor.tsx | 1 - 12 files changed, 159 insertions(+), 703 deletions(-) diff --git a/apps/web/src/components/conditions/Conditions.tsx b/apps/web/src/components/conditions/Conditions.tsx index f83df40a908..fb9e52c7a7c 100644 --- a/apps/web/src/components/conditions/Conditions.tsx +++ b/apps/web/src/components/conditions/Conditions.tsx @@ -1,42 +1,47 @@ -import { Button, colors, Dropdown, Input, Select, Sidebar, Text, Title, Tooltip } from '../../design-system'; import { Grid, Group, ActionIcon, Center } from '@mantine/core'; +import styled from '@emotion/styled'; +import { Controller, useFieldArray, useForm } from 'react-hook-form'; + import { FILTER_TO_LABEL, FilterPartTypeEnum } from '@novu/shared'; + +import { Button, colors, Dropdown, Input, Select, Sidebar, Text, Title, Tooltip } from '../../design-system'; import { ConditionPlus, DotsHorizontal, Duplicate, Trash, Condition, ErrorIcon } from '../../design-system/icons'; -import { Controller, useFieldArray, useForm, useWatch } from 'react-hook-form'; -import styled from '@emotion/styled'; -import { useEffect } from 'react'; +import { When } from '../utils/When'; +import { IConditions } from '../../pages/integrations/types'; export function Conditions({ isOpened, conditions, onClose, setConditions, + name, }: { isOpened: boolean; onClose: () => void; - setConditions: (data: any) => void; - conditions: any; + setConditions: (data: IConditions[]) => void; + conditions?: IConditions[]; + name: string; }) { const { control, setValue, getValues, - handleSubmit: handleSubmit1, - watch, + trigger, + formState: { errors, isValid }, } = useForm({ defaultValues: { conditions }, + shouldUseNativeValidation: false, + mode: 'onChange', + reValidateMode: 'onChange', }); + const { fields, append, update, remove, insert } = useFieldArray({ control, name: `conditions.0.children`, }); - const watchConditions = watch(`conditions.0.children`); + const FilterPartTypeList = [{ value: FilterPartTypeEnum.TENANT, label: FILTER_TO_LABEL[FilterPartTypeEnum.TENANT] }]; - const FilterPartTypeList = [ - { value: FilterPartTypeEnum.TENANT, label: FILTER_TO_LABEL[FilterPartTypeEnum.TENANT] }, - { value: FilterPartTypeEnum.SUBSCRIBER, label: FILTER_TO_LABEL[FilterPartTypeEnum.SUBSCRIBER] }, - ]; function handleOnChildOnChange(index: number) { return (data) => { const newField = Object.assign({}, fields[index], { on: data }); @@ -44,14 +49,9 @@ export function Conditions({ }; } - useEffect(() => { - console.log(watchConditions); - }, [watchConditions]); - // console.log('conditions', conditions); - function updateConditions(data) { - console.log('data 1', data); - setConditions(data); + setConditions(data.conditions); + onClose(); } return ( @@ -59,22 +59,11 @@ export function Conditions({ isOpened={isOpened} onClose={onClose} isExpanded - // onSubmit={handleSubmit(updateConditions)} - - onSubmit={(e) => { - e.stopPropagation(); - e.preventDefault(); - console.log(e); - handleSubmit1(updateConditions)(e); - onClose(); - - // e.stopPropagation(); - }} customHeader={
- Condition for + Condition for {name} provider instance
} @@ -83,276 +72,31 @@ export function Conditions({ - - - } - > - {fields.map((item, index) => { - const filterFieldOn = (fields[index] as any).on; - console.log('item', item); - - return ( -
- - - {index > 0 ? ( - - { - return ( - - ); + + 0} + label={!isValid ? 'Some conditions are missing values' : 'Add at least one condition'} + > +
+
- ); - })} - - - - - - ); -} -export function Conditions1({ - isOpened, - conditions, - onClose, - setConditions, -}: { - isOpened: boolean; - onClose: () => void; - setConditions: (data: any) => void; - conditions: any; -}) { - const { - control, - setValue, - getValues, - handleSubmit: handleSubmit1, - watch, - } = useForm({ - defaultValues: { conditions }, - }); - const { fields, append, update, remove, insert } = useFieldArray({ - control, - name: `conditions.0.children`, - }); - - const watchConditions = watch(`conditions.0.children`); - - const FilterPartTypeList = [ - { value: FilterPartTypeEnum.TENANT, label: FILTER_TO_LABEL[FilterPartTypeEnum.TENANT] }, - { value: FilterPartTypeEnum.SUBSCRIBER, label: FILTER_TO_LABEL[FilterPartTypeEnum.SUBSCRIBER] }, - ]; - function handleOnChildOnChange(index: number) { - return (data) => { - const newField = Object.assign({}, fields[index], { on: data }); - update(index, newField); - }; - } - - useEffect(() => { - console.log(watchConditions); - }, [watchConditions]); - // console.log('conditions', conditions); - - function updateConditions(data) { - console.log('data 1', data); - setConditions(data); - } - - return ( - { - e.preventDefault(); - console.log(e); - handleSubmit1(updateConditions)(e); - onClose(); - - // e.stopPropagation(); - }} - customHeader={ -
- - - Condition for - -
- } - customFooter={ - - - + Apply conditions + +
+ + } > {fields.map((item, index) => { - const filterFieldOn = (fields[index] as any).on; - console.log('item', item); - return (
@@ -388,7 +132,7 @@ export function Conditions1({ { return ( - ); - }} - /> - - - { return ( -
- -
- - } - required - disabled={field.value === 'IS_DEFINED'} - error={fieldState.error?.message} - placeholder="Value" - data-test-id="filter-value-input" - /> - ); - }} - /> -
- - - - - } - middlewares={{ flip: false, shift: false }} - position="bottom-end" - > - { - insert(index + 1, getValues(`conditions.0.children.${index}`)); - }} - icon={} - > - Duplicate - - { - remove(index); - }} - icon={} - > - Delete - - - -
-
- ); - })} - - - - - - ); -} -export function Conditions2({ - isOpened, - onClose, - control, - setValue, - getValues, -}: { - isOpened: boolean; - onClose: () => void; - control: any; - setValue: any; - getValues: any; -}) { - const { fields, append, update, remove, insert } = useFieldArray({ - control, - name: `conditions.0.children`, - }); - - const FilterPartTypeList = [ - { value: FilterPartTypeEnum.TENANT, label: FILTER_TO_LABEL[FilterPartTypeEnum.TENANT] }, - { value: FilterPartTypeEnum.SUBSCRIBER, label: FILTER_TO_LABEL[FilterPartTypeEnum.SUBSCRIBER] }, - ]; - console.log(28 / 4); - function handleOnChildOnChange(index: number) { - return (data) => { - const newField = Object.assign({}, fields[index], { on: data }); - update(index, newField); - }; - } - - return ( - - - - Condition for - - - } - customFooter={ - - - - - } - > - {fields.map((item, index) => { - const filterFieldOn = (fields[index] as any).on; - - return ( -
- - - {index > 0 ? ( - - { - return ( - - ); - }} - /> - - - { - return ( - ); }} @@ -678,22 +196,38 @@ export function Conditions2({ /> - { - return ( - - ); - }} - /> + {getValues(`conditions.0.children.${index}.operator`) !== 'IS_DEFINED' && ( + { + return ( + + + + + + + + + + } + required + disabled={getValues(`conditions.0.children.${index}.operator`) === 'IS_DEFINED'} + error={!!fieldState.error} + placeholder="Value" + data-test-id="filter-value-input" + /> + ); + }} + /> + )} { append({ operator: 'EQUAL', - on: 'tenant', + on: FilterPartTypeEnum.TENANT, + field: 'identifier', + value: '', }); }} icon={} @@ -748,10 +284,6 @@ export function Conditions2({ ); } -const ItemName = () => { - return
bla
; -}; - const Wrapper = styled.div` .mantine-Select-wrapper:not(:hover) { .mantine-Select-input { @@ -765,3 +297,24 @@ const Wrapper = styled.div` } } `; + +const TooltipContainer = styled.div` + & .mantine-Tooltip-tooltip { + color: ${colors.error}; + padding: 16px; + font-size: 14px; + font-weight: 400; + border-radius: 8px; + background: ${({ theme }) => + `linear-gradient(0deg, rgba(229, 69, 69, 0.2) 0%, rgba(229, 69, 69, 0.2) 100%), ${ + theme.colorScheme === 'dark' ? '#23232b' : colors.white + } !important`}; + } + + & .mantine-Tooltip-arrow { + background: ${({ theme }) => + `linear-gradient(0deg, rgba(229, 69, 69, 0.2) 0%, rgba(229, 69, 69, 0.2) 100%), ${ + theme.colorScheme === 'dark' ? '#23232b' : colors.white + } !important`}; + } +`; diff --git a/apps/web/src/design-system/sidebar/Sidebar.tsx b/apps/web/src/design-system/sidebar/Sidebar.tsx index 20f7f4485ad..274fc147e2c 100644 --- a/apps/web/src/design-system/sidebar/Sidebar.tsx +++ b/apps/web/src/design-system/sidebar/Sidebar.tsx @@ -1,5 +1,5 @@ import styled from '@emotion/styled'; -import { ActionIcon, Box, createStyles, Drawer, Loader, MantineTheme, Stack } from '@mantine/core'; +import { ActionIcon, createStyles, Drawer, Loader, MantineTheme, Stack } from '@mantine/core'; import { ReactNode } from 'react'; import { HEADER_HEIGHT } from '../../components/layout/constants'; @@ -46,11 +46,10 @@ const useDrawerStyles = createStyles((theme: MantineTheme) => { return { root: { position: 'absolute', - // zIndex: 1, + zIndex: 1, }, drawer: { position: 'fixed', - // zIndex: 9999, top: `${INTEGRATION_SETTING_TOP}px`, right: 0, bottom: 0, @@ -123,10 +122,9 @@ export const Sidebar = ({ closeOnEscape={false} withinPortal={false} trapFocus={false} - zIndex={999} data-expanded={isExpanded} > -
+ {isExpanded && onBack && ( diff --git a/apps/web/src/pages/integrations/components/ConditionCell.tsx b/apps/web/src/pages/integrations/components/ConditionCell.tsx index 3e07e6e308e..70c50525366 100644 --- a/apps/web/src/pages/integrations/components/ConditionCell.tsx +++ b/apps/web/src/pages/integrations/components/ConditionCell.tsx @@ -6,7 +6,7 @@ import type { ITableIntegration } from '../types'; const ConditionCellBase = ({ row: { original } }: IExtendedCellProps) => { const { colorScheme } = useMantineColorScheme(); - if (!original.conditions) { + if (!original.conditions || original.conditions.length < 1) { return (
-
{original.conditions.length}
+
+ {original.conditions?.[0]?.children?.length} +
); }; diff --git a/apps/web/src/pages/integrations/components/multi-provider/CreateProviderInstanceSidebar.tsx b/apps/web/src/pages/integrations/components/multi-provider/CreateProviderInstanceSidebar.tsx index ebd17b528a1..f6d667a753d 100644 --- a/apps/web/src/pages/integrations/components/multi-provider/CreateProviderInstanceSidebar.tsx +++ b/apps/web/src/pages/integrations/components/multi-provider/CreateProviderInstanceSidebar.tsx @@ -3,16 +3,7 @@ import { useEffect, useMemo, useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { Controller, useForm } from 'react-hook-form'; import styled from '@emotion/styled'; -import { - BuilderFieldType, - BuilderGroupValues, - ChannelTypeEnum, - FilterParts, - FilterPartTypeEnum, - ICreateIntegrationBodyDto, - InAppProviderIdEnum, - providers, -} from '@novu/shared'; +import { ChannelTypeEnum, ICreateIntegrationBodyDto, InAppProviderIdEnum, providers } from '@novu/shared'; import { Button, colors, NameInput, Sidebar } from '../../../../design-system'; import { ArrowLeft, ConditionPlus } from '../../../../design-system/icons'; @@ -25,7 +16,7 @@ import { errorMessage, successMessage } from '../../../../utils/notifications'; import { QueryKeys } from '../../../../api/query.keys'; import { ProviderImage } from './SelectProviderSidebar'; import { CHANNEL_TYPE_TO_STRING } from '../../../../utils/channels'; -import type { IntegrationEntity } from '../../types'; +import type { IConditions, IntegrationEntity } from '../../types'; import { useProviders } from '../../useProviders'; import { When } from '../../../../components/utils/When'; import { Conditions } from '../../../../components/conditions/Conditions'; @@ -33,12 +24,7 @@ import { Conditions } from '../../../../components/conditions/Conditions'; interface ICreateProviderInstanceForm { name: string; environmentId: string; - conditions: { - isNegated?: boolean; - type?: BuilderFieldType; - value?: BuilderGroupValues; - children?: FilterParts[]; - }[]; + conditions: IConditions[]; } export function CreateProviderInstanceSidebar({ @@ -84,7 +70,6 @@ export function CreateProviderInstanceSidebar({ }); const selectedEnvironmentId = watch('environmentId'); - const conditions = watch('conditions'); const showInAppErrorMessage = useMemo(() => { if (!provider || integrations.length === 0 || provider.id !== InAppProviderIdEnum.Novu) { @@ -105,8 +90,7 @@ export function CreateProviderInstanceSidebar({ } const { channel: selectedChannel } = provider; - const { environmentId, conditions: cond } = data; - console.log('data', cond); + const { environmentId, conditions } = data; const { _id: integrationId } = await createIntegrationApi({ providerId: provider.id, @@ -115,7 +99,7 @@ export function CreateProviderInstanceSidebar({ credentials: {}, active: provider.channel === ChannelTypeEnum.IN_APP ? true : false, check: false, - conditions: cond, + conditions, _environmentId: environmentId, }); @@ -145,21 +129,7 @@ export function CreateProviderInstanceSidebar({ reset({ name: provider?.displayName ?? '', environmentId: environments.find((env) => env.name === 'Development')?._id || '', - conditions: [ - { - isNegated: false, - type: 'GROUP', - value: 'AND', - children: [ - { - on: FilterPartTypeEnum.TENANT, - field: 'identifier', - value: 'pawan', - operator: 'EQUAL', - }, - ], - }, - ], + conditions: [], }); }, [environments, provider]); @@ -167,15 +137,14 @@ export function CreateProviderInstanceSidebar({ return null; } - console.log(conditions); - if (openConditions) { return ( { - setValue('conditions', data.conditions); + setValue('conditions', data, { shouldDirty: true }); }} onClose={() => setOpenConditions(false)} /> diff --git a/apps/web/src/pages/integrations/components/multi-provider/UpdateProviderSidebar.tsx b/apps/web/src/pages/integrations/components/multi-provider/UpdateProviderSidebar.tsx index 4b32a8089e5..cbe036ca79e 100644 --- a/apps/web/src/pages/integrations/components/multi-provider/UpdateProviderSidebar.tsx +++ b/apps/web/src/pages/integrations/components/multi-provider/UpdateProviderSidebar.tsx @@ -5,12 +5,9 @@ import slugify from 'slugify'; import { Controller, FormProvider, useForm, useWatch } from 'react-hook-form'; import { useIntercom } from 'react-use-intercom'; import { - BuilderFieldType, - BuilderGroupValues, CHANNELS_WITH_PRIMARY, CredentialsKeyEnum, EmailProviderIdEnum, - FilterParts, IConfigCredentials, IConstructIntegrationDto, ICredentialsDto, @@ -21,7 +18,7 @@ import { import { Button, colors, Sidebar, Text } from '../../../../design-system'; import { useProviders } from '../../useProviders'; -import type { IIntegratedProvider } from '../../types'; +import type { IConditions, IIntegratedProvider } from '../../types'; import { IntegrationInput } from '../IntegrationInput'; import { useFetchEnvironments } from '../../../../hooks/useFetchEnvironments'; import { useUpdateIntegration } from '../../../../api/hooks/useUpdateIntegration'; @@ -47,12 +44,7 @@ interface IProviderForm { credentials: ICredentialsDto; active: boolean; identifier: string; - conditions: { - isNegated?: boolean; - type?: BuilderFieldType; - value?: BuilderGroupValues; - children?: FilterParts[]; - }[]; + conditions: IConditions[]; } enum SidebarStateEnum { @@ -225,9 +217,10 @@ export function UpdateProviderSidebar({ return ( { - setValue('conditions', data.conditions); + setValue('conditions', data, { shouldDirty: true }); }} onClose={() => setOpenConditions(false)} /> diff --git a/apps/web/src/pages/integrations/types.ts b/apps/web/src/pages/integrations/types.ts index 8ee50d1fc59..a4c11479f00 100644 --- a/apps/web/src/pages/integrations/types.ts +++ b/apps/web/src/pages/integrations/types.ts @@ -23,7 +23,7 @@ export interface ITableIntegration { environment: string; active: boolean; logoFileName: IProviderConfig['logoFileName']; - conditions?: any[]; + conditions?: IConditions[]; } export interface IIntegratedProvider { @@ -36,12 +36,7 @@ export interface IIntegratedProvider { comingSoon: boolean; active: boolean; connected: boolean; - conditions?: { - isNegated?: boolean; - type?: BuilderFieldType; - value?: BuilderGroupValues; - children?: FilterParts[]; - }[]; + conditions?: IConditions[]; logoFileName: ILogoFileName; betaVersion: boolean; novu?: boolean; @@ -60,12 +55,7 @@ export interface IntegrationEntity { providerId: ProvidersIdEnum; channel: ChannelTypeEnum; credentials: ICredentials; - conditions?: { - isNegated?: boolean; - type?: BuilderFieldType; - value?: BuilderGroupValues; - children?: FilterParts[]; - }[]; + conditions?: IConditions[]; active: boolean; deleted: boolean; order: number; @@ -73,3 +63,10 @@ export interface IntegrationEntity { deletedAt: string; deletedBy: string; } + +export interface IConditions { + isNegated?: boolean; + type?: BuilderFieldType; + value?: BuilderGroupValues; + children?: FilterParts[]; +} diff --git a/apps/web/src/pages/integrations/useProviders.ts b/apps/web/src/pages/integrations/useProviders.ts index 64ecbb4d9a4..d4b6e2faff6 100644 --- a/apps/web/src/pages/integrations/useProviders.ts +++ b/apps/web/src/pages/integrations/useProviders.ts @@ -2,7 +2,6 @@ import { useMemo } from 'react'; import * as cloneDeep from 'lodash.clonedeep'; import { ChannelTypeEnum, - FilterPartTypeEnum, IConfigCredentials, IProviderConfig, NOVU_SMS_EMAIL_PROVIDERS, @@ -117,21 +116,7 @@ function initializeProvidersByIntegration(integrations: IntegrationEntity[]): II name: integrationItem?.name, identifier: integrationItem?.identifier, primary: integrationItem?.primary ?? false, - conditions: integrationItem?.conditions ?? [ - { - isNegated: false, - type: 'GROUP', - value: 'AND', - children: [ - { - on: FilterPartTypeEnum.TENANT, - field: 'identifier', - value: 'pawan', - operator: 'EQUAL', - }, - ], - }, - ], + conditions: integrationItem?.conditions ?? [], }; }); } diff --git a/apps/web/src/pages/integrations/utils.ts b/apps/web/src/pages/integrations/utils.ts index d78a54b92ce..1104e3ac571 100644 --- a/apps/web/src/pages/integrations/utils.ts +++ b/apps/web/src/pages/integrations/utils.ts @@ -29,5 +29,6 @@ export const mapToTableIntegration = ( active: integration.active, logoFileName, providerId: integration.providerId, + conditions: integration.conditions, }; }; diff --git a/apps/web/src/pages/templates/editor/TemplateEditorPage.tsx b/apps/web/src/pages/templates/editor/TemplateEditorPage.tsx index 4a62f010910..63555093811 100644 --- a/apps/web/src/pages/templates/editor/TemplateEditorPage.tsx +++ b/apps/web/src/pages/templates/editor/TemplateEditorPage.tsx @@ -82,11 +82,11 @@ function BaseTemplateEditorPage() { - {/**/} + ); } diff --git a/apps/web/src/pages/templates/workflow/SideBar/Sidebar.tsx b/apps/web/src/pages/templates/workflow/SideBar/Sidebar.tsx index d60a41667ca..8b4a57b6e31 100644 --- a/apps/web/src/pages/templates/workflow/SideBar/Sidebar.tsx +++ b/apps/web/src/pages/templates/workflow/SideBar/Sidebar.tsx @@ -40,5 +40,5 @@ const SideBarWrapper = styled.div<{ dark: boolean }>` background: transparent; height: 100%; right: 8px; - z-index: 5; + z-index: 9999; `; diff --git a/apps/web/src/pages/templates/workflow/SideBar/StepSettings.tsx b/apps/web/src/pages/templates/workflow/SideBar/StepSettings.tsx index c27c95a7fb8..73953261279 100644 --- a/apps/web/src/pages/templates/workflow/SideBar/StepSettings.tsx +++ b/apps/web/src/pages/templates/workflow/SideBar/StepSettings.tsx @@ -1,5 +1,9 @@ import { Group } from '@mantine/core'; -import { useFieldArray, useFormContext } from 'react-hook-form'; +import { useState } from 'react'; +import { useFormContext } from 'react-hook-form'; +import { useParams } from 'react-router-dom'; + +import { StepTypeEnum } from '@novu/shared'; import { Button } from '../../../../design-system'; import type { IForm } from '../../components/formTypes'; @@ -7,50 +11,21 @@ import { StepActiveSwitch } from '../StepActiveSwitch'; import { useEnvController } from '../../../../hooks'; import { ShouldStopOnFailSwitch } from '../ShouldStopOnFailSwitch'; import { ReplyCallback, ReplyCallbackSwitch } from '../ReplyCallback'; -import { useParams, Outlet } from 'react-router-dom'; -import { StepTypeEnum } from '@novu/shared'; import { When } from '../../../../components/utils/When'; import { FilterModal } from '../../filter/FilterModal'; -import { useState } from 'react'; -import { Filter } from '../../../../design-system/icons/actions/Filter'; -import { FilterGradient } from '../../../../design-system/icons/gradient/FilterGradient'; +import { FilterGradient, Filter } from '../../../../design-system/icons'; import { FilterOutlined } from '../../../../design-system/icons/gradient/FilterOutlined'; -import { Conditions } from '../../../../components/conditions/Conditions'; export function StepSettings({ index }: { index: number }) { const { readonly } = useEnvController(); - const { control, watch, setValue, getValues } = useFormContext(); + const { control, watch, setValue } = useFormContext(); const [filterOpen, setFilterOpen] = useState(false); const { channel } = useParams<{ channel: StepTypeEnum; }>(); const [filterHover, setFilterHover] = useState(false); - const { fields, replace, update, remove } = useFieldArray({ - control, - name: `steps.${index}.filters.0.children`, - }); - const filters = watch(`steps.${index}.filters.0.children`); - console.log('fields', fields); - - /* - * if (filterOpen) { - * return ( - * { - * setFilterOpen(false); - * }} - * setConditions={(data) => { - * console.log(data); - * replace(data.conditions[0].children); - * setValue(`steps.${index}.filters.0.children`, fields); - * }} - * conditions={getValues(`steps.${index}.filters`)} - * /> - * ); - * } - */ + const filters = watch(`steps.${index}.filters.0.children`); return ( <> @@ -104,34 +79,18 @@ export function StepSettings({ index }: { index: number }) { - {filterOpen && ( - <> - { - setFilterOpen(false); - }} - setConditions={(data) => { - console.log(data); - replace(data.conditions[0].children); - setValue(`steps.${index}.filters.0.children`, fields); - }} - conditions={getValues(`steps.${index}.filters`)} - /> - - )} - {/* {*/} - {/* setFilterOpen(false);*/} - {/* }}*/} - {/* confirm={() => {*/} - {/* setFilterOpen(false);*/} - {/* }}*/} - {/* control={control}*/} - {/* stepIndex={index}*/} - {/* setValue={setValue}*/} - {/*/>*/} + { + setFilterOpen(false); + }} + confirm={() => { + setFilterOpen(false); + }} + control={control} + stepIndex={index} + setValue={setValue} + /> ); } diff --git a/apps/web/src/pages/templates/workflow/WorkflowEditor.tsx b/apps/web/src/pages/templates/workflow/WorkflowEditor.tsx index 1b5472f720c..bc055ab8fc4 100644 --- a/apps/web/src/pages/templates/workflow/WorkflowEditor.tsx +++ b/apps/web/src/pages/templates/workflow/WorkflowEditor.tsx @@ -61,7 +61,6 @@ const WorkflowEditor = () => { event.preventDefault(); if (node.type === 'channelNode') { - console.log('node.data.uuid', node.data.uuid); navigate(basePath + `/${node.data.channelType}/${node.data.uuid}`); } if (node.type === 'triggerNode') {