-
Notifications
You must be signed in to change notification settings - Fork 28
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
WD-8528 - feat: Display errors in Actions Panel #1691
WD-8528 - feat: Display errors in Actions Panel #1691
Conversation
Demo starting at https://juju-dashboard-1691.demos.haus |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #1691 +/- ##
==========================================
+ Coverage 95.04% 95.07% +0.03%
==========================================
Files 182 183 +1
Lines 5325 5359 +34
Branches 1545 1555 +10
==========================================
+ Hits 5061 5095 +34
Misses 243 243
Partials 21 21 ☔ View full report in Codecov by Sentry. |
@@ -211,12 +244,21 @@ export default function ActionsPanel(): JSX.Element { | |||
cancelButtonLabel={Label.CANCEL_BUTTON} | |||
confirmButtonLabel={Label.CONFIRM_BUTTON} | |||
confirmButtonAppearance="positive" | |||
onConfirm={() => { | |||
onConfirm={(event: React.MouseEvent<HTMLElement, MouseEvent>) => { | |||
event.nativeEvent.stopImmediatePropagation(); |
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.
This line of code (and maybe similar lines in other places) might become redundant in the case this gets implemented.
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.
Thanks for filing that issue. I think it would be good to leave a comment here about why this stopImmediatePropagation
is necessary and probably link to the issue you filed as well.
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've ended up making quite a few small comments so I'll do another review of this once those changes have been made.
@@ -119,9 +145,16 @@ export default function ActionsPanel(): JSX.Element { | |||
setActionData(actions.results[0].actions); | |||
} | |||
setFetchingActionData(false); | |||
setInlineErrors((prevInlineErrors) => [null, prevInlineErrors[1]]); |
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.
This case (and the other setInlineErrors() calls below) would lead to bugs if the total number of errors in the tuple changed (e.g. if a third error was added it would get lost during this call). Instead we should only update the slot that matches the error we're concerned with.
If you're concerned about mutating state then you could do something like:
errors = [... prevInlineErrors];
errors[0] = null;
@@ -211,12 +244,21 @@ export default function ActionsPanel(): JSX.Element { | |||
cancelButtonLabel={Label.CANCEL_BUTTON} | |||
confirmButtonLabel={Label.CONFIRM_BUTTON} | |||
confirmButtonAppearance="positive" | |||
onConfirm={() => { | |||
onConfirm={(event: React.MouseEvent<HTMLElement, MouseEvent>) => { | |||
event.nativeEvent.stopImmediatePropagation(); |
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.
Thanks for filing that issue. I think it would be good to leave a comment here about why this stopImmediatePropagation
is necessary and probably link to the issue you filed as well.
console.error(Label.EXECUTE_ACTION_ERROR, error), | ||
); | ||
handleRemovePanelQueryParams(); | ||
executeAction() |
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 think this should clear the errors here in case the user submits the form again. Also, depending on how long this action takes there could be a pause before the panel closes. You could show a loading state in the button. You'd need a new state (e.g. "const [saving, setSaving] = useState(false);".
executeAction() | |
setSaving(true); | |
executeAction() |
You'll also need to update the button on line 287 to be <ActionButton
and then give it the props disabled={saving} loading={saving}
.
.catch((error) => { | ||
setInlineErrors((prevInlineError) => [ |
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.
If you set the saving state when the action starts then you'll need to update it again here:
.catch((error) => { | |
setInlineErrors((prevInlineError) => [ | |
.catch((error) => { | |
setSaving(false); | |
setInlineErrors((prevInlineError) => [ |
return; | ||
}) | ||
.catch((error) => console.error(Label.GET_ACTIONS_ERROR, error)); | ||
.catch((error) => { | ||
setInlineErrors((prevInlineErrors) => [ |
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.
Here also we need to only update a single error slot so we don't accidentally remove errors if the number of errors in the tuple changes.
prevInlineError[0], | ||
Label.EXECUTE_ACTION_ERROR, |
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.
Also need to only update a single slot in the tuple.
@@ -392,7 +395,7 @@ export default function ConfigPanel(): JSX.Element { | |||
|
|||
<div className="config-panel__list"> | |||
{formErrors |
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 think this should also have .some(...
or at the very least check that this isn't an empty array.
const generateErrors = (errors: string[], scrollArea: HTMLElement | null) => ( | ||
<ScrollOnRender scrollArea={scrollArea}> | ||
{errors.map((error) => ( | ||
<Notification key={error} severity="negative"> | ||
{error} | ||
</Notification> | ||
))} | ||
</ScrollOnRender> | ||
); |
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.
Possibly in a follow-up branch this could become a shared component, something like PanelErrors
and include the .some(...)
like you do in the other panel, as we're doing the same thing in a number of places.
{inlineErrors.some((error) => error) | ||
? generateInlineErrors(inlineErrors, scrollArea.current) | ||
: null} |
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.
This needs to be outside of the wrapping <p>
as this is currently giving errors about nested <p>
tags.
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.
Thanks for all the changes. I've made a couple of small comments but this can land once those have been fixed.
return; | ||
}) | ||
.catch((error) => console.error(Label.GET_ACTIONS_ERROR, error)); | ||
.catch((error) => { |
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 think this also needs to call setFetchingActionData(false);
so that the spinner hides when the error appears.
scrollArea?: HTMLElement | null; | ||
}; | ||
|
||
const PanelInlineErrors = ({ |
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.
Nice, thanks for adding this.
|
||
import PanelInlineErrors from "./PanelInlineErrors"; | ||
|
||
describe("PanelInlineErrors", () => { |
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 think it would be good to also test that the ScrollOnRender
component does not appear if inlineErrors
is null
, an empty array or only contains falsey items.
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 one tiny comment.
Done
QA
executeAction
function definition:Details