diff --git a/apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/page.tsx b/apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/page.tsx index 7300fd6..06c1cf2 100644 --- a/apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/page.tsx +++ b/apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/page.tsx @@ -1,170 +1 @@ -import NotFoundPage from "@/app/not-found"; -import { ContentCard } from "@/components/ContentCard"; -import { CopyButton } from "@/components/CopyButton"; -import DEPRECATED_Typography from "@/components/core/Typography"; -import PageContent from "@/components/layout/PageContent"; -import { PageLoader } from "@/components/layout/PageLoader"; -import { TableRowItem } from "@/components/Table"; -import { TableCard } from "@/components/TableCard"; -import { completeDate } from "@/helpers/date"; -import { toTitleCase } from "@/helpers/string"; -import { useClientSDK } from "@/providers/ClientProvider"; -import { Icon, Tag, Typography, useModal } from "@keetanetwork/web-ui"; -import { useQuery$ } from "@preact-signals/query"; -import { Fragment } from "preact/jsx-runtime"; -import { twMerge } from "tailwind-merge"; -import { CertificatePemContent } from "./CertificatePemContent"; -import { ChainCertificateModal } from "./ChainCertificateModal"; -import { IconBoolean } from "./IconBoolean"; - -export default function CertificatePage({ params: { accountPublicKey, certificateHash } }: { params: { accountPublicKey: string, certificateHash: string }}) { - const sdk = useClientSDK(); - const { data, isError, isLoading } = useQuery$(() => ({ - queryKey: ['account', accountPublicKey, 'certificate', certificateHash], - queryFn: () => sdk.account.certificate(accountPublicKey, certificateHash), - })) - - const { openModal } = useModal(); - - if (isError) { - return(); - } - - if (!data || isLoading) { - return(); - } - - const { certificate } = data; - - return ( - -
-
- - - - Certificate - -
- -
-
- - {certificate.hash} - - -
- -
- - {certificate.issuerName} - -
-
-
- -
- {completeDate(certificate.expiresAt)}, type: "jsx" } - ), - { label: "Serial", value: `${certificate.serial.toString(16).toUpperCase()} (${certificate.serial.toString()})` }, - { label: "Trusted", value: , type: "jsx" }, - ]} - /> - - ({ - label: toTitleCase(item.name), - value: item.value, - }))} - /> - - ({ - label: toTitleCase(item.name), - value: item.value, - }))} - /> - - ({ - label: toTitleCase(item.name), - value: item.sensitive ? "********" : item.value, - }))} - /> - - {/* Chain of Trust */} - ( - - - - {/* - {middleSubstring(row.hash, 4)} - */} - {/* */} - - - {row.isSelfSigned ? ( - - {row.issuerName} - - - ) : ( - <> - - {row.issuerName} - - - {row.subjectName} - - - )} - - openModal()} className={"text-functional-focused"}>View - - - )} - /> - - {/* Certificate PEM Content */} - -
-
- ) -} +export { default } from "@/components/Certificate/page" diff --git a/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/CertificatePemContent.tsx b/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/CertificatePemContent.tsx deleted file mode 100644 index 1c8c652..0000000 --- a/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/CertificatePemContent.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { twMerge } from 'tailwind-merge'; - -import Icon from '@/components/core/Icon'; -import Typography from '@/components/core/Typography'; - -export function CertificatePemContent({ content }: { content: string }) { - return(
- Certificate PEM - -
- {content} -
-
-
-
-
- -
-
-
); -} diff --git a/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/ChainCertificateModal.tsx b/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/ChainCertificateModal.tsx deleted file mode 100644 index 744b087..0000000 --- a/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/ChainCertificateModal.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { ContentCard } from "@/components/ContentCard"; -import { completeDate } from "@/helpers/date"; -import { Button, Modal, ModalContent, ModalFooter, ModalHeader, useModal } from "@keetanetwork/web-ui"; -import { IconBoolean } from "./IconBoolean"; -import { toTitleCase } from "@/helpers/string"; -import { ExplorerClientSDK } from "@/libs/explorer-sdk"; - -type ChainCertificateModalProps = { - certificate: Awaited>['certificate']['chain'][number]; -}; - -export function ChainCertificateModal({ certificate }: ChainCertificateModalProps) { - const { closeModal } = useModal(); - return ( - - - - - , type: "jsx" }, - ]} - /> - - ({ - label: toTitleCase(item.name), - value: item.value, - }))} - /> - - ({ - label: toTitleCase(item.name), - value: item.value, - }))} - /> - - ({ - label: toTitleCase(item.name), - value: item.sensitive ? "********" : item.value, - }))} - /> - - - closeModal()}>Close} - /> - - ) -} diff --git a/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/IconBoolean.tsx b/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/IconBoolean.tsx deleted file mode 100644 index ce50d06..0000000 --- a/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/IconBoolean.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Icon } from "@keetanetwork/web-ui"; -import { twMerge } from "tailwind-merge"; - -export function IconBoolean({ value }: { value: boolean }) { - return ( - - ); -} diff --git a/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/page.tsx b/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/page.tsx index 7300fd6..06c1cf2 100644 --- a/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/page.tsx +++ b/apps/web/src/app/storage/[accountPublicKey]/certificate/[certificateHash]/page.tsx @@ -1,170 +1 @@ -import NotFoundPage from "@/app/not-found"; -import { ContentCard } from "@/components/ContentCard"; -import { CopyButton } from "@/components/CopyButton"; -import DEPRECATED_Typography from "@/components/core/Typography"; -import PageContent from "@/components/layout/PageContent"; -import { PageLoader } from "@/components/layout/PageLoader"; -import { TableRowItem } from "@/components/Table"; -import { TableCard } from "@/components/TableCard"; -import { completeDate } from "@/helpers/date"; -import { toTitleCase } from "@/helpers/string"; -import { useClientSDK } from "@/providers/ClientProvider"; -import { Icon, Tag, Typography, useModal } from "@keetanetwork/web-ui"; -import { useQuery$ } from "@preact-signals/query"; -import { Fragment } from "preact/jsx-runtime"; -import { twMerge } from "tailwind-merge"; -import { CertificatePemContent } from "./CertificatePemContent"; -import { ChainCertificateModal } from "./ChainCertificateModal"; -import { IconBoolean } from "./IconBoolean"; - -export default function CertificatePage({ params: { accountPublicKey, certificateHash } }: { params: { accountPublicKey: string, certificateHash: string }}) { - const sdk = useClientSDK(); - const { data, isError, isLoading } = useQuery$(() => ({ - queryKey: ['account', accountPublicKey, 'certificate', certificateHash], - queryFn: () => sdk.account.certificate(accountPublicKey, certificateHash), - })) - - const { openModal } = useModal(); - - if (isError) { - return(); - } - - if (!data || isLoading) { - return(); - } - - const { certificate } = data; - - return ( - -
-
- - - - Certificate - -
- -
-
- - {certificate.hash} - - -
- -
- - {certificate.issuerName} - -
-
-
- -
- {completeDate(certificate.expiresAt)}, type: "jsx" } - ), - { label: "Serial", value: `${certificate.serial.toString(16).toUpperCase()} (${certificate.serial.toString()})` }, - { label: "Trusted", value: , type: "jsx" }, - ]} - /> - - ({ - label: toTitleCase(item.name), - value: item.value, - }))} - /> - - ({ - label: toTitleCase(item.name), - value: item.value, - }))} - /> - - ({ - label: toTitleCase(item.name), - value: item.sensitive ? "********" : item.value, - }))} - /> - - {/* Chain of Trust */} - ( - - - - {/* - {middleSubstring(row.hash, 4)} - */} - {/* */} - - - {row.isSelfSigned ? ( - - {row.issuerName} - - - ) : ( - <> - - {row.issuerName} - - - {row.subjectName} - - - )} - - openModal()} className={"text-functional-focused"}>View - - - )} - /> - - {/* Certificate PEM Content */} - -
-
- ) -} +export { default } from "@/components/Certificate/page" diff --git a/apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/CertificatePemContent.tsx b/apps/web/src/components/Certificate/CertificatePemContent.tsx similarity index 100% rename from apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/CertificatePemContent.tsx rename to apps/web/src/components/Certificate/CertificatePemContent.tsx diff --git a/apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/ChainCertificateModal.tsx b/apps/web/src/components/Certificate/ChainCertificateModal.tsx similarity index 83% rename from apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/ChainCertificateModal.tsx rename to apps/web/src/components/Certificate/ChainCertificateModal.tsx index 744b087..6241e75 100644 --- a/apps/web/src/app/account/[accountPublicKey]/certificate/[certificateHash]/ChainCertificateModal.tsx +++ b/apps/web/src/components/Certificate/ChainCertificateModal.tsx @@ -3,7 +3,8 @@ import { completeDate } from "@/helpers/date"; import { Button, Modal, ModalContent, ModalFooter, ModalHeader, useModal } from "@keetanetwork/web-ui"; import { IconBoolean } from "./IconBoolean"; import { toTitleCase } from "@/helpers/string"; -import { ExplorerClientSDK } from "@/libs/explorer-sdk"; +import type { ExplorerClientSDK } from "@/libs/explorer-sdk"; +import { CardContainer } from "@/components/CardContainer"; type ChainCertificateModalProps = { certificate: Awaited>['certificate']['chain'][number]; @@ -23,7 +24,7 @@ export function ChainCertificateModal({ certificate }: ChainCertificateModalProp content={[ { label: "Issuer", value: certificate.issuerName }, { label: "Subject", value: certificate.subjectName }, - { label: "Is Self-Signed", value: certificate.isSelfSigned ? "Yes" : "No" }, + { label: "Is Root", value: certificate.isSelfSigned ? : undefined, type: "jsx" }, { label: "Issued At", value: completeDate(certificate.issuedAt) }, { label: certificate.valid ? "Valid Until" : "Expired On", value: completeDate(certificate.expiresAt) }, { label: "Serial", value: `${certificate.serial.toString(16).toUpperCase()} (${certificate.serial.toString()})` }, @@ -57,6 +58,10 @@ export function ChainCertificateModal({ certificate }: ChainCertificateModalProp value: item.sensitive ? "********" : item.value, }))} /> + + + {certificate.pem} + ({ + queryKey: ['account', accountPublicKey, 'certificate', certificateHash], + queryFn: () => sdk.account.certificate(accountPublicKey, certificateHash), + })) + + const { openModal } = useModal(); + + if (isError) { + return(); + } + + if (!data || isLoading) { + return(); + } + + const { certificate } = data; + + return ( + +
+
+ + + + Certificate + +
+ +
+
+ + {certificate.hash} + + +
+ +
+ + {certificate.issuerName} + +
+
+
+ +
+ {completeDate(certificate.expiresAt)}, type: "jsx" } + ), + { label: "Serial", value: `${certificate.serial.toString(16).toUpperCase()} (${certificate.serial.toString()})` }, + { label: "Trusted", value: , type: "jsx" }, + ]} + /> + + ({ + label: toTitleCase(item.name), + value: item.value, + }))} + /> + + ({ + label: toTitleCase(item.name), + value: item.value, + }))} + /> + + ({ + label: toTitleCase(item.name), + value: item.sensitive ? "********" : item.value, + }))} + /> + + {/* Chain of Trust */} + ( + + + + {/* + {middleSubstring(row.hash, 4)} + */} + {/* */} + + + {row.isSelfSigned ? ( + + {row.issuerName} + + + ) : ( + <> + + {row.issuerName} + + + {row.subjectName} + + + )} + + openModal()} className={"text-functional-focused"}>View + + + )} + /> + + {/* Certificate PEM Content */} + +
+
+ ) +} diff --git a/apps/web/src/components/ContentCard.tsx b/apps/web/src/components/ContentCard.tsx index 63e8ddc..2880796 100644 --- a/apps/web/src/components/ContentCard.tsx +++ b/apps/web/src/components/ContentCard.tsx @@ -1,11 +1,11 @@ import { Typography } from "@keetanetwork/web-ui"; import { TextAccountLink } from "./TextAccountLink"; -import { NonNullableProps } from "@/utils/types"; -import { CardContainer, CardContainerProps } from "./CardContainer"; +import type { NonNullableProps } from "@/utils/types"; +import { CardContainer, type CardContainerProps } from "./CardContainer"; import { twMerge } from "tailwind-merge"; import { TextBlockLink } from "./TextBlockLink"; import { completeDate, completeDay } from "@/helpers/date"; -import { VNode } from "preact"; +import type { VNode } from "preact"; type ContentItemType = "text" | "account" | "block" | "datetime" | "date" | "jsx"; @@ -37,14 +37,14 @@ interface ContentItemDatetime extends ContentItemBase { interface ContentItemJSX extends ContentItemBase { type: Extract; - value: VNode; + value: VNode | undefined; } export type ContentItem = ContentItemText | ContentItemAccount | ContentItemBlock | ContentItemDatetime | ContentItemJSX; interface ContentCardProps extends CardContainerProps { content: ContentItem[] -}; +} /** * Utility function to check if a value is valid diff --git a/apps/web/src/libs/explorer-sdk.ts b/apps/web/src/libs/explorer-sdk.ts index 8bfcd2e..e4ea31a 100644 --- a/apps/web/src/libs/explorer-sdk.ts +++ b/apps/web/src/libs/explorer-sdk.ts @@ -74,6 +74,7 @@ function certificateToAPIResponse(certificate: Anchor.lib.Certificates.Certifica issuerDN: certificate.issuerDN, subjectDN: certificate.subjectDN, attributes, + pem: certificate.toPEM(), }) as const; } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index a440be6..6de2410 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "explorer", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { @@ -16,7 +16,7 @@ "node": ">=20.18.0", "npm": ">=9.8.1" }, - "version": "0.1.0" + "version": "0.1.1" }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.4", diff --git a/package.json b/package.json index 8b348fb..f353874 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "explorer", - "version": "0.1.0", + "version": "0.1.1", "description": "", "author": "Keeta Token Genesis LLC", "private": true,