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

Error alert component #4084

Merged
merged 5 commits into from
Jan 20, 2022
Merged

Error alert component #4084

merged 5 commits into from
Jan 20, 2022

Conversation

castelblanque
Copy link
Collaborator

Signed-off-by: Rafa Castelblanque rcastelblanq@vmware.com

Description of the change

Introduces a React ErrorAlert component aimed at improving readability of UI errors and that could replace existing <Alert> usages.

It is able to turn this kind of UI error:

image

into this:

image

It can detect RPC errors and show them indented while not affecting existing plain text errors.
The change also allows to specify a stack of errors when creating a custom error (or an extension of it).

Benefits

Better error readability on UI

Possible drawbacks

None that I can think of.

Rafa Castelblanque added 3 commits January 14, 2022 12:27
Signed-off-by: Rafa Castelblanque <rcastelblanq@vmware.com>
Signed-off-by: Rafa Castelblanque <rcastelblanq@vmware.com>
Signed-off-by: Rafa Castelblanque <rcastelblanq@vmware.com>
dispatch(
errorApp(
e instanceof Error
? new FetchError("Unable to list apps", [e])
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Only place where the new constructor for errors is used by now.

@@ -131,7 +131,7 @@ function AppList() {
className="margin-t-xl"
>
{error ? (
<Alert theme="danger">Unable to list apps: {error.message}</Alert>
<ErrorAlert>{error}</ErrorAlert>
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Only usage of the new ErrorAlert component by now.

Copy link
Contributor

Choose a reason for hiding this comment

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

Great, just to confirm: you mean there are other errors out there (like there is a problem with this package...) which are not being handled by this novel ErrorAlert, don't you?
So this is just a kind of proof of concept, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Exactly, I first wanted the community to review it. If accepted, we can start using it from now on and eventually replace existing <Alert> with it.

@@ -0,0 +1,24 @@
export class RpcError extends Error {
// Following https://github.com/grpc/grpc-go/blob/master/internal/status/status.go#L140
static RPC_ERROR_REGEX = /rpc error: code = (\w+) desc = (.*)/;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Until we can have GRPC code to properly throw a dedicated error object, we can only guess if it is an rpc error by checking the error message string.

Copy link
Contributor

Choose a reason for hiding this comment

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

You should be able to check the grpc error code? At least, the gRPC dashboard code should be throwing an error object with a .code property. That's what we're using here already: https://github.com/kubeapps/kubeapps/blob/master/dashboard/src/shared/Auth.ts#L71-L88

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, will definitely take a look. It would be simpler.

// via err.contructor == FOO
constructor(message?: string) {
// via err.constructor == FOO
constructor(message?: string, causes?: Error[]) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Allows to optionally specify a stack of causing errors.

Signed-off-by: Rafa Castelblanque <rcastelblanq@vmware.com>
import "./ErrorAlert.css";

export interface IErrorAlert {
children: CustomError | Error | string;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Component supports rendering this three types.

Copy link
Contributor

Choose a reason for hiding this comment

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

What if there are no children?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Children is a mandatory item it seems. In this case doesn't make sense to show the error block without any content, does it?

@castelblanque
Copy link
Collaborator Author

This can be a complimentary work to #3723

Copy link
Contributor

@antgamdia antgamdia left a comment

Choose a reason for hiding this comment

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

Great. It seems a great UI improvement; I only have some minor comments and questions but in general LGTM!
Thank you!

@@ -131,7 +131,7 @@ function AppList() {
className="margin-t-xl"
>
{error ? (
<Alert theme="danger">Unable to list apps: {error.message}</Alert>
<ErrorAlert>{error}</ErrorAlert>
Copy link
Contributor

Choose a reason for hiding this comment

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

Great, just to confirm: you mean there are other errors out there (like there is a problem with this package...) which are not being handled by this novel ErrorAlert, don't you?
So this is just a kind of proof of concept, no?

import "./ErrorAlert.css";

export interface IErrorAlert {
children: CustomError | Error | string;
Copy link
Contributor

Choose a reason for hiding this comment

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

What if there are no children?

} else if (children instanceof Error) {
messages = [createWrap(children.message, 0, false)];
} else {
messages = [children];
Copy link
Contributor

Choose a reason for hiding this comment

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

As above, what if we have no response from the other side of the wire. For example, the API server being OOMkilled by k8s and the gRPC call just returns the nginx error 502 page ? - meaning no explicit error message being sent.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Same as commented above, it does not make sense to have the error block with empty data. For the error codes, it will show exactly the same as current <Alert> component, just the passed children.

@@ -0,0 +1,9 @@
.error-alert-rpc {
ul > li {
font-weight: bolder;
Copy link
Contributor

Choose a reason for hiding this comment

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

We are using explicit numbers in the rest of the CSS files, usually 400, 500 or 600. See what you think

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sure, will change it to be aligned 😃

font-weight: bolder;

span.rpc-value {
font-weight: normal;
Copy link
Contributor

Choose a reason for hiding this comment

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

Idem here

@@ -0,0 +1,24 @@
export class RpcError extends Error {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should rename Rpc to GRpc instead

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, I thought about it, but error message states rpc error: so I went ahead with a generic rpc naming for everything.

private extractData(message: string): [string, string, string] {
const found = message.trim().match(RpcError.RPC_ERROR_REGEX);
return found
? [found[1], found[2], message.substring(0, message.indexOf(found[0]))]
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rather check found.length to avoid undesired undefined

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added tests for empty strings and undefined and it seems ok.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was curious, so checked the match return for empty strings. It is undefined, for a positive case, the data is in the array. So we are good.

Signed-off-by: Rafa Castelblanque <rcastelblanq@vmware.com>
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.

None yet

3 participants