-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nv 1458 web abstract variable manager to not #2529
Nv 1458 web abstract variable manager to not #2529
Conversation
…bstract-variable-manager-to-not # Conflicts: # apps/web/src/pages/brand/tabs/LayoutEditor.tsx
…bstract-variable-manager-to-not # Conflicts: # apps/web/src/pages/brand/tabs/LayoutEditor.tsx
…l-content-in-Trigger' into nv-1458-web-abstract-variable-manager-to-not # Conflicts: # apps/web/src/pages/brand/tabs/LayoutEditor.tsx
NV-1458 Web - abstract variable manager to not apply only to template steps.
Currently, our variable manager is built to watch only the variables inside the template editor form. As it is now needed in layouts - different context and separate form - we need to abstract it so it we would be able to reuse our var manager. |
@@ -49,12 +38,25 @@ export class CompileEmailTemplateUsecase { | |||
useNovuDefault = true; | |||
} | |||
} | |||
const layoutVariables = layout?.variables || []; | |||
const defaultPayload = verifyPayloadService.verifyPayload(layoutVariables, command.payload); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So defaultValue defined for the layout variables will also apply when sending email/preview/test
|
apps/api/src/app/layouts/use-cases/create-layout/create-layout.use-case.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work. Some considerations. Do you plan to do Cypress tests for this piece?
private async loadTemplateContent(name: string) { | ||
return new Promise<string>((resolve, reject) => { | ||
let path = '/../../compile-template'; | ||
if (!process.env.E2E_RUNNER) { | ||
path = '/src/app/content-templates/usecases/compile-template'; | ||
} | ||
fs.readFile(`${__dirname}${path}/templates/${name}`, (err, content) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
|
||
return resolve(content.toString()); | ||
}); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done making it reusable.
export const novuReservedVariableNames = ['body']; | ||
|
||
export function isReservedVariableName(variableName: string) { | ||
return novuReservedVariableNames.includes(variableName); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏🏻
|
||
@Injectable() | ||
export class CreateLayoutUseCase { | ||
constructor(private layoutRepository: LayoutRepository) {} | ||
|
||
async execute(command: CreateLayoutCommand) { | ||
const entity = this.mapToEntity(command); | ||
const variables = this.getExtractedVariables(command.variables as ITemplateVariable[], command.content); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of applying it here you could directly apply it, inside of the mapToEntity
. It can be a matter of preference: either we want it clearly independently like you did, or we want to hide it a bit inside of the method that maps all properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did that at first :) But it felt that the map function look more complicated and less clear. Also, he really didn't like the types😅
@@ -43,4 +47,27 @@ export class CreateLayoutUseCase { | |||
isDeleted: layout.deleted, | |||
}; | |||
} | |||
|
|||
private getExtractedVariables(variables: ITemplateVariable[], content: string): ITemplateVariable[] { | |||
const contentService = new ContentService(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's our internal take on the use of a service? Just asking to consider suggesting to add it to the constructor of the use case rather that instantiate it every time the method is being called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was also wondering what will be better
const variableTypeHumanize = { | ||
String: 'Value', | ||
Array: 'Array', | ||
Boolean: 'Boolean', | ||
}[variable.type]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that you are trying to humanize the variable type. So just swap the order in the name would reads more natural I think: humanizedVariableType
. Though you could also to refer to it as variableTypeLabel
that might go more in line with being the text will be rendered like in an UI.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, its an old code, I just moved it.
export const VariableComponent = ({ index, template }: VariableComponentProps) => { | ||
const { control, watch } = useFormContext(); | ||
export const VariableComponent = ({ index, template, control, path }: VariableComponentProps) => { | ||
const formPrefix = path ? `${path}variables.${index}` : `${template}.variables.${index}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to double check that the intention is to create the formPrefix
for the case where path
exists as: ${path}variables.${index}
and not ${path}.variables.${index}
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Because I want to allow thw option of path being ''.
I want to refactor all the hooks and components related to var manager, we can do it much better. But will probably do it in cool down
apps/web/src/components/templates/email-editor/variables-management/VariablesManagement.tsx
Outdated
Show resolved
Hide resolved
interface ILayoutForm { | ||
content: string; | ||
name: string; | ||
description: string; | ||
isDefault: boolean; | ||
variables: ITemplateVariable[]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can generate the interface from Pick<LayoutDto, 'content' | 'name' | 'description' | 'isDefault' | 'variables'>
.
variables.forEach((vari) => { | ||
if (!arrayFields.find((field) => field.name === vari.name)) { | ||
arrayFields.push(vari); | ||
} | ||
}); | ||
arrayFields.forEach((vari, ind) => { | ||
if (!variables.find((field) => field.name === vari.name)) { | ||
delete arrayFields[ind]; | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am struggling to understand this bit. I have a feeling that this could be done with a single loop. Maybe with arrayFields
being a Set and using delete
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is a replicated code. Currently the hook we have for it is very dependent on a specific form context (the steps template.
I thought so to a few months ago haha. Worked on it for hours, eventually realized why it is needed- I'll tell you the problem later when we have more time and I remind myself a bit.
styles={{ | ||
modal: { | ||
backgroundColor: theme.colorScheme === 'dark' ? colors.B15 : colors.white, | ||
width: '90%', | ||
}, | ||
body: { | ||
paddingTop: '5px', | ||
paddingInline: '8px', | ||
}, | ||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use useStyles
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I like doing that for a very specific Modal. We already have a Modal in our design system. I would prefer to make that one more flexible to style changes. Will add it to backlog ❤️ Maybe a community member would like to help with thah.
Definitely! So many tests! But because of the huge PR I thought it's better if I do it separately. Thank you @p-fernandez for the thorough code review! I really appreciate it |
…ement/VariablesManagement.tsx Co-authored-by: Pablo Fernández <pablo@novu.co>
…l-content-in-Trigger' into nv-1458-web-abstract-variable-manager-to-not # Conflicts: # apps/api/src/app/layouts/use-cases/create-layout/create-layout.use-case.ts
aaca4c5
into
NV-1475-Compile-layout-with-email-content-in-Trigger
What change does this PR introduce?
Show var manager in layout editor, allow to set defaultValue and required for layout vars. Apply layout vars defaults in send email.
Why was this change needed?
Other information (Screenshots)