committed by
Fredrik Adelöw
parent
467fe2200c
commit
6ce1caa854
@@ -14,11 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// TODO align this design with the backend errors
|
||||
|
||||
import React from 'react';
|
||||
import { AppComponents } from '../..';
|
||||
import { ResponseErrorPanel } from '../ResponseErrorPanel';
|
||||
import { ErrorPanel } from '../ErrorPanel';
|
||||
import { Button } from '@material-ui/core';
|
||||
|
||||
export const ErrorBoundaryFallback: AppComponents['ErrorBoundaryFallback'] = ({
|
||||
@@ -27,15 +25,14 @@ export const ErrorBoundaryFallback: AppComponents['ErrorBoundaryFallback'] = ({
|
||||
plugin,
|
||||
}) => {
|
||||
return (
|
||||
<ResponseErrorPanel
|
||||
<ErrorPanel
|
||||
title={`Error in ${plugin?.getId()}`}
|
||||
defaultExpanded
|
||||
error={error}
|
||||
actions={
|
||||
<Button variant="outlined" onClick={resetError}>
|
||||
Retry
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
>
|
||||
<Button variant="outlined" onClick={resetError}>
|
||||
Retry
|
||||
</Button>
|
||||
</ErrorPanel>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { List, ListItem, ListItemText, makeStyles } from '@material-ui/core';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { CopyTextButton } from '../CopyTextButton';
|
||||
import { WarningPanel } from '../WarningPanel';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
text: {
|
||||
fontFamily: 'monospace',
|
||||
whiteSpace: 'pre',
|
||||
overflowX: 'auto',
|
||||
marginRight: theme.spacing(2),
|
||||
},
|
||||
divider: {
|
||||
margin: theme.spacing(2),
|
||||
},
|
||||
}));
|
||||
|
||||
type ErrorListProps = {
|
||||
error: string;
|
||||
message: string;
|
||||
request?: string;
|
||||
stack?: string;
|
||||
json?: string;
|
||||
};
|
||||
|
||||
const ErrorList = ({
|
||||
error,
|
||||
message,
|
||||
stack,
|
||||
children,
|
||||
}: PropsWithChildren<ErrorListProps>) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<List dense>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Error"
|
||||
secondary={error}
|
||||
/>
|
||||
<CopyTextButton text={error} />
|
||||
</ListItem>
|
||||
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Message"
|
||||
secondary={message}
|
||||
/>
|
||||
<CopyTextButton text={message} />
|
||||
</ListItem>
|
||||
|
||||
{stack && (
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Stack Trace"
|
||||
secondary={stack}
|
||||
/>
|
||||
<CopyTextButton text={stack} />
|
||||
</ListItem>
|
||||
)}
|
||||
|
||||
{children}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
export type ErrorPanelProps = {
|
||||
error: Error;
|
||||
defaultExpanded?: boolean;
|
||||
title?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a warning panel as the effect of an error.
|
||||
*/
|
||||
export const ErrorPanel = ({
|
||||
title,
|
||||
error,
|
||||
defaultExpanded,
|
||||
children,
|
||||
}: PropsWithChildren<ErrorPanelProps>) => {
|
||||
return (
|
||||
<WarningPanel
|
||||
title={title ?? error.message}
|
||||
defaultExpanded={defaultExpanded}
|
||||
>
|
||||
<ErrorList
|
||||
error={error.name}
|
||||
message={error.message}
|
||||
stack={error.stack}
|
||||
children={children}
|
||||
/>
|
||||
</WarningPanel>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ErrorPanel } from './ErrorPanel';
|
||||
export type { ErrorPanelProps } from './ErrorPanel';
|
||||
@@ -15,17 +15,11 @@
|
||||
*/
|
||||
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import {
|
||||
Divider,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
makeStyles,
|
||||
} from '@material-ui/core';
|
||||
import { Divider, ListItem, ListItemText, makeStyles } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { CodeSnippet } from '../CodeSnippet';
|
||||
import { CopyTextButton } from '../CopyTextButton';
|
||||
import { WarningPanel } from '../WarningPanel';
|
||||
import { ErrorPanel, ErrorPanelProps } from '../ErrorPanel';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
text: {
|
||||
@@ -39,107 +33,25 @@ const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
}));
|
||||
|
||||
type ResponseErrorListProps = {
|
||||
error: string;
|
||||
message: string;
|
||||
request?: string;
|
||||
stack?: string;
|
||||
json?: string;
|
||||
actions?: React.ReactNode;
|
||||
};
|
||||
|
||||
const ResponseErrorList = ({
|
||||
error,
|
||||
request,
|
||||
message,
|
||||
stack,
|
||||
json,
|
||||
actions,
|
||||
}: ResponseErrorListProps) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<List dense>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Error"
|
||||
secondary={error}
|
||||
/>
|
||||
<CopyTextButton text={error} />
|
||||
</ListItem>
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Message"
|
||||
secondary={message}
|
||||
/>
|
||||
<CopyTextButton text={message} />
|
||||
</ListItem>
|
||||
{request && (
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Request"
|
||||
secondary={request}
|
||||
/>
|
||||
<CopyTextButton text={request} />
|
||||
</ListItem>
|
||||
)}
|
||||
{stack && (
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Stack Trace"
|
||||
secondary={stack}
|
||||
/>
|
||||
<CopyTextButton text={stack} />
|
||||
</ListItem>
|
||||
)}
|
||||
{json && (
|
||||
<>
|
||||
<Divider component="li" className={classes.divider} />
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Full Error as JSON"
|
||||
secondary={<CodeSnippet language="json" text={json} />}
|
||||
/>
|
||||
<CopyTextButton text={json} />
|
||||
</ListItem>
|
||||
</>
|
||||
)}
|
||||
{actions && (
|
||||
<>
|
||||
<Divider component="li" className={classes.divider} />
|
||||
<ListItem alignItems="flex-start">{actions}</ListItem>
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
);
|
||||
};
|
||||
|
||||
type Props = {
|
||||
error: Error;
|
||||
defaultExpanded?: boolean;
|
||||
title?: string;
|
||||
actions?: React.ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders details about a failed server request.
|
||||
* Renders a warning panel as the effect of a failed server request.
|
||||
*
|
||||
* Has special treatment for ResponseError errors, to display rich
|
||||
* server-provided information about what happened.
|
||||
*/
|
||||
export const ResponseErrorDetails = ({ error, actions }: Props) => {
|
||||
export const ResponseErrorPanel = ({
|
||||
title,
|
||||
error,
|
||||
defaultExpanded,
|
||||
}: ErrorPanelProps) => {
|
||||
const classes = useStyles();
|
||||
|
||||
if (error.name !== 'ResponseError') {
|
||||
return (
|
||||
<ResponseErrorList
|
||||
error={error.name}
|
||||
message={error.message}
|
||||
stack={error.stack}
|
||||
actions={actions}
|
||||
<ErrorPanel
|
||||
title={title ?? error.message}
|
||||
defaultExpanded={defaultExpanded}
|
||||
error={error}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -154,34 +66,32 @@ export const ResponseErrorDetails = ({ error, actions }: Props) => {
|
||||
const jsonString = JSON.stringify(data, undefined, 2);
|
||||
|
||||
return (
|
||||
<ResponseErrorList
|
||||
error={errorString}
|
||||
message={messageString}
|
||||
request={requestString}
|
||||
stack={stackString}
|
||||
json={jsonString}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders a warning panel as the effect of a failed server request.
|
||||
*
|
||||
* Has special treatment for ResponseError errors, to display rich
|
||||
* server-provided information about what happened.
|
||||
*/
|
||||
export const ResponseErrorPanel = ({
|
||||
title,
|
||||
error,
|
||||
defaultExpanded,
|
||||
actions,
|
||||
}: Props) => {
|
||||
return (
|
||||
<WarningPanel
|
||||
<ErrorPanel
|
||||
title={title ?? error.message}
|
||||
defaultExpanded={defaultExpanded}
|
||||
error={{ name: errorString, message: messageString, stack: stackString }}
|
||||
>
|
||||
<ResponseErrorDetails error={error} actions={actions} />
|
||||
</WarningPanel>
|
||||
{requestString && (
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Request"
|
||||
secondary={request}
|
||||
/>
|
||||
<CopyTextButton text={requestString} />
|
||||
</ListItem>
|
||||
)}
|
||||
<>
|
||||
<Divider component="li" className={classes.divider} />
|
||||
<ListItem alignItems="flex-start">
|
||||
<ListItemText
|
||||
classes={{ secondary: classes.text }}
|
||||
primary="Full Error as JSON"
|
||||
secondary={<CodeSnippet language="json" text={jsonString} />}
|
||||
/>
|
||||
<CopyTextButton text={jsonString} />
|
||||
</ListItem>
|
||||
</>
|
||||
</ErrorPanel>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ResponseErrorDetails, ResponseErrorPanel } from './ResponseErrorPanel';
|
||||
export { ResponseErrorPanel } from './ResponseErrorPanel';
|
||||
|
||||
Reference in New Issue
Block a user