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

Adds server error messages to form actions bar #788

Merged
merged 14 commits into from
Apr 21, 2022
Merged

Conversation

zephraph
Copy link
Contributor

@zephraph zephraph commented Apr 13, 2022

Goals

  • Show server errors in the form actions as shown in the designs
  • Move the responsibility for formatting errors to the api package
    • Formatted error messages can be gotten from the error.message response anywhere in app code

A note on client-side vs server-side errors

To re-cap a lot of in-chat discussions, we largely believe the client should do very little in the way of modifying error messages coming back from the server. Ideally the server would provide errors that are injectable directly into the form error. Further, if we need to map an error to a particular field, that information will ultimately need to be provided by the server too. The latter part is kind of covered by oxidecomputer/omicron#910. Once we've made server-side updates, it's very likely that errorCodeFormatter could just go away entirely and most of what's happening in the client api layer can be simplified.

Progress shots

image

image

@vercel
Copy link

vercel bot commented Apr 13, 2022

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/oxidecomputer/console-ui-storybook/CvZu67VirkUcZ3qif8xfErAnQooP
✅ Preview: https://console-ui-storybook-git-form-error-msgs-oxidecomputer.vercel.app

@github-actions
Copy link
Contributor

Preview will be deployed at https://console-git-form-error-msgs.internal.oxide.computer

Comment on lines -355 to +354
<div className="text-destructive">{getServerError(error)}</div>
<div className="text-destructive">{error?.error.message}</div>
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'll go away once we convert this form

@zephraph zephraph temporarily deployed to Preview VM April 13, 2022 19:08 Inactive
Comment on lines 11 to 27
const methodCodeMap: { [key in keyof Partial<ApiMethods>]: Record<string, string> } = {
organizationsPost: {
ObjectAlreadyExists: 'An organization with that name already exists',
},
projectInstancesPost: {
ObjectAlreadyExists: 'An instance with that name already exists in this project',
},
projectDisksPost: {
ObjectAlreadyExists: 'A disk with that name already exists in this project',
},
projectVpcsPost: {
ObjectAlreadyExists: 'A VPC with that name already exists in this project',
},
vpcSubnetsPost: {
ObjectAlreadyExists: 'A Subnet with that name already exists in this project',
},
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

You can imagine how this could get incredibly verbose. Definitely need to come up with a better way to break it down.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We could easily put this together dynamically if each endpoint was tagged with the name of the resource and the name of the parent, but that really feels like API logic. At least for this specific error, I don't see why the API couldn't produce this sentence for us. To me the fact that this mapping feels like it belongs in the API layer of the console suggests it could really go in the API itself.

That doesn't solve the problem in general, because I'm sure there will be cases where we want to say something more specific than would be appropriate for an API message. But for those cases maybe we don't need to think of them as API-layer errors but rather as part of the logic of the calling form, like I had before at the page level:

const ERROR_CODES = {
ObjectAlreadyExists:
'A project with that name already exists in this organization',
}

Maybe the solution is to get as many of these messages as we can from the API, and for the remaining ones we encode them at the form level?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree this should come more from the API. Any transformations or mapping that we have to do on the client are a bit of a smell. One clear way we could resolve this is to change the ObjectAlreadyExists error in Nexus to require the type of the object that already exists. I mean, if an ObjectAlreadyExists error is spawned in a saga it might not be clear what object doesn't exist as we've built it now.

I'm not necessarily convinced that spreading the errors out makes any real difference. I'm afraid that would lead to inconsistent implementation of error messaging because the only context you have is what's already in the form you're looking at (or another form you reference). Having them centralized makes it easy to see all the custom errors at a glance. From an architectural perspective I also don't feel like the forms should have any specific knowledge of an error. Ideally it just displays whatever is given.

Copy link
Collaborator

@david-crespo david-crespo Apr 17, 2022

Choose a reason for hiding this comment

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

I think spreading them out into the callers would make sense only if there are just a few very context-specific cases we can't get the API to handle, in which case we would think of them as UI copy.

That's a good point about sagas. With composite endpoints like instance create, we really do need more info from the API no matter what, and I'm inclined toward having it just write a nice message instead of trying to come up with an abstract scheme of all the bits of info we might need to come up with such a message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looking at the Error enum in omicron, it looks like some of these messages are already build out. I think they could be tweaked, but that much is promising.

@zephraph zephraph temporarily deployed to Preview VM April 14, 2022 17:42 Inactive
@zephraph zephraph temporarily deployed to Preview VM April 14, 2022 18:42 Inactive
libs/api/errors.ts Outdated Show resolved Hide resolved
@vercel
Copy link

vercel bot commented Apr 17, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
console-ui-storybook ✅ Ready (Inspect) Visit Preview Apr 19, 2022 at 3:13AM (UTC)

@zephraph zephraph temporarily deployed to Preview VM April 18, 2022 21:26 Inactive
@jessfraz jessfraz temporarily deployed to Preview VM April 18, 2022 21:34 Inactive
@zephraph zephraph temporarily deployed to Preview VM April 18, 2022 23:22 Inactive
@zephraph zephraph marked this pull request as ready for review April 19, 2022 03:01
Comment on lines 7 to 8
(errorCode: string, error: Error): string | undefined => {
switch (errorCode) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not a huge fan of errorCode being untyped. Generally this is because dropshot is piping out a generic http error instead of more specific nexus errors.

I wrote about this in chat:

Currently the Error type isn't being exported via the OpenAPI spec. The exported error type is much more permissive. If I'm reading dropshot#286 correctly, the permissive type is just dropshot's default http error. Looking at http_entrypoints that'd make sense given that all our routes just return dropshot's HttpError. I'm wondering at this point if we could change dropshot's behavior to provide a customizable http error. Ideally if we could return like... NexusHttpError instead, we could likely get the types that we want.

@zephraph zephraph merged commit 0a6cf48 into main Apr 21, 2022
@zephraph zephraph deleted the form-error-msgs branch April 21, 2022 20:41
@zephraph zephraph linked an issue Apr 27, 2022 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add back in form-level error message
3 participants