Skip to content

Commit 048fe9a

Browse files
feat(trust-roots): add error state pages (#60)
* feat(trust-roots): add error state pages * feat(trust-root): fix lint errors
1 parent fa61f5e commit 048fe9a

File tree

7 files changed

+95
-2
lines changed

7 files changed

+95
-2
lines changed

client/src/app/pages/TrustRoot/TrustRoot.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useFetchTrustRootMetadataInfo, useFetchTrustTargetCertificates } from "
99
import { CertificatesTable } from "./components/Certificates";
1010
import { Overview } from "./components/Overview";
1111
import { RootDetails } from "./components/RootDetails";
12+
import { MetadataNotAvailable } from "./components/ErrorStates/MetadataNotAvailable";
1213

1314
export const TrustRoots: React.FC = () => {
1415
const {
@@ -81,6 +82,7 @@ export const TrustRoots: React.FC = () => {
8182
certificates={certificates?.data ?? []}
8283
isFetching={isFetchingCertificates}
8384
fetchError={fetchErrorCertificates}
85+
rootLink={rootMetadataList?.["repo-url"]}
8486
/>
8587
</TabContent>
8688
<TabContent eventKey={1} id="certificatesTabSection" ref={certificatesTabRef} aria-label="Certificates" hidden>
@@ -92,7 +94,11 @@ export const TrustRoots: React.FC = () => {
9294
</TabContent>
9395
<TabContent eventKey={2} id="rootDetailsTabSection" ref={rootDetailsTabRef} aria-label="Root details" hidden>
9496
<LoadingWrapper isFetching={isFetchingRootMetadata} fetchError={fetchErrorRootMetadata}>
95-
{rootMetadataList && <RootDetails rootMetadataList={rootMetadataList} />}
97+
{rootMetadataList ? (
98+
<RootDetails rootMetadataList={rootMetadataList} />
99+
) : (
100+
<MetadataNotAvailable errorInfo="No metadata list found" />
101+
)}
96102
</LoadingWrapper>
97103
</TabContent>
98104
</PageSection>

client/src/app/pages/TrustRoot/components/Certificates.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import { ConditionalTableBody } from "@app/components/TableControls/ConditionalT
2727
import { useWithUiId } from "@app/hooks/query-utils";
2828
import { usePFToolbarTable } from "@app/hooks/usePFToolbarTable";
2929
import { formatDate, stringMatcher } from "@app/utils/utils";
30+
import { CertificateDoesNotExist } from "./ErrorStates/CertificateDoesNotExist";
31+
import { ErrorRetrievingCertificate } from "./ErrorStates/ErrorRetrievingCertificate";
3032

3133
interface ICertificatesTableProps {
3234
certificates: CertificateInfo[];
@@ -78,6 +80,14 @@ export const CertificatesTable: React.FC<ICertificatesTableProps> = ({ certifica
7880
},
7981
});
8082

83+
if (fetchError) {
84+
return <ErrorRetrievingCertificate />;
85+
}
86+
87+
if (certificates.length === 0) {
88+
return <CertificateDoesNotExist />;
89+
}
90+
8191
const {
8292
tableState: { currentPageItems },
8393
propHelpers: {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "react";
2+
import { Bullseye, EmptyState, EmptyStateBody, EmptyStateStatus } from "@patternfly/react-core";
3+
4+
export const CertificateDoesNotExist: React.FC = () => {
5+
return (
6+
<Bullseye>
7+
<EmptyState titleText="Certificate does not exist" headingLevel="h6" status={EmptyStateStatus.info}>
8+
<EmptyStateBody>Currently this trust root does not have any have certificates to display</EmptyStateBody>
9+
</EmptyState>
10+
</Bullseye>
11+
);
12+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from "react";
2+
import { Bullseye, EmptyState, EmptyStateBody, EmptyStateStatus, EmptyStateVariant } from "@patternfly/react-core";
3+
4+
export const ErrorRetrievingCertificate: React.FC = () => (
5+
<Bullseye>
6+
<EmptyState
7+
headingLevel="h4"
8+
titleText="Error retrieving certificate information"
9+
status={EmptyStateStatus.danger}
10+
variant={EmptyStateVariant.lg}
11+
>
12+
<EmptyStateBody className="pf-v6-u-font-size--xs">
13+
Due to issues with extracting certificate information, we could not find any valid certificates. The system will
14+
automatically retry again in 30 seconds.
15+
</EmptyStateBody>
16+
</EmptyState>
17+
</Bullseye>
18+
);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from "react";
2+
import { Bullseye, EmptyState, EmptyStateBody, EmptyStateStatus, EmptyStateVariant } from "@patternfly/react-core";
3+
4+
interface MetadataNotAvailableProps {
5+
errorInfo?: string;
6+
}
7+
8+
export const MetadataNotAvailable: React.FC<MetadataNotAvailableProps> = ({ errorInfo }) => (
9+
<Bullseye>
10+
<EmptyState
11+
variant={EmptyStateVariant.sm}
12+
titleText="Latest root metadata not available"
13+
status={EmptyStateStatus.danger}
14+
headingLevel="h4"
15+
>
16+
<EmptyStateBody>{errorInfo} </EmptyStateBody>
17+
</EmptyState>
18+
</Bullseye>
19+
);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from "react";
2+
import { Bullseye, EmptyState, EmptyStateBody, EmptyStateStatus, EmptyStateVariant } from "@patternfly/react-core";
3+
4+
interface RepositoryNotInitiatedProps {
5+
rootLink?: string;
6+
}
7+
8+
export const RepositoryNotInitiated: React.FC<RepositoryNotInitiatedProps> = ({ rootLink }) => (
9+
<Bullseye>
10+
<EmptyState
11+
variant={EmptyStateVariant.lg}
12+
titleText="Repository not initialized"
13+
headingLevel="h4"
14+
status={EmptyStateStatus.danger}
15+
>
16+
<EmptyStateBody>
17+
{rootLink
18+
? `
19+
Failed to build trust root options for ${rootLink}. The system will retry again in 30 seconds.`
20+
: "Failed to build trust root options. The system will retry again in 30 seconds."}
21+
</EmptyStateBody>
22+
</EmptyState>
23+
</Bullseye>
24+
);

client/src/app/pages/TrustRoot/components/Overview.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@ import { InfoAltIcon } from "@patternfly/react-icons";
2222
import type { _Error, CertificateInfo } from "@app/client";
2323
import { LoadingWrapper } from "@app/components/LoadingWrapper";
2424
import { formatDate } from "@app/utils/utils";
25+
import { RepositoryNotInitiated } from "./ErrorStates/RepositoryNotInitialized";
2526

2627
interface IOverviewProps {
2728
certificates: CertificateInfo[];
2829
isFetching: boolean;
2930
fetchError: AxiosError<_Error> | null;
31+
rootLink?: string;
3032
}
3133

32-
export const Overview: React.FC<IOverviewProps> = ({ certificates, isFetching, fetchError }) => {
34+
export const Overview: React.FC<IOverviewProps> = ({ certificates, isFetching, fetchError, rootLink }) => {
3335
const chartDonutData = React.useMemo(() => {
3436
return certificates.reduce(
3537
(prev, current) => {
@@ -52,6 +54,8 @@ export const Overview: React.FC<IOverviewProps> = ({ certificates, isFetching, f
5254
.sort((a, b) => dayjs(a.expiration).valueOf() - dayjs(b.expiration).valueOf());
5355
}, [certificates]);
5456

57+
if (Array.isArray(certificates) && certificates.length === 0) return <RepositoryNotInitiated rootLink={rootLink} />;
58+
5559
return (
5660
<LoadingWrapper isFetching={isFetching} fetchError={fetchError}>
5761
<Flex direction={{ default: "column", md: "row" }}>

0 commit comments

Comments
 (0)