Skip to content
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

feat(dashboard): step conditions editor ui #7502

Open
wants to merge 6 commits into
base: next
Choose a base branch
from

Conversation

LetItRock
Copy link
Contributor

@LetItRock LetItRock commented Jan 14, 2025

What changed? Why was the change needed?

The Step Conditions - just the editor UI part. It will be integrated with API in the upcoming PRs.

The components used to build the editor look a bit different from what we had in the designs because the sizes used in the designs are not the ones that we support in the code, and not all component behavior was shown.

Also, improved performance of the CodeMirror Editor component.

Screenshots

Screenshot 2025-01-14 at 12 01 41

Screen.Recording.2025-01-14.at.11.58.48.mov

Copy link

linear bot commented Jan 14, 2025

Copy link

netlify bot commented Jan 14, 2025

Deploy Preview for dev-web-novu ready!

Name Link
🔨 Latest commit 1cfceec
🔍 Latest deploy log https://app.netlify.com/sites/dev-web-novu/deploys/67893716c4f885000803c822
😎 Deploy Preview https://deploy-preview-7502.dashboard.novu-staging.co
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

netlify bot commented Jan 14, 2025

Deploy Preview for dashboard-v2-novu-staging ready!

Name Link
🔨 Latest commit 1cfceec
🔍 Latest deploy log https://app.netlify.com/sites/dashboard-v2-novu-staging/deploys/6789371638acc90008c96358
😎 Deploy Preview https://deploy-preview-7502.dashboard-v2.novu-staging.co
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.


import { Button } from '@/components/primitives/button';

export const AddConditionAction = ({ label, title, rules, handleOnClick }: ActionWithRulesAndAddersProps) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This represents the add condition button in the editor UI. The button will be hidden if there are 10 conditions applied (restriction from the definition of done).

Screenshot 2025-01-14 at 12 20 00

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about the And icon? I feel it's a little confusing and feels like a reload, what if we just remove it? another UX tweak, we can hide if there is only one condition available, and show it if more than one was added.

cc. @twentyone24

Copy link
Contributor Author

@LetItRock LetItRock Jan 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the icon feels a bit odd, I'll change it to a default double arrows. I wouldn't do the conditional hiding as it will introduce the UI jumping effect.

import { StackedPlusLine } from '@/components/icons/stacked-plus-line';
import { Button } from '@/components/primitives/button';

export const AddGroupAction = ({ label, title, level, rules, handleOnClick }: ActionWithRulesAndAddersProps) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This represents the add group button in the editor UI. The button will be hidden if there are 10 conditions applied or the group is nested (restriction from the definition of done).

Screenshot 2025-01-14 at 12 20 00

import { cn } from '@/utils/ui';
import { toSelectOptions } from '@/components/conditions-editor/select-option-utils';

export const CombinatorSelector = ({ disabled, value, options, handleOnChange }: CombinatorSelectorProps) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This represents the Or/And combinator dropdown.
Screenshot 2025-01-14 at 12 20 00

getParentGroup: () => null,
});

export function ConditionsEditorProvider({ children }: { children: React.ReactNode }) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The context provider for the editor. It stores the query, allows to remove and clone condition/group, and get the nearest parent.

Comment on lines +20 to +36
const fields = [
{ name: 'payload.foo', label: 'payload.foo', value: 'payload.foo' },
{ name: 'payload.bar', label: 'payload.bar', value: 'payload.bar' },
{ name: 'payload.baz', label: 'payload.baz', value: 'payload.baz' },
{ name: 'payload.qux', label: 'payload.qux', value: 'payload.qux' },
{ name: 'payload.quux', label: 'payload.quux', value: 'payload.quux' },
{ name: 'payload.corge', label: 'payload.corge', value: 'payload.corge' },
{ name: 'payload.grault', label: 'payload.grault', value: 'payload.grault' },
{ name: 'payload.garply', label: 'payload.garply', value: 'payload.garply' },
{ name: 'payload.waldo', label: 'payload.waldo', value: 'payload.waldo' },
{ name: 'payload.fred', label: 'payload.fred', value: 'payload.fred' },
{ name: 'payload.plugh', label: 'payload.plugh', value: 'payload.plugh' },
{ name: 'payload.xyzzy', label: 'payload.xyzzy', value: 'payload.xyzzy' },
{ name: 'payload.thud', label: 'payload.thud', value: 'payload.thud' },
] satisfies Field[];

export const variables = fields.map((field) => ({ type: 'variable', label: field.label })) satisfies LiquidVariable[];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are just the examples for now, will be removed when we integrate with the API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will those come from the combination of all the payloads used on the workflow? This also has to contain things like previous steps, etc... Can we reuse the exact logic of the variables autocomplete context we give in the code mirror?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


return (
<div className="flex flex-col">
<input
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hidden input manages the focus and keyboard navigation. I've tried with cmdk, but it doesn't work well and doesn't allow you to control the focus. Let me explain: when the input is focused, we want to show the dropdown but not focus on it so the input stays focused, then, when the keyboard navigation is used, we want to focus on the list and navigate through the list items.

Comment on lines +136 to +139
<KeyboardItem>↑</KeyboardItem>
<KeyboardItem>↓</KeyboardItem>
<span className="text-foreground-600 text-paragraph-xs ml-0.5">Navigate</span>
<KeyboardItem className="ml-auto">↵</KeyboardItem>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for svg's :P

Comment on lines +166 to +167
const [inputValue, setInputValue] = useState(value ?? '');
const [filterValue, setFilterValue] = useState('');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filter value is used to filter the options array. When the input is focused it's value is reset to '' and all the items are shown to the user, otherwise if input value is typed it will filter the list.

<path d="M13.662 15.68c-.499.28-1.045.37-1.412.37a.55.55 0 0 1 0-1.1c.217 0 .57-.06.875-.23.288-.16.515-.407.583-.81.051-.31.054-.678.058-1.116v-.056c.005-.439.011-.941.1-1.404.09-.467.275-.958.683-1.328.415-.375.985-.556 1.701-.556a.55.55 0 0 1 0 1.1c-.533 0-.808.132-.963.272-.162.147-.274.374-.34.72-.068.35-.076.753-.08 1.205l-.001.089c-.003.406-.007.857-.073 1.255-.133.797-.614 1.3-1.13 1.59ZM8.111 8.111a.55.55 0 0 1 .778 0l3 3a.55.55 0 1 1-.778.778l-3-3a.55.55 0 0 1 0-.778Z" />
<path d="M11.89 8.111a.55.55 0 0 0-.779 0l-3 3a.55.55 0 1 0 .778.778l3-3a.55.55 0 0 0 0-.778Z" />
</g>
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improved this svg to be able to better control sizes

@@ -183,10 +185,10 @@ export const Editor = React.forwardRef<{ focus: () => void; blur: () => void },
// which results in value not being updated and "jumping" effect in the editor
// to prevent this we need to flush the state updates synchronously
flushSync(() => {
onChange?.(value);
onChangeRef.current?.(value);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The performance improvement for the CodeMirror Editor. When the onChange prop changes, usually on every render it has a slow performance and lag, this approach fixes it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the initial screen open we see 3 buttons, what if we just show one in the empty state? Or maybe craft an empty state that explains the basics of conditions? cc. @twentyone24
CleanShot 2025-01-14 at 16 37 47@2x

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Showing one rule will require picking up some values for field, operator, value inputs which will be tricky.
The library does not support the empty state, and there is no API for setting an empty component, unfortunately. We can hack it, but it will require building the layout for all buttons, rules, and actions from the ground.

I think that if we supply good documentation about it, it should be enough.

Copy link
Contributor

@scopsy scopsy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks really exciting! Left a few notes and comments, other than that it works great from manual testing perspective, ofcourse will test more once it's integrated e2e

@LetItRock LetItRock requested a review from scopsy January 16, 2025 16:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants