Skip to content

Commit 84aa096

Browse files
Merge pull request #3 from abhinandan13jan/add-trust-colum
feat(trust-pages): refactor trust pages and add metadata card
2 parents f5e7bc4 + 873f73b commit 84aa096

File tree

11 files changed

+939
-324
lines changed

11 files changed

+939
-324
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import * as React from "react";
2+
import { Flex, FlexItem, Icon, Pagination } from "@patternfly/react-core";
3+
import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table";
4+
import CheckCircleIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
5+
import { capitalizeFirstLetter } from "@app/utils/utils";
6+
import { ExclamationTriangleIcon } from "@patternfly/react-icons";
7+
import { type TrustRootKind } from "../../data/TrustRoots.data";
8+
import TrustRootNotFound from "../TrustRootNotFound";
9+
10+
export interface TrustRootCertificateTabProps {
11+
trustRoot?: TrustRootKind;
12+
}
13+
14+
const TrustRootCertificateTab: React.FC<TrustRootCertificateTabProps> = ({ trustRoot }) => {
15+
return trustRoot ? (
16+
<>
17+
<Pagination itemCount={trustRoot.certificates.length} perPage={10} page={1} variant="top" />
18+
<Table variant="compact">
19+
<Thead>
20+
<Tr>
21+
<Th>Subject</Th>
22+
<Th>Issuer</Th>
23+
<Th>Type</Th>
24+
<Th>Status</Th>
25+
</Tr>
26+
</Thead>
27+
<Tbody>
28+
{trustRoot.certificates.map((cert, idx) => (
29+
<Tr key={idx}>
30+
<Td>{cert.subject}</Td>
31+
<Td>{cert.issuer}</Td>
32+
<Td>{cert.type}</Td>
33+
<Td>
34+
<Flex spaceItems={{ default: "spaceItemsSm" }}>
35+
<FlexItem>
36+
{cert.status === "valid" ? (
37+
<Icon status="success">
38+
<CheckCircleIcon />
39+
</Icon>
40+
) : (
41+
<Icon status="warning">
42+
<ExclamationTriangleIcon />
43+
</Icon>
44+
)}{" "}
45+
{capitalizeFirstLetter(cert.status)}
46+
</FlexItem>
47+
</Flex>
48+
</Td>
49+
</Tr>
50+
))}
51+
</Tbody>
52+
</Table>
53+
<Pagination itemCount={trustRoot.certificates.length} perPage={10} page={1} variant="bottom" />
54+
</>
55+
) : (
56+
<TrustRootNotFound />
57+
);
58+
};
59+
60+
export default TrustRootCertificateTab;
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import {
2+
Button,
3+
DescriptionList,
4+
DescriptionListDescription,
5+
DescriptionListGroup,
6+
DescriptionListTermHelpText,
7+
DescriptionListTermHelpTextButton,
8+
PageSection,
9+
Popover,
10+
} from "@patternfly/react-core";
11+
12+
import PlusCircleIcon from "@patternfly/react-icons/dist/esm/icons/plus-circle-icon";
13+
import { formatDate } from "@app/utils/utils";
14+
import TrustRootNotFound from "../TrustRootNotFound";
15+
import type { TrustRootKind } from "../../data/TrustRoots.data";
16+
17+
interface TrustRootInfoTabProps {
18+
trustRoot?: TrustRootKind;
19+
}
20+
21+
const TrustRootInfoTab: React.FC<TrustRootInfoTabProps> = ({ trustRoot }) => {
22+
return trustRoot ? (
23+
<>
24+
<PageSection>
25+
<DescriptionList>
26+
<DescriptionListGroup>
27+
<DescriptionListTermHelpText>
28+
<Popover headerContent={<div>ID</div>} bodyContent={<div>Additional info</div>}>
29+
<DescriptionListTermHelpTextButton> ID </DescriptionListTermHelpTextButton>
30+
</Popover>
31+
</DescriptionListTermHelpText>
32+
<DescriptionListDescription>{trustRoot.id}</DescriptionListDescription>
33+
</DescriptionListGroup>
34+
<DescriptionListGroup>
35+
<DescriptionListTermHelpText>
36+
<Popover headerContent={<div>Source</div>} bodyContent={<div>Additional source info</div>}>
37+
<DescriptionListTermHelpTextButton> Source </DescriptionListTermHelpTextButton>
38+
</Popover>
39+
</DescriptionListTermHelpText>
40+
<DescriptionListDescription>
41+
<a href="#">{trustRoot.source}</a>
42+
</DescriptionListDescription>
43+
</DescriptionListGroup>
44+
<DescriptionListGroup>
45+
<DescriptionListTermHelpText>
46+
<Popover headerContent={<div>Last Updated</div>} bodyContent={<div>Additional info</div>}>
47+
<DescriptionListTermHelpTextButton> Last Updated </DescriptionListTermHelpTextButton>
48+
</Popover>
49+
</DescriptionListTermHelpText>
50+
<DescriptionListDescription>{formatDate(trustRoot.lastUpdated)}</DescriptionListDescription>
51+
</DescriptionListGroup>
52+
<DescriptionListGroup>
53+
<DescriptionListTermHelpText>
54+
<Popover headerContent={<div>Type</div>} bodyContent={<div>Additional info</div>}>
55+
<DescriptionListTermHelpTextButton> Type </DescriptionListTermHelpTextButton>
56+
</Popover>
57+
</DescriptionListTermHelpText>
58+
<DescriptionListDescription>
59+
<Button variant="link" isInline icon={<PlusCircleIcon />}>
60+
{trustRoot.type}
61+
</Button>
62+
</DescriptionListDescription>
63+
</DescriptionListGroup>
64+
<DescriptionListGroup>
65+
<DescriptionListTermHelpText>
66+
<Popover headerContent={<div>Certificates</div>} bodyContent={<div>Additional info</div>}>
67+
<DescriptionListTermHelpTextButton> Certificates </DescriptionListTermHelpTextButton>
68+
</Popover>
69+
</DescriptionListTermHelpText>
70+
<DescriptionListDescription>{trustRoot.certificates.length} Certificate(s)</DescriptionListDescription>
71+
</DescriptionListGroup>
72+
<DescriptionListGroup>
73+
<DescriptionListTermHelpText>
74+
<Popover headerContent={<div>TUF Metadata</div>} bodyContent={<div>Additional info</div>}>
75+
<DescriptionListTermHelpTextButton> TUF Metadata </DescriptionListTermHelpTextButton>
76+
</Popover>
77+
</DescriptionListTermHelpText>
78+
<DescriptionListDescription>{trustRoot.tufMetadata.length} Metadata File(s)</DescriptionListDescription>
79+
</DescriptionListGroup>
80+
</DescriptionList>
81+
</PageSection>
82+
</>
83+
) : (
84+
<TrustRootNotFound />
85+
);
86+
};
87+
88+
export default TrustRootInfoTab;
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import * as React from "react";
2+
import { Button, Card, CardBody, CardFooter, CardTitle, Content, Flex, FlexItem, Icon } from "@patternfly/react-core";
3+
import CheckCircleIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
4+
import { capitalizeFirstLetter, formatDate } from "@app/utils/utils";
5+
import { ExclamationTriangleIcon, ExternalLinkAltIcon } from "@patternfly/react-icons";
6+
import { type TrustRootKind } from "../../data/TrustRoots.data";
7+
import TrustRootNotFound from "../TrustRootNotFound";
8+
9+
export interface TrustRootMetadataTabProps {
10+
trustRoot?: TrustRootKind;
11+
}
12+
13+
const TrustRootMetadataTab: React.FC<TrustRootMetadataTabProps> = ({ trustRoot }) => {
14+
if (!trustRoot?.tufMetadata || !Array.isArray(trustRoot.tufMetadata) || trustRoot.tufMetadata.length === 0) {
15+
return <TrustRootNotFound />;
16+
}
17+
const latestTUF = trustRoot?.tufMetadata[0];
18+
19+
return (
20+
<Card id="certificate-health" isPlain isFullHeight key="card-1">
21+
<CardTitle>
22+
<Content component="h3">TUF metadata</Content>
23+
</CardTitle>
24+
<CardBody>
25+
<Flex grow={{ default: "grow" }} spaceItems={{ default: "spaceItemsXl" }}>
26+
<Flex flex={{ default: "flex_1" }}>
27+
<Flex direction={{ default: "column" }} spaceItems={{ default: "spaceItemsLg" }}>
28+
<FlexItem>
29+
<Flex direction={{ default: "column" }}>
30+
<FlexItem>
31+
<Content component="h4">Status</Content>
32+
</FlexItem>
33+
<FlexItem>
34+
{latestTUF.status === "valid" ? (
35+
<Icon status="success">
36+
<CheckCircleIcon />
37+
</Icon>
38+
) : (
39+
<Icon status="warning">
40+
<ExclamationTriangleIcon />
41+
</Icon>
42+
)}{" "}
43+
{capitalizeFirstLetter(latestTUF.status)}
44+
</FlexItem>
45+
</Flex>
46+
</FlexItem>
47+
48+
<FlexItem>
49+
<Flex direction={{ default: "column" }}>
50+
<FlexItem>
51+
<Content component="h4">Version</Content>
52+
</FlexItem>
53+
<FlexItem>{latestTUF.version}</FlexItem>
54+
</Flex>
55+
</FlexItem>
56+
</Flex>
57+
</Flex>
58+
<Flex flex={{ default: "flex_1" }} align={{ default: "alignRight" }}>
59+
<Flex direction={{ default: "column" }} spaceItems={{ default: "spaceItemsLg" }}>
60+
<FlexItem>
61+
<FlexItem>
62+
<Flex direction={{ default: "column" }}>
63+
<FlexItem>
64+
<Content component="h4">Role</Content>
65+
</FlexItem>
66+
<FlexItem>{latestTUF.role}</FlexItem>
67+
</Flex>
68+
</FlexItem>
69+
</FlexItem>
70+
<Flex>
71+
<FlexItem align={{ default: "alignRight" }}>
72+
<FlexItem>
73+
<Flex direction={{ default: "column" }}>
74+
<FlexItem>
75+
<Content component="h4">Expires</Content>
76+
</FlexItem>
77+
<FlexItem>{formatDate(latestTUF.expires)}</FlexItem>
78+
</Flex>
79+
</FlexItem>
80+
</FlexItem>
81+
</Flex>
82+
</Flex>
83+
</Flex>
84+
</Flex>
85+
</CardBody>
86+
<CardFooter>
87+
<Button variant="link" isInline icon={<ExternalLinkAltIcon />}>
88+
See the trust root definition on store
89+
</Button>
90+
</CardFooter>
91+
</Card>
92+
);
93+
};
94+
95+
export default TrustRootMetadataTab;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Icon } from "@patternfly/react-core";
2+
import * as React from "react";
3+
import CheckCircleIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
4+
import TimesCircleIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon";
5+
import { MinusIcon } from "@patternfly/react-icons";
6+
7+
interface StatusIconProps {
8+
status: string;
9+
}
10+
11+
const StatusIcon: React.FC<StatusIconProps> = ({ status }) => {
12+
if (status === "success") {
13+
return (
14+
<Icon size="xl" status="success">
15+
<CheckCircleIcon />
16+
</Icon>
17+
);
18+
} else if (status === "error") {
19+
return (
20+
<Icon size="xl" status="danger">
21+
<TimesCircleIcon />
22+
</Icon>
23+
);
24+
} else {
25+
return (
26+
<Icon size="xl">
27+
<MinusIcon />
28+
</Icon>
29+
);
30+
}
31+
};
32+
33+
export default StatusIcon;

client/src/app/pages/TrustRoots/components/TrustRootAction.tsx

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { ErrorState } from "@patternfly/react-component-groups";
2+
3+
const TrustRootNotFound = () => {
4+
return <ErrorState title="Trust root not found" />;
5+
};
6+
7+
export default TrustRootNotFound;

0 commit comments

Comments
 (0)