Skip to content

Commit ce33df3

Browse files
fix: separated ArtifactSignatureItem component
1 parent 19e6a4b commit ce33df3

File tree

3 files changed

+252
-333
lines changed

3 files changed

+252
-333
lines changed

client/src/app/pages/Artifacts/components/ArtifactResults.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export interface IArtifactResultsProps {
1919

2020
export const ArtifactResults = ({ artifact }: IArtifactResultsProps) => {
2121
// temporary workaround until API merged
22-
const artifactSignatures: string[] = [];
22+
const artifactSignatures: string[] = ["a", "b"];
2323

2424
return (
2525
<div style={{ margin: "2em auto" }}>

client/src/app/pages/Artifacts/components/ArtifactResultsSignatures.tsx

Lines changed: 6 additions & 332 deletions
Original file line numberDiff line numberDiff line change
@@ -1,344 +1,18 @@
1-
import {
2-
Content,
3-
ContentVariants,
4-
DataList,
5-
DataListItem,
6-
DataListItemRow,
7-
DataListToggle,
8-
DataListItemCells,
9-
DataListCell,
10-
ClipboardCopy,
11-
DataListAction,
12-
Dropdown,
13-
type MenuToggleElement,
14-
MenuToggle,
15-
DropdownList,
16-
DropdownItem,
17-
DataListContent,
18-
CodeBlock,
19-
CodeBlockCode,
20-
Panel,
21-
TreeView,
22-
ClipboardCopyButton,
23-
CodeBlockAction,
24-
type TreeViewDataItem,
25-
} from "@patternfly/react-core";
26-
import { EllipsisVIcon } from "@patternfly/react-icons";
27-
import { Fragment, useState, type MouseEvent } from "react";
1+
import { Content, ContentVariants, DataList } from "@patternfly/react-core";
2+
import { ArtifactSignatureItem } from "./ArtifactSignatureItem";
283

294
export const ArtifactResultsSignatures = ({ signatures }: { signatures: string[] }) => {
30-
const [activeItems, setActiveItems] = useState<TreeViewDataItem[]>();
31-
const [sigDropdownOpen, setSigDropdownOpen] = useState<Record<string, boolean>>({});
32-
const [expanded, setExpanded] = useState(["ex-toggle1", "ex-toggle3"]);
33-
345
console.table(signatures);
356

36-
const onSelectCertChain = (_event: MouseEvent, treeViewItem: TreeViewDataItem) => {
37-
// ignore folders for selection
38-
if (treeViewItem && !treeViewItem.children) {
39-
setActiveItems([treeViewItem]);
40-
}
41-
};
42-
43-
const setSigDropdownState = (id: string, isOpen: boolean) => {
44-
setSigDropdownOpen((prev) => ({ ...prev, [id]: isOpen }));
45-
};
46-
47-
const handleOpenSigDropdown = (id: string) => (isOpen: boolean) => {
48-
setSigDropdownState(id, isOpen);
49-
};
50-
51-
const handleToggleClick = (id: string) => () => {
52-
setSigDropdownState(id, !(sigDropdownOpen[id] ?? false));
53-
};
54-
55-
const handleSelect = (id: string) => () => {
56-
setSigDropdownState(id, false);
57-
};
58-
59-
const toggle = (id: string) => {
60-
const index = expanded.indexOf(id);
61-
const newExpanded =
62-
index >= 0 ? [...expanded.slice(0, index), ...expanded.slice(index + 1, expanded.length)] : [...expanded, id];
63-
setExpanded(newExpanded);
64-
};
65-
66-
const options = [
67-
{
68-
name: "Leaf Certificate [Valid ✓] [Copy PEM] [Download] [View X.509 fields]",
69-
id: "example1-AppLaunch",
70-
children: [
71-
{
72-
name: "Subject",
73-
id: "example1-App1",
74-
children: [
75-
{ name: "Settings", id: "example1-App1Settings" },
76-
{ name: "Current", id: "example1-App1Current" },
77-
],
78-
},
79-
{
80-
name: "Extensions",
81-
id: "example1-App2",
82-
children: [
83-
{ name: "Settings", id: "example1-App2Settings" },
84-
{
85-
name: "Loader",
86-
id: "example1-App2Loader",
87-
children: [
88-
{ name: "Loading App 1", id: "example1-LoadApp1" },
89-
{ name: "Loading App 2", id: "example1-LoadApp2" },
90-
{ name: "Loading App 3", id: "example1-LoadApp3" },
91-
],
92-
},
93-
],
94-
},
95-
],
96-
defaultExpanded: true,
97-
},
98-
{
99-
name: "Intermediate A",
100-
id: "example1-Cost",
101-
children: [
102-
{
103-
name: "Authority Key ID",
104-
id: "example1-App3",
105-
children: [
106-
{ name: "Settings", id: "example1-App3Settings" },
107-
{ name: "Current", id: "example1-App3Current" },
108-
],
109-
},
110-
],
111-
},
112-
{
113-
name: "Root (Trust Anchor)",
114-
id: "example1-Sources",
115-
children: [
116-
{ name: "Application 4", id: "example1-App4", children: [{ name: "Settings", id: "example1-App4Settings" }] },
117-
],
118-
},
119-
];
120-
121-
// DIGEST CODE BLOCKS
122-
const [copied, setCopied] = useState(false);
123-
124-
const clipboardCopyFunc = (text: { toString: () => string }) => {
125-
void navigator.clipboard.writeText(text.toString());
126-
};
127-
128-
const onClick = (text: string) => {
129-
clipboardCopyFunc(text);
130-
setCopied(true);
131-
};
132-
133-
const code = String.raw`data:
134-
Serial Number: '0x0639cb6e52987006777bb9395de0f08eb09e2ae0'
135-
Signature:
136-
Issuer: O=sigstore.dev, CN=sigstore-intermediate
137-
Validity:
138-
Not Before: 4 months ago (2025-07-05T13:00:17+01:00)
139-
Not After: 4 months ago (2025-07-05T13:10:17+01:00)
140-
Algorithm:
141-
name: ECDSA
142-
namedCurve: P-256
143-
Subject:
144-
extraNames:
145-
items: {}
146-
asn: []
147-
X509v3 extensions:
148-
Key Usage (critical):
149-
- Digital Signature
150-
Extended Key Usage:
151-
- Code Signing
152-
Subject Key Identifier:
153-
- 47:61:F5:AE:1B:97:1C:DF:8E:70:97:BD:08:55:CB:6A:CE:79:80:02
154-
Authority Key Identifier:
155-
keyid: DF:D3:E9:CF:56:24:11:96:F9:A8:D8:E9:28:55:A2:C6:2E:18:64:3F
156-
Subject Alternative Name (critical):
157-
email:
158-
159-
OIDC Issuer: https://login.microsoftonline.com
160-
OIDC Issuer (v2): https://login.microsoftonline.com
161-
1.3.6.1.4.1.11129.2.4.2: 04:7b:00:79:00:77:00:dd:3d:30:6a:c6:c7:11:32:63:19:1e:1c:99:67:37:02:a2:4a:5e:b8:de:3c:ad:ff:87:8a:72:80:2f:29:ee:8e:00:00:01:97:da:75:6c:62:00:00:04:03:00:48:30:46:02:21:00:b1:c8:00:32:6d:71:4d:f2:8e:a6:b9:8f:81:99:4e:5a:48:65:72:94:85:ff:14:6f:6e:e0:50:c9:f2:aa:f8:da:02:21:00:95:58:65:f6:1b:c6:77:00:3d:9f:d4:98:a6:43:93:6e:1b:59:4c:b9:b9:85:41:28:3b:da:a3:9a:3f:fb:b5:0b
162-
163-
`;
164-
165-
const codeBlockActions = (
166-
<Fragment>
167-
<CodeBlockAction>
168-
<ClipboardCopyButton
169-
id="basic-copy-button"
170-
textId="code-content"
171-
aria-label="Copy to clipboard"
172-
onClick={() => onClick(code)}
173-
exitDelay={copied ? 1500 : 600}
174-
maxWidth="110px"
175-
variant="plain"
176-
onTooltipHidden={() => setCopied(false)}
177-
>
178-
{copied ? "Successfully copied to clipboard!" : "Copy to clipboard"}
179-
</ClipboardCopyButton>
180-
</CodeBlockAction>
181-
</Fragment>
182-
);
1837
return (
1848
<>
1859
<Content component={ContentVariants.h6} style={{ margin: "2em auto 1.5em", overflowY: "hidden" }}>
18610
Signatures
18711
</Content>
188-
<DataList aria-label="Compact data list example" isCompact>
189-
<DataListItem aria-labelledby="ex-item1" key="sig-1" isExpanded={expanded.includes("ex-toggle1")}>
190-
<DataListItemRow>
191-
<DataListToggle
192-
onClick={() => toggle("ex-toggle1")}
193-
isExpanded={expanded.includes("ex-toggle1")}
194-
id="ex-toggle1"
195-
aria-controls="ex-expand1"
196-
/>
197-
<DataListItemCells
198-
dataListCells={[
199-
<DataListCell key="identity">
200-
<span id="compact-item1">[email protected]</span>
201-
</DataListCell>,
202-
<DataListCell key="digest">
203-
<ClipboardCopy hoverTip="Copy" clickTip="Copied" variant="inline-compact" isCode>
204-
sha256:77db
205-
</ClipboardCopy>
206-
</DataListCell>,
207-
<DataListCell key="signatureType">hashedrekord</DataListCell>,
208-
<DataListCell key="integratedTime">4 months ago </DataListCell>,
209-
<DataListCell key="verificationStatus">Signature ✓ / Rekor ✓ / Chain ✓</DataListCell>,
210-
]}
211-
/>
212-
<DataListAction aria-labelledby="ex-item1 ex-action1" id="ex-action1" aria-label="Actions">
213-
<Dropdown
214-
popperProps={{ position: "right" }}
215-
onSelect={handleSelect("sig-1")}
216-
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
217-
<MenuToggle
218-
ref={toggleRef}
219-
isExpanded={sigDropdownOpen["sig-1"] ?? false}
220-
onClick={handleToggleClick("sig-1")}
221-
variant="plain"
222-
aria-label="Data list exapndable example kebaby toggle 1"
223-
icon={<EllipsisVIcon />}
224-
/>
225-
)}
226-
isOpen={sigDropdownOpen["sig-1"] ?? false}
227-
onOpenChange={handleOpenSigDropdown("sig-1")}
228-
>
229-
<DropdownList>
230-
<DropdownItem key="link" to="#" onClick={(event: MouseEvent) => event.preventDefault()}>
231-
Open in Rekor Search
232-
</DropdownItem>
233-
<DropdownItem key="disabled action" isDisabled>
234-
Download Bundle
235-
</DropdownItem>
236-
</DropdownList>
237-
</Dropdown>
238-
</DataListAction>
239-
</DataListItemRow>
240-
<DataListContent
241-
aria-label="First expandable content details"
242-
id="ex-expand1"
243-
isHidden={!expanded.includes("ex-toggle1")}
244-
>
245-
<CodeBlock actions={codeBlockActions}>
246-
<CodeBlockCode id="code-content">{code}</CodeBlockCode>
247-
</CodeBlock>
248-
<Panel>
249-
<Content component={ContentVariants.h6} style={{ margin: "1em auto" }}>
250-
Certificate Chain
251-
</Content>
252-
<TreeView
253-
hasAnimations
254-
hasGuides
255-
aria-label="Certificate chain"
256-
data={options}
257-
activeItems={activeItems}
258-
onSelect={onSelectCertChain}
259-
/>
260-
</Panel>
261-
<Panel>
262-
<Content component={ContentVariants.h6} style={{ margin: "1em auto" }}>
263-
Attestations
264-
</Content>
265-
</Panel>
266-
<Panel>
267-
<Content component={ContentVariants.h6} style={{ margin: "1em auto" }}>
268-
Rekor Entry
269-
</Content>
270-
<CodeBlock>
271-
<CodeBlockCode id="code-content">{String.raw`Entry #128904331 (UUID abcd…1234)`}</CodeBlockCode>
272-
</CodeBlock>
273-
</Panel>
274-
</DataListContent>
275-
</DataListItem>
276-
<DataListItem aria-labelledby="ex-item2" isExpanded={expanded.includes("ex-toggle2")}>
277-
<DataListItemRow>
278-
<DataListToggle
279-
onClick={() => toggle("ex-toggle2")}
280-
isExpanded={expanded.includes("ex-toggle2")}
281-
id="ex-toggle2"
282-
aria-controls="ex-expand2"
283-
/>
284-
<DataListItemCells
285-
dataListCells={[
286-
<DataListCell isFilled={false} key="secondary content fill">
287-
<span id="ex-item2">[email protected]</span>
288-
</DataListCell>,
289-
<DataListCell isFilled={false} alignRight key="secondary content align">
290-
{" "}
291-
</DataListCell>,
292-
]}
293-
/>
294-
<DataListAction aria-labelledby="ex-item2 ex-action2" id="ex-action2" aria-label="Actions">
295-
<Dropdown
296-
popperProps={{ position: "right" }}
297-
onSelect={handleSelect("sig-2")}
298-
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
299-
<MenuToggle
300-
ref={toggleRef}
301-
isExpanded={sigDropdownOpen["sig-2"] ?? false}
302-
onClick={handleToggleClick("sig-2")}
303-
variant="plain"
304-
aria-label="Data list exapndable example kebaby toggle 2"
305-
icon={<EllipsisVIcon />}
306-
/>
307-
)}
308-
isOpen={sigDropdownOpen["sig-2"] ?? false}
309-
onOpenChange={handleOpenSigDropdown("sig-2")}
310-
>
311-
<DropdownList>
312-
<DropdownItem key="action2">Action</DropdownItem>
313-
<DropdownItem key="link2" to="#" onClick={(event: MouseEvent) => event.preventDefault()}>
314-
Link
315-
</DropdownItem>
316-
<DropdownItem key="disabled action2" isDisabled>
317-
Disabled Action
318-
</DropdownItem>
319-
<DropdownItem
320-
key="disabled link2"
321-
isDisabled
322-
to="#"
323-
onClick={(event: MouseEvent) => event.preventDefault()}
324-
>
325-
Disabled Link
326-
</DropdownItem>
327-
</DropdownList>
328-
</Dropdown>
329-
</DataListAction>
330-
</DataListItemRow>
331-
<DataListContent
332-
aria-label="Second expandable content details"
333-
id="ex-expand2"
334-
isHidden={!expanded.includes("ex-toggle2")}
335-
>
336-
<p>
337-
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
338-
dolore magna aliqua.
339-
</p>
340-
</DataListContent>
341-
</DataListItem>
12+
<DataList aria-label="Signatures list" isCompact>
13+
{signatures.map((signature, id) => (
14+
<ArtifactSignatureItem signature={signature} key={id} />
15+
))}
34216
</DataList>
34317
</>
34418
);

0 commit comments

Comments
 (0)