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

better error decoding #880

Merged
merged 1 commit into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 7 additions & 32 deletions src/components/async-resource/another-async-resource.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { CircularProgress, Typography } from '@equinor/eds-core-react';
import { SerializedError } from '@reduxjs/toolkit';
import { FetchBaseQueryError } from '@reduxjs/toolkit/query';
import { getReasonPhrase } from 'http-status-codes';
import React, { FunctionComponent, PropsWithChildren, ReactNode } from 'react';

import { Alert } from '../alert';
import { externalUrls } from '../../externalUrls';
import { isNullOrUndefined } from '../../utils/object';
import { FetchQueryResult } from '../../store/types';
import { FetchQueryError, FetchQueryResult } from '../../store/types';
import { getFetchErrorData } from '../../store/utils';

type AnotherAsyncStatus = Pick<
FetchQueryResult,
Expand All @@ -31,39 +29,16 @@ const LoadingComponent: FunctionComponent<{
defaultContent
);

export function getErrorData(error: FetchQueryResult['error']): {
code?: string | number;
message: string;
} {
let errObj: ReturnType<typeof getErrorData> = { message: '' };
if ((error as SerializedError).message || (error as SerializedError).code) {
const { code, message } = error as SerializedError;
errObj = { code, message };
} else if ((error as FetchBaseQueryError).status) {
const err = error as FetchBaseQueryError;
errObj.message = err.data as string;
if (typeof err.status === 'number') {
errObj.code = err.status;
} else if (err.status === 'PARSING_ERROR') {
errObj.code = err.originalStatus;
errObj.message = getReasonPhrase(errObj.code);
}
}

return errObj;
}

const ErrorPanel: FunctionComponent<
Required<Pick<FetchQueryResult, 'error'>>
> = ({ error }) => {
const { message, code } = getErrorData(error);
const ErrorPanel: FunctionComponent<{ error: FetchQueryError }> = ({
error,
}) => {
const { code, message } = getFetchErrorData(error);

return (
<div>
<Typography variant="caption">Error message:</Typography>
<samp className="word-break">
{code && `${code}: `}
{message}
{[code, message].filter((x) => !!x).join(': ')}
</samp>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ import {
useState,
} from 'react';

import AsyncResource, {
getErrorData,
} from '../async-resource/another-async-resource';
import AsyncResource from '../async-resource/another-async-resource';
import { errorToast } from '../global-top-nav/styled-toaster';
import { Duration } from '../time/duration';
import { RelativeToNow } from '../time/relative-to-now';
Expand All @@ -30,6 +28,7 @@ import {
useGetComponentInventoryQuery,
} from '../../store/log-api';
import { FetchQueryResult } from '../../store/types';
import { getFetchErrorData } from '../../store/utils';
import { sortCompareDate, sortDirection } from '../../utils/sort-utils';
import {
copyToTextFile,
Expand Down Expand Up @@ -76,7 +75,7 @@ function saveLog(
const extension = !fileName.endsWith('.txt') ? '.txt' : '';
copyToTextFile(`${fileName}${extension}`, query.data as string);
} else if (query.isError) {
const { code, message } = getErrorData(query.error);
const { code, message } = getFetchErrorData(query.error);
errorToast(`${errMsg}: ${code && `[${code}] `}${message}`);
}
}
Expand Down
17 changes: 9 additions & 8 deletions src/components/page-environment/component-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import * as PropTypes from 'prop-types';
import { FunctionComponent, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';

import AsyncResource, {
getErrorData,
} from '../async-resource/another-async-resource';
import AsyncResource from '../async-resource/another-async-resource';
import { ComponentStatusBadge } from '../status-badges';
import { ReplicaStatusTooltip } from '../status-tooltips';
import { VulnerabilitySummary } from '../vulnerability-summary';
Expand All @@ -28,6 +26,7 @@ import {
ImageWithLastScan,
useGetEnvironmentVulnerabilitySummaryQuery,
} from '../../store/scan-api';
import { getFetchErrorData } from '../../store/utils';
import {
getActiveComponentUrl,
getActiveJobComponentUrl,
Expand Down Expand Up @@ -120,7 +119,7 @@ export const ComponentList: FunctionComponent<ComponentListProps> = ({
environment: { name: envName },
components,
}) => {
const { data: vulnerabilities, ...vulnerabilitiesState } =
const { data: vulnerabilities, ...state } =
useGetEnvironmentVulnerabilitySummaryQuery({ appName, envName });

const [compMap, setCompMap] = useState<Record<string, Array<ComponentModel>>>(
Expand Down Expand Up @@ -184,13 +183,15 @@ export const ComponentList: FunctionComponent<ComponentListProps> = ({
</Table.Cell>
<Table.Cell>
<AsyncResource
asyncState={vulnerabilitiesState}
asyncState={state}
errorContent={
<samp>
{vulnerabilitiesState.error &&
{state.isError &&
(({ code, message }) =>
`${code && `${code}: `}${message}`)(
getErrorData(vulnerabilitiesState.error)
[code, message]
.filter((x) => !!x)
.join(': '))(
getFetchErrorData(state.error)
)}
</samp>
}
Expand Down
7 changes: 3 additions & 4 deletions src/components/page-scheduled-job/replica-log-accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ import {
useState,
} from 'react';

import AsyncResource, {
getErrorData,
} from '../async-resource/another-async-resource';
import AsyncResource from '../async-resource/another-async-resource';
import { errorToast } from '../global-top-nav/styled-toaster';
import { Duration } from '../time/duration';
import { RelativeToNow } from '../time/relative-to-now';
Expand All @@ -31,6 +29,7 @@ import {
useGetJobInventoryQuery,
} from '../../store/log-api';
import { FetchQueryResult } from '../../store/types';
import { getFetchErrorData } from '../../store/utils';
import { sortCompareDate, sortDirection } from '../../utils/sort-utils';
import {
copyToTextFile,
Expand Down Expand Up @@ -90,7 +89,7 @@ function saveLog(
const extension = !fileName.endsWith('.txt') ? '.txt' : '';
copyToTextFile(`${fileName}${extension}`, query.data as string);
} else if (query.isError) {
const { code, message } = getErrorData(query.error);
const { code, message } = getFetchErrorData(query.error);
errorToast(`${errMsg}: ${code && `[${code}] `}${message}`);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/store/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ export type FetchQueryResult<T = unknown> = Omit<
FetchQueryHookResult<T>,
'refetch'
>;

export type FetchQueryError = FetchQueryResult['error'];
59 changes: 59 additions & 0 deletions src/store/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { SerializedError } from '@reduxjs/toolkit';
import { FetchBaseQueryError } from '@reduxjs/toolkit/query';
import { getReasonPhrase } from 'http-status-codes';

import { FetchQueryError } from '../types';

export function getFetchErrorData(error: FetchQueryError): {
code?: string | number;
message: string;
} {
const errObj: ReturnType<typeof getFetchErrorData> = {
code: undefined,
message: '',
};

if ((error as SerializedError).message || (error as SerializedError).code) {
errObj.code = (error as SerializedError).code;
errObj.message = (error as SerializedError).message;
} else if ((error as FetchBaseQueryError).status) {
const err = error as FetchBaseQueryError;
if (err.data?.['code'] || err.data?.['message']) {
// data is an object containing status
errObj.code = err.data['code'];
if (typeof err.data['message'] === 'string') {
errObj.message = err.data['message'];
}
} else if (typeof err.status === 'number') {
errObj.code = err.status;
if (typeof err.data === 'string') {
errObj.message = err.data;
}
} else if (err.status === 'PARSING_ERROR') {
errObj.code = err.originalStatus;
try {
const code = getReasonPhrase(errObj.code);
errObj.message = code;
} catch (_) {
// noop
}
} else {
errObj.code = err.status;
errObj.message = err.error;
}
}

return errObj;
}

export function getFetchErrorCode(
error: FetchQueryError
): ReturnType<typeof getFetchErrorData>['code'] {
return getFetchErrorData(error).code;
}

export function getFetchErrorMessage(
error: FetchQueryError
): ReturnType<typeof getFetchErrorData>['message'] {
return getFetchErrorData(error).message;
}