@burdenoff/microfe-vibecontrols 2026.521.3 → 2026.522.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/VibeControlsRoot.js +86 -78
- package/dist/VibeControlsRoot.js.map +1 -1
- package/dist/VibeControlsRoutes.js +168 -125
- package/dist/VibeControlsRoutes.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerBookmarksDrawer.js +174 -0
- package/dist/components/agent-manager/AgentManagerBookmarksDrawer.js.map +1 -0
- package/dist/components/agent-manager/AgentManagerChatPane.js +149 -94
- package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerMessageItem.js +52 -41
- package/dist/components/agent-manager/AgentManagerMessageItem.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerMessageList.js +22 -15
- package/dist/components/agent-manager/AgentManagerMessageList.js.map +1 -1
- package/dist/components/agents/OpenInEditorMenu.js +241 -0
- package/dist/components/agents/OpenInEditorMenu.js.map +1 -0
- package/dist/components/agents/VibeOpenInEditorMenu.js +20 -0
- package/dist/components/agents/VibeOpenInEditorMenu.js.map +1 -0
- package/dist/components/agents/idePresets.js +148 -0
- package/dist/components/agents/idePresets.js.map +1 -0
- package/dist/components/agents/index.js +3 -0
- package/dist/components/ai/AIPlanPanel.js +332 -0
- package/dist/components/ai/AIPlanPanel.js.map +1 -0
- package/dist/components/analytics/index.js +2 -2
- package/dist/components/assistant/AssistantMessageItem.js +55 -47
- package/dist/components/assistant/AssistantMessageItem.js.map +1 -1
- package/dist/components/audit/AuditExportButton.js +87 -41
- package/dist/components/audit/AuditExportButton.js.map +1 -1
- package/dist/components/gitops/CIDurationChart.js +11 -11
- package/dist/components/security/SecurityEmptyState.js +33 -0
- package/dist/components/security/SecurityEmptyState.js.map +1 -0
- package/dist/components/security/SecurityEvidenceList.js +42 -0
- package/dist/components/security/SecurityEvidenceList.js.map +1 -0
- package/dist/components/security/SecurityFindingsTable.js +201 -0
- package/dist/components/security/SecurityFindingsTable.js.map +1 -0
- package/dist/components/security/SecurityHeaderStrip.js +67 -0
- package/dist/components/security/SecurityHeaderStrip.js.map +1 -0
- package/dist/components/security/SecurityLifecycleStepper.js +66 -0
- package/dist/components/security/SecurityLifecycleStepper.js.map +1 -0
- package/dist/components/security/SecurityProviderDrawer.js +112 -0
- package/dist/components/security/SecurityProviderDrawer.js.map +1 -0
- package/dist/components/security/SecurityTabPanel.js +105 -0
- package/dist/components/security/SecurityTabPanel.js.map +1 -0
- package/dist/components/security/gql.js +128 -0
- package/dist/components/security/gql.js.map +1 -0
- package/dist/components/security/index.js +8 -0
- package/dist/components/security/types.js +80 -0
- package/dist/components/security/types.js.map +1 -0
- package/dist/components/settings/IdePreferencesSection.js +66 -0
- package/dist/components/settings/IdePreferencesSection.js.map +1 -0
- package/dist/components/shared/PageSkeleton.js +88 -0
- package/dist/components/shared/PageSkeleton.js.map +1 -0
- package/dist/constants/pluginCatalog.js +20 -8
- package/dist/constants/pluginCatalog.js.map +1 -1
- package/dist/generated/wspace-operations.js +1350 -1262
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/hooks/useToggleAgentBookmark.js +32 -0
- package/dist/hooks/useToggleAgentBookmark.js.map +1 -0
- package/dist/index.js +10 -10
- package/dist/pages/AgentDetailsPage.js +25 -25
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +326 -327
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/AnalyticsPage.js +425 -420
- package/dist/pages/AnalyticsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +258 -249
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/CatalogPage.js +22 -22
- package/dist/pages/CatalogPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +30 -30
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/ComponentsPage.js +23 -23
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/LogsPage.js +107 -0
- package/dist/pages/LogsPage.js.map +1 -0
- package/dist/pages/NoteDetailsPage.js +12 -12
- package/dist/pages/NoteDetailsPage.js.map +1 -1
- package/dist/pages/SessionDetailsPage.js +12 -12
- package/dist/pages/SessionDetailsPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +158 -136
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/SettingsPage.js +60 -52
- package/dist/pages/SettingsPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +18 -18
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +328 -331
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +17 -17
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/TemplatesPage.js +17 -17
- package/dist/pages/TemplatesPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +552 -535
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/VibesPage.js +321 -296
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/ai/AIBookmarksPage.js +184 -0
- package/dist/pages/ai/AIBookmarksPage.js.map +1 -0
- package/dist/pages/ai/AIPage.js +138 -109
- package/dist/pages/ai/AIPage.js.map +1 -1
- package/dist/services/planApi.js +18 -0
- package/dist/services/planApi.js.map +1 -0
- package/dist/store/vibeControlsStore.js +20 -2
- package/dist/store/vibeControlsStore.js.map +1 -1
- package/dist/translations/en.js +30 -1
- package/dist/translations/en.js.map +1 -1
- package/package.json +4 -4
|
@@ -2,83 +2,91 @@ import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
|
2
2
|
import { downloadAssistantArtifact as t } from "../../services/assistantApi.js";
|
|
3
3
|
import { AssistantMarkdownRenderer as n } from "./AssistantMarkdownRenderer.js";
|
|
4
4
|
import { useMemo as r, useState as i } from "react";
|
|
5
|
-
import { Bot as a,
|
|
6
|
-
import { useGatewayClient as
|
|
7
|
-
import { useAuthToken as
|
|
8
|
-
import { jsx as
|
|
5
|
+
import { Bot as a, User as o } from "lucide-react";
|
|
6
|
+
import { useGatewayClient as s } from "@burdenoff/fe-libs/shared/graphql";
|
|
7
|
+
import { useAuthToken as c } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
8
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
9
|
+
import { SaveToFilesButton as d } from "@burdenoff/fe-libs/storage";
|
|
9
10
|
//#region src/components/assistant/AssistantMessageItem.tsx
|
|
10
|
-
function
|
|
11
|
+
function f(e) {
|
|
11
12
|
return e.role === "assistant" ? e.metadata : void 0;
|
|
12
13
|
}
|
|
13
|
-
function
|
|
14
|
+
function p(e) {
|
|
14
15
|
return e?.artifacts ?? [];
|
|
15
16
|
}
|
|
16
|
-
function
|
|
17
|
+
function m(e) {
|
|
17
18
|
return window.atob(e);
|
|
18
19
|
}
|
|
19
|
-
function
|
|
20
|
-
let r =
|
|
20
|
+
function h(e, t, n) {
|
|
21
|
+
let r = m(e), i = new Uint8Array(r.length);
|
|
21
22
|
for (let e = 0; e < r.length; e += 1) i[e] = r.charCodeAt(e);
|
|
22
23
|
let a = new Blob([i], { type: n }), o = URL.createObjectURL(a), s = document.createElement("a");
|
|
23
24
|
s.href = o, s.download = t, document.body.appendChild(s), s.click(), document.body.removeChild(s), URL.revokeObjectURL(o);
|
|
24
25
|
}
|
|
25
|
-
var
|
|
26
|
-
let
|
|
27
|
-
if (!
|
|
26
|
+
var g = ({ message: m, isStreaming: g }) => {
|
|
27
|
+
let _ = e(), v = s("workspace"), { getAccessToken: y, getWorkspaceToken: b } = c(), [x, S] = i(null), C = m.role === "user", w = r(() => f(m), [m]), T = r(() => p(w), [w]), E = async (e) => {
|
|
28
|
+
if (!w?.sandboxId || !w.sessionId) return;
|
|
28
29
|
let n = new URLSearchParams(window.location.search).get("workspace") ?? "";
|
|
29
30
|
if (n) {
|
|
30
|
-
|
|
31
|
+
S(e.path);
|
|
31
32
|
try {
|
|
32
|
-
let r = await t(
|
|
33
|
-
accessToken:
|
|
34
|
-
workspaceToken:
|
|
33
|
+
let r = await t(v, w.sandboxId, n, w.sessionId, e.path, {
|
|
34
|
+
accessToken: y(),
|
|
35
|
+
workspaceToken: b()
|
|
35
36
|
});
|
|
36
|
-
|
|
37
|
+
h(r.contentBase64, r.filename, r.mimeType);
|
|
37
38
|
} finally {
|
|
38
|
-
|
|
39
|
+
S(null);
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
};
|
|
42
|
-
return /* @__PURE__ */
|
|
43
|
-
className: `flex gap-2.5 ${
|
|
44
|
-
children: [/* @__PURE__ */
|
|
45
|
-
className: `flex-shrink-0 w-6 h-6 rounded-full flex items-center justify-center mt-0.5 ${
|
|
46
|
-
children:
|
|
47
|
-
}), /* @__PURE__ */
|
|
48
|
-
className: `max-w-[85%] rounded-lg px-3 py-2 ${
|
|
43
|
+
return /* @__PURE__ */ u("div", {
|
|
44
|
+
className: `flex gap-2.5 ${C ? "flex-row-reverse" : "flex-row"}`,
|
|
45
|
+
children: [/* @__PURE__ */ l("div", {
|
|
46
|
+
className: `flex-shrink-0 w-6 h-6 rounded-full flex items-center justify-center mt-0.5 ${C ? "bg-action-primary-bg" : "bg-bg-elevated border border-border-default"}`,
|
|
47
|
+
children: C ? /* @__PURE__ */ l(o, { className: "w-3.5 h-3.5 text-action-primary-text" }) : /* @__PURE__ */ l(a, { className: "w-3.5 h-3.5 text-text-secondary" })
|
|
48
|
+
}), /* @__PURE__ */ u("div", {
|
|
49
|
+
className: `max-w-[85%] rounded-lg px-3 py-2 ${C ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-elevated border border-border-subtle"}`,
|
|
49
50
|
children: [
|
|
50
|
-
|
|
51
|
+
C ? /* @__PURE__ */ l("p", {
|
|
51
52
|
className: "text-xs whitespace-pre-wrap leading-relaxed",
|
|
52
|
-
children:
|
|
53
|
-
}) : /* @__PURE__ */
|
|
54
|
-
|
|
53
|
+
children: m.content
|
|
54
|
+
}) : /* @__PURE__ */ l(n, { content: m.content }),
|
|
55
|
+
T.length > 0 && !C && w?.sandboxId && w.sessionId && /* @__PURE__ */ u("div", {
|
|
55
56
|
className: "mt-3 space-y-2 border-t border-border-subtle pt-2",
|
|
56
|
-
children: [/* @__PURE__ */
|
|
57
|
+
children: [/* @__PURE__ */ l("p", {
|
|
57
58
|
className: "text-[10px] font-medium uppercase tracking-wide text-text-muted",
|
|
58
|
-
children:
|
|
59
|
-
}), /* @__PURE__ */
|
|
59
|
+
children: _("vibecontrols.assistant.message.downloads", "Downloads")
|
|
60
|
+
}), /* @__PURE__ */ l("div", {
|
|
60
61
|
className: "flex flex-wrap gap-2",
|
|
61
|
-
children:
|
|
62
|
-
let t =
|
|
63
|
-
return /* @__PURE__ */
|
|
64
|
-
|
|
65
|
-
disabled:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
children: T.map((e) => {
|
|
63
|
+
let t = `${e.name}${e.type === "directory" ? ".tar.gz" : ""}`;
|
|
64
|
+
return /* @__PURE__ */ l(d, {
|
|
65
|
+
label: t,
|
|
66
|
+
disabled: x === e.path,
|
|
67
|
+
testId: `assistant-artifact-${e.name}`,
|
|
68
|
+
source: {
|
|
69
|
+
kind: "sandbox-artifact",
|
|
70
|
+
sandboxId: w.sandboxId,
|
|
71
|
+
sessionId: w.sessionId,
|
|
72
|
+
path: e.path,
|
|
73
|
+
filename: t
|
|
74
|
+
},
|
|
75
|
+
defaultFolderPath: "/Vibecontrols/AI Assistant/Artifacts",
|
|
76
|
+
onDownload: () => E(e)
|
|
69
77
|
}, e.path);
|
|
70
78
|
})
|
|
71
79
|
})]
|
|
72
80
|
}),
|
|
73
|
-
|
|
74
|
-
/* @__PURE__ */
|
|
75
|
-
className: `text-[10px] mt-1 ${
|
|
76
|
-
children: [new Date(
|
|
81
|
+
g && !C && /* @__PURE__ */ l("span", { className: "inline-block w-1.5 h-3.5 bg-text-secondary animate-pulse ml-0.5 align-middle rounded-sm" }),
|
|
82
|
+
/* @__PURE__ */ u("div", {
|
|
83
|
+
className: `text-[10px] mt-1 ${C ? "text-action-primary-text/60" : "text-text-muted"}`,
|
|
84
|
+
children: [new Date(m.timestamp).toLocaleTimeString([], {
|
|
77
85
|
hour: "2-digit",
|
|
78
86
|
minute: "2-digit"
|
|
79
|
-
}),
|
|
87
|
+
}), m.tokens && !C && /* @__PURE__ */ u("span", {
|
|
80
88
|
className: "ml-2",
|
|
81
|
-
children: [
|
|
89
|
+
children: [m.tokens.input + m.tokens.output, " tokens"]
|
|
82
90
|
})]
|
|
83
91
|
})
|
|
84
92
|
]
|
|
@@ -86,6 +94,6 @@ var _ = ({ message: h, isStreaming: _ }) => {
|
|
|
86
94
|
});
|
|
87
95
|
};
|
|
88
96
|
//#endregion
|
|
89
|
-
export {
|
|
97
|
+
export { g as AssistantMessageItem };
|
|
90
98
|
|
|
91
99
|
//# sourceMappingURL=AssistantMessageItem.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantMessageItem.js","names":[],"sources":["../../../src/components/assistant/AssistantMessageItem.tsx"],"sourcesContent":["import { useMemo, useState, type FC } from 'react';\nimport { Bot,
|
|
1
|
+
{"version":3,"file":"AssistantMessageItem.js","names":[],"sources":["../../../src/components/assistant/AssistantMessageItem.tsx"],"sourcesContent":["import { useMemo, useState, type FC } from 'react';\nimport { Bot, User } from 'lucide-react';\nimport { useGatewayClient } from '@burdenoff/fe-libs/shared/graphql';\nimport { useAuthToken } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { SaveToFilesButton } from '@burdenoff/fe-libs/storage';\nimport { AssistantMarkdownRenderer } from './AssistantMarkdownRenderer';\nimport { downloadAssistantArtifact } from '@/services/assistantApi';\nimport type { AssistantArtifact, AssistantMessageMetadata, Message } from '@/types/assistant';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface Props {\n message: Message;\n isStreaming?: boolean;\n}\n\nfunction getAssistantMetadata(message: Message): AssistantMessageMetadata | undefined {\n return message.role === 'assistant' ? message.metadata : undefined;\n}\n\nfunction getArtifacts(metadata: AssistantMessageMetadata | undefined): AssistantArtifact[] {\n return metadata?.artifacts ?? [];\n}\n\nfunction decodeBase64(base64: string): string {\n return window.atob(base64);\n}\n\nfunction downloadBase64File(base64: string, filename: string, mimeType: string): void {\n const binary = decodeBase64(base64);\n const bytes = new Uint8Array(binary.length);\n\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n\n const blob = new Blob([bytes], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n\nexport const AssistantMessageItem: FC<Props> = ({ message, isStreaming }) => {\n const tr = useTr();\n const apollo = useGatewayClient('workspace');\n const { getAccessToken, getWorkspaceToken } = useAuthToken();\n const [downloadingArtifactPath, setDownloadingArtifactPath] = useState<string | null>(null);\n const isUser = message.role === 'user';\n const metadata = useMemo(() => getAssistantMetadata(message), [message]);\n const artifacts = useMemo(() => getArtifacts(metadata), [metadata]);\n\n const handleArtifactDownload = async (artifact: AssistantArtifact) => {\n if (!metadata?.sandboxId || !metadata.sessionId) return;\n\n const workspaceId = new URLSearchParams(window.location.search).get('workspace') ?? '';\n if (!workspaceId) return;\n\n setDownloadingArtifactPath(artifact.path);\n\n try {\n const result = await downloadAssistantArtifact(\n apollo,\n metadata.sandboxId,\n workspaceId,\n metadata.sessionId,\n artifact.path,\n {\n accessToken: getAccessToken(),\n workspaceToken: getWorkspaceToken(),\n }\n );\n\n downloadBase64File(result.contentBase64, result.filename, result.mimeType);\n } finally {\n setDownloadingArtifactPath(null);\n }\n };\n\n return (\n <div className={`flex gap-2.5 ${isUser ? 'flex-row-reverse' : 'flex-row'}`}>\n <div\n className={`flex-shrink-0 w-6 h-6 rounded-full flex items-center justify-center mt-0.5 ${\n isUser ? 'bg-action-primary-bg' : 'bg-bg-elevated border border-border-default'\n }`}\n >\n {isUser ? (\n <User className=\"w-3.5 h-3.5 text-action-primary-text\" />\n ) : (\n <Bot className=\"w-3.5 h-3.5 text-text-secondary\" />\n )}\n </div>\n\n <div\n className={`max-w-[85%] rounded-lg px-3 py-2 ${\n isUser\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-elevated border border-border-subtle'\n }`}\n >\n {isUser ? (\n <p className=\"text-xs whitespace-pre-wrap leading-relaxed\">{message.content}</p>\n ) : (\n <AssistantMarkdownRenderer content={message.content} />\n )}\n\n {artifacts.length > 0 && !isUser && metadata?.sandboxId && metadata.sessionId && (\n <div className=\"mt-3 space-y-2 border-t border-border-subtle pt-2\">\n <p className=\"text-[10px] font-medium uppercase tracking-wide text-text-muted\">\n {tr('vibecontrols.assistant.message.downloads', 'Downloads')}\n </p>\n <div className=\"flex flex-wrap gap-2\">\n {artifacts.map((artifact) => {\n const displayName = `${artifact.name}${artifact.type === 'directory' ? '.tar.gz' : ''}`;\n const isDownloading = downloadingArtifactPath === artifact.path;\n return (\n <SaveToFilesButton\n key={artifact.path}\n label={displayName}\n disabled={isDownloading}\n testId={`assistant-artifact-${artifact.name}`}\n source={{\n kind: 'sandbox-artifact',\n sandboxId: metadata.sandboxId!,\n sessionId: metadata.sessionId!,\n path: artifact.path,\n filename: displayName,\n }}\n defaultFolderPath=\"/Vibecontrols/AI Assistant/Artifacts\"\n onDownload={() => handleArtifactDownload(artifact)}\n />\n );\n })}\n </div>\n </div>\n )}\n\n {isStreaming && !isUser && (\n <span className=\"inline-block w-1.5 h-3.5 bg-text-secondary animate-pulse ml-0.5 align-middle rounded-sm\" />\n )}\n\n <div\n className={`text-[10px] mt-1 ${\n isUser ? 'text-action-primary-text/60' : 'text-text-muted'\n }`}\n >\n {new Date(message.timestamp).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n })}\n {message.tokens && !isUser && (\n <span className=\"ml-2\">{message.tokens.input + message.tokens.output} tokens</span>\n )}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -2,30 +2,31 @@ import { useExportVibeAuditLogsMutation as e } from "../../generated/wspace-oper
|
|
|
2
2
|
import { VibeAuditExportFormat as t } from "../../generated/wspace-types.js";
|
|
3
3
|
import { useEffect as n, useRef as r, useState as i } from "react";
|
|
4
4
|
import { useI18n as a } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
5
|
-
import { Download as o } from "lucide-react";
|
|
6
|
-
import { jsx as
|
|
5
|
+
import { Download as o, FolderInput as s } from "lucide-react";
|
|
6
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
7
|
+
import { SaveToFilesDialog as u } from "@burdenoff/fe-libs/storage";
|
|
7
8
|
//#region src/components/audit/AuditExportButton.tsx
|
|
8
|
-
function
|
|
9
|
-
let { t:
|
|
10
|
-
let n =
|
|
9
|
+
function d({ filter: d }) {
|
|
10
|
+
let { t: f } = a(), p = r(null), [m, h] = i(!1), [g, _] = i(null), [v, { loading: y }] = e(), b = (e, t) => {
|
|
11
|
+
let n = f(e);
|
|
11
12
|
return n === e ? t : n;
|
|
12
13
|
};
|
|
13
14
|
n(() => {
|
|
14
|
-
if (!
|
|
15
|
+
if (!m) return;
|
|
15
16
|
let e = (e) => {
|
|
16
|
-
|
|
17
|
+
p.current?.contains(e.target) || h(!1);
|
|
17
18
|
}, t = (e) => {
|
|
18
|
-
e.key === "Escape" &&
|
|
19
|
+
e.key === "Escape" && h(!1);
|
|
19
20
|
};
|
|
20
21
|
return window.addEventListener("mousedown", e), window.addEventListener("keydown", t), () => {
|
|
21
22
|
window.removeEventListener("mousedown", e), window.removeEventListener("keydown", t);
|
|
22
23
|
};
|
|
23
|
-
}, [
|
|
24
|
-
let
|
|
25
|
-
|
|
24
|
+
}, [m]);
|
|
25
|
+
let x = async (e) => {
|
|
26
|
+
h(!1);
|
|
26
27
|
try {
|
|
27
|
-
let t = (await
|
|
28
|
-
filter:
|
|
28
|
+
let t = (await v({ variables: { input: {
|
|
29
|
+
filter: d || {},
|
|
29
30
|
format: e
|
|
30
31
|
} } })).data?.exportVibeAuditLogs;
|
|
31
32
|
if (!t) return;
|
|
@@ -33,38 +34,83 @@ function l({ filter: l }) {
|
|
|
33
34
|
i.href = r, i.download = `vibe-audit-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.${e.toLowerCase()}`, document.body.appendChild(i), i.click(), document.body.removeChild(i), URL.revokeObjectURL(r);
|
|
34
35
|
} catch {}
|
|
35
36
|
};
|
|
36
|
-
return /* @__PURE__ */
|
|
37
|
-
ref:
|
|
37
|
+
return /* @__PURE__ */ l("div", {
|
|
38
|
+
ref: p,
|
|
38
39
|
className: "relative",
|
|
39
|
-
children: [
|
|
40
|
-
|
|
41
|
-
"aria-haspopup": "menu",
|
|
42
|
-
"aria-expanded": f,
|
|
43
|
-
onClick: () => p((e) => !e),
|
|
44
|
-
disabled: h,
|
|
45
|
-
className: "inline-flex items-center gap-2 rounded-lg border border-border-primary px-3 py-2 text-sm transition-colors hover:bg-bg-secondary disabled:opacity-50",
|
|
46
|
-
children: [/* @__PURE__ */ s(o, { size: 14 }), h ? g("audit.exporting", "Exporting…") : g("audit.export", "Export")]
|
|
47
|
-
}), f ? /* @__PURE__ */ c("div", {
|
|
48
|
-
role: "menu",
|
|
49
|
-
"aria-label": g("audit.exportOptions", "Export options"),
|
|
50
|
-
className: "absolute right-0 top-full z-10 mt-1 min-w-[140px] rounded-lg border border-border-default bg-bg-surface py-1 shadow-lg",
|
|
51
|
-
children: [/* @__PURE__ */ s("button", {
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ l("button", {
|
|
52
42
|
type: "button",
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
43
|
+
"aria-haspopup": "menu",
|
|
44
|
+
"aria-expanded": m,
|
|
45
|
+
onClick: () => h((e) => !e),
|
|
46
|
+
disabled: y,
|
|
47
|
+
className: "inline-flex items-center gap-2 rounded-lg border border-border-primary px-3 py-2 text-sm transition-colors hover:bg-bg-secondary disabled:opacity-50",
|
|
48
|
+
children: [/* @__PURE__ */ c(o, { size: 14 }), y ? b("audit.exporting", "Exporting…") : b("audit.export", "Export")]
|
|
49
|
+
}),
|
|
50
|
+
m ? /* @__PURE__ */ l("div", {
|
|
51
|
+
role: "menu",
|
|
52
|
+
"aria-label": b("audit.exportOptions", "Export options"),
|
|
53
|
+
className: "absolute right-0 top-full z-10 mt-1 min-w-[200px] rounded-lg border border-border-default bg-bg-surface py-1 shadow-lg",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ l("button", {
|
|
56
|
+
type: "button",
|
|
57
|
+
role: "menuitem",
|
|
58
|
+
onClick: () => x(t.Csv),
|
|
59
|
+
className: "flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors hover:bg-bg-secondary",
|
|
60
|
+
children: [/* @__PURE__ */ c(o, { size: 12 }), b("audit.exportCsv", "Download CSV")]
|
|
61
|
+
}),
|
|
62
|
+
/* @__PURE__ */ l("button", {
|
|
63
|
+
type: "button",
|
|
64
|
+
role: "menuitem",
|
|
65
|
+
onClick: () => x(t.Json),
|
|
66
|
+
className: "flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors hover:bg-bg-secondary",
|
|
67
|
+
children: [/* @__PURE__ */ c(o, { size: 12 }), b("audit.exportJson", "Download JSON")]
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ c("div", { className: "my-1 border-t border-border-subtle" }),
|
|
70
|
+
/* @__PURE__ */ l("button", {
|
|
71
|
+
type: "button",
|
|
72
|
+
role: "menuitem",
|
|
73
|
+
onClick: () => {
|
|
74
|
+
h(!1), _(t.Csv);
|
|
75
|
+
},
|
|
76
|
+
className: "flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors hover:bg-bg-secondary",
|
|
77
|
+
children: [/* @__PURE__ */ c(s, { size: 12 }), b("audit.saveCsvToFiles", "Save CSV to Files…")]
|
|
78
|
+
}),
|
|
79
|
+
/* @__PURE__ */ l("button", {
|
|
80
|
+
type: "button",
|
|
81
|
+
role: "menuitem",
|
|
82
|
+
onClick: () => {
|
|
83
|
+
h(!1), _(t.Json);
|
|
84
|
+
},
|
|
85
|
+
className: "flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors hover:bg-bg-secondary",
|
|
86
|
+
children: [/* @__PURE__ */ c(s, { size: 12 }), b("audit.saveJsonToFiles", "Save JSON to Files…")]
|
|
87
|
+
})
|
|
88
|
+
]
|
|
89
|
+
}) : null,
|
|
90
|
+
g && /* @__PURE__ */ c(u, {
|
|
91
|
+
open: !0,
|
|
92
|
+
onOpenChange: (e) => {
|
|
93
|
+
e || _(null);
|
|
94
|
+
},
|
|
95
|
+
defaultFolderPath: "/Vibecontrols/Audit Logs",
|
|
96
|
+
filename: `vibe-audit-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.${g.toLowerCase()}`,
|
|
97
|
+
source: {
|
|
98
|
+
kind: "blob",
|
|
99
|
+
filename: `vibe-audit-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.${g.toLowerCase()}`,
|
|
100
|
+
mimeType: g === t.Csv ? "text/csv" : "application/json",
|
|
101
|
+
getBlob: async () => {
|
|
102
|
+
let e = (await v({ variables: { input: {
|
|
103
|
+
filter: d || {},
|
|
104
|
+
format: g
|
|
105
|
+
} } })).data?.exportVibeAuditLogs?.data;
|
|
106
|
+
return e ? { blob: new Blob([e], { type: g === t.Csv ? "text/csv" : "application/json" }) } : null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
]
|
|
65
111
|
});
|
|
66
112
|
}
|
|
67
113
|
//#endregion
|
|
68
|
-
export {
|
|
114
|
+
export { d as AuditExportButton };
|
|
69
115
|
|
|
70
116
|
//# sourceMappingURL=AuditExportButton.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuditExportButton.js","names":[],"sources":["../../../src/components/audit/AuditExportButton.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { Download } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useExportVibeAuditLogsMutation } from '@/generated/wspace-operations';\nimport { VibeAuditExportFormat, type VibeAuditLogFilterInput } from '@/generated/wspace-types';\n\ninterface AuditExportButtonProps {\n filter?: VibeAuditLogFilterInput;\n}\n\nexport function AuditExportButton({ filter }: AuditExportButtonProps) {\n const { t } = useI18n();\n const menuRef = useRef<HTMLDivElement | null>(null);\n const [showMenu, setShowMenu] = useState(false);\n const [exportMutation, { loading }] = useExportVibeAuditLogsMutation();\n\n const tr = (key: string, fallback: string) => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n useEffect(() => {\n if (!showMenu) return undefined;\n\n const handlePointerDown = (event: MouseEvent) => {\n if (!menuRef.current?.contains(event.target as Node)) {\n setShowMenu(false);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setShowMenu(false);\n }\n };\n\n window.addEventListener('mousedown', handlePointerDown);\n window.addEventListener('keydown', handleKeyDown);\n return () => {\n window.removeEventListener('mousedown', handlePointerDown);\n window.removeEventListener('keydown', handleKeyDown);\n };\n }, [showMenu]);\n\n const handleExport = async (format: VibeAuditExportFormat) => {\n setShowMenu(false);\n try {\n const result = await exportMutation({\n variables: {\n input: { filter: filter || {}, format },\n },\n });\n\n const exportData = result.data?.exportVibeAuditLogs;\n if (!exportData) return;\n\n const blob = new Blob([exportData.data], {\n type: format === 'CSV' ? 'text/csv' : 'application/json',\n });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `vibe-audit-${new Date().toISOString().slice(0, 10)}.${format.toLowerCase()}`;\n document.body.appendChild(anchor);\n anchor.click();\n document.body.removeChild(anchor);\n URL.revokeObjectURL(url);\n } catch {\n // Apollo error handling surfaces failures globally.\n }\n };\n\n return (\n <div ref={menuRef} className=\"relative\">\n <button\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-expanded={showMenu}\n onClick={() => setShowMenu((current) => !current)}\n disabled={loading}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-primary px-3 py-2 text-sm transition-colors hover:bg-bg-secondary disabled:opacity-50\"\n >\n <Download size={14} />\n {loading ? tr('audit.exporting', 'Exporting…') : tr('audit.export', 'Export')}\n </button>\n\n {showMenu ? (\n <div\n role=\"menu\"\n aria-label={tr('audit.exportOptions', 'Export options')}\n className=\"absolute right-0 top-full z-10 mt-1 min-w-[
|
|
1
|
+
{"version":3,"file":"AuditExportButton.js","names":[],"sources":["../../../src/components/audit/AuditExportButton.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { Download, FolderInput } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { SaveToFilesDialog } from '@burdenoff/fe-libs/storage';\nimport { useExportVibeAuditLogsMutation } from '@/generated/wspace-operations';\nimport { VibeAuditExportFormat, type VibeAuditLogFilterInput } from '@/generated/wspace-types';\n\ninterface AuditExportButtonProps {\n filter?: VibeAuditLogFilterInput;\n}\n\nexport function AuditExportButton({ filter }: AuditExportButtonProps) {\n const { t } = useI18n();\n const menuRef = useRef<HTMLDivElement | null>(null);\n const [showMenu, setShowMenu] = useState(false);\n const [saveFormat, setSaveFormat] = useState<VibeAuditExportFormat | null>(null);\n const [exportMutation, { loading }] = useExportVibeAuditLogsMutation();\n\n const tr = (key: string, fallback: string) => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n useEffect(() => {\n if (!showMenu) return undefined;\n\n const handlePointerDown = (event: MouseEvent) => {\n if (!menuRef.current?.contains(event.target as Node)) {\n setShowMenu(false);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setShowMenu(false);\n }\n };\n\n window.addEventListener('mousedown', handlePointerDown);\n window.addEventListener('keydown', handleKeyDown);\n return () => {\n window.removeEventListener('mousedown', handlePointerDown);\n window.removeEventListener('keydown', handleKeyDown);\n };\n }, [showMenu]);\n\n const handleExport = async (format: VibeAuditExportFormat) => {\n setShowMenu(false);\n try {\n const result = await exportMutation({\n variables: {\n input: { filter: filter || {}, format },\n },\n });\n\n const exportData = result.data?.exportVibeAuditLogs;\n if (!exportData) return;\n\n const blob = new Blob([exportData.data], {\n type: format === 'CSV' ? 'text/csv' : 'application/json',\n });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement('a');\n anchor.href = url;\n anchor.download = `vibe-audit-${new Date().toISOString().slice(0, 10)}.${format.toLowerCase()}`;\n document.body.appendChild(anchor);\n anchor.click();\n document.body.removeChild(anchor);\n URL.revokeObjectURL(url);\n } catch {\n // Apollo error handling surfaces failures globally.\n }\n };\n\n return (\n <div ref={menuRef} className=\"relative\">\n <button\n type=\"button\"\n aria-haspopup=\"menu\"\n aria-expanded={showMenu}\n onClick={() => setShowMenu((current) => !current)}\n disabled={loading}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-primary px-3 py-2 text-sm transition-colors hover:bg-bg-secondary disabled:opacity-50\"\n >\n <Download size={14} />\n {loading ? tr('audit.exporting', 'Exporting…') : tr('audit.export', 'Export')}\n </button>\n\n {showMenu ? (\n <div\n role=\"menu\"\n aria-label={tr('audit.exportOptions', 'Export options')}\n className=\"absolute right-0 top-full z-10 mt-1 min-w-[200px] rounded-lg border border-border-default bg-bg-surface py-1 shadow-lg\"\n >\n <button\n type=\"button\"\n role=\"menuitem\"\n onClick={() => handleExport(VibeAuditExportFormat.Csv)}\n className=\"flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors hover:bg-bg-secondary\"\n >\n <Download size={12} />\n {tr('audit.exportCsv', 'Download CSV')}\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n onClick={() => handleExport(VibeAuditExportFormat.Json)}\n className=\"flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors hover:bg-bg-secondary\"\n >\n <Download size={12} />\n {tr('audit.exportJson', 'Download JSON')}\n </button>\n <div className=\"my-1 border-t border-border-subtle\" />\n <button\n type=\"button\"\n role=\"menuitem\"\n onClick={() => {\n setShowMenu(false);\n setSaveFormat(VibeAuditExportFormat.Csv);\n }}\n className=\"flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors hover:bg-bg-secondary\"\n >\n <FolderInput size={12} />\n {tr('audit.saveCsvToFiles', 'Save CSV to Files…')}\n </button>\n <button\n type=\"button\"\n role=\"menuitem\"\n onClick={() => {\n setShowMenu(false);\n setSaveFormat(VibeAuditExportFormat.Json);\n }}\n className=\"flex w-full items-center gap-2 px-4 py-2 text-left text-sm transition-colors hover:bg-bg-secondary\"\n >\n <FolderInput size={12} />\n {tr('audit.saveJsonToFiles', 'Save JSON to Files…')}\n </button>\n </div>\n ) : null}\n\n {saveFormat && (\n <SaveToFilesDialog\n open\n onOpenChange={(open: boolean) => {\n if (!open) setSaveFormat(null);\n }}\n defaultFolderPath=\"/Vibecontrols/Audit Logs\"\n filename={`vibe-audit-${new Date().toISOString().slice(0, 10)}.${saveFormat.toLowerCase()}`}\n source={{\n kind: 'blob',\n filename: `vibe-audit-${new Date().toISOString().slice(0, 10)}.${saveFormat.toLowerCase()}`,\n mimeType: saveFormat === VibeAuditExportFormat.Csv ? 'text/csv' : 'application/json',\n getBlob: async () => {\n const result = await exportMutation({\n variables: { input: { filter: filter || {}, format: saveFormat } },\n });\n const data = result.data?.exportVibeAuditLogs?.data;\n if (!data) return null;\n return {\n blob: new Blob([data], {\n type: saveFormat === VibeAuditExportFormat.Csv ? 'text/csv' : 'application/json',\n }),\n };\n },\n }}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { Tooltip as t } from "../../node_modules/recharts/es6/component/Tooltip.js";
|
|
3
|
+
import { ResponsiveContainer as n } from "../../node_modules/recharts/es6/component/ResponsiveContainer.js";
|
|
4
|
+
import { Area as r } from "../../node_modules/recharts/es6/cartesian/Area.js";
|
|
5
|
+
import { AreaChart as i } from "../../node_modules/recharts/es6/chart/AreaChart.js";
|
|
6
|
+
import { formatDuration as a } from "../../utils/relativeTime.js";
|
|
7
7
|
import { useMemo as o } from "react";
|
|
8
8
|
import { Timer as s } from "lucide-react";
|
|
9
9
|
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
@@ -35,7 +35,7 @@ var u = "var(--color-text-link)", d = ({ averageDuration: d }) => {
|
|
|
35
35
|
className: "mb-3",
|
|
36
36
|
children: [/* @__PURE__ */ c("p", {
|
|
37
37
|
className: "text-3xl font-bold text-text-primary",
|
|
38
|
-
children:
|
|
38
|
+
children: a(d)
|
|
39
39
|
}), /* @__PURE__ */ c("p", {
|
|
40
40
|
className: "text-xs text-text-secondary mt-0.5",
|
|
41
41
|
children: f("vibecontrols.gitops.ciTab.perPipelineRun", "per pipeline run")
|
|
@@ -43,10 +43,10 @@ var u = "var(--color-text-link)", d = ({ averageDuration: d }) => {
|
|
|
43
43
|
}),
|
|
44
44
|
/* @__PURE__ */ c("div", {
|
|
45
45
|
className: "h-16",
|
|
46
|
-
children: /* @__PURE__ */ c(
|
|
46
|
+
children: /* @__PURE__ */ c(n, {
|
|
47
47
|
width: "100%",
|
|
48
48
|
height: "100%",
|
|
49
|
-
children: /* @__PURE__ */ l(
|
|
49
|
+
children: /* @__PURE__ */ l(i, {
|
|
50
50
|
data: p,
|
|
51
51
|
margin: {
|
|
52
52
|
top: 0,
|
|
@@ -71,17 +71,17 @@ var u = "var(--color-text-link)", d = ({ averageDuration: d }) => {
|
|
|
71
71
|
stopOpacity: 0
|
|
72
72
|
})]
|
|
73
73
|
}) }),
|
|
74
|
-
/* @__PURE__ */ c(
|
|
74
|
+
/* @__PURE__ */ c(t, {
|
|
75
75
|
contentStyle: {
|
|
76
76
|
background: "var(--color-bg-surface)",
|
|
77
77
|
border: "1px solid var(--color-border-default)",
|
|
78
78
|
borderRadius: "6px",
|
|
79
79
|
fontSize: "11px"
|
|
80
80
|
},
|
|
81
|
-
formatter: (e) => [
|
|
81
|
+
formatter: (e) => [a(Math.round(e)), "Duration"],
|
|
82
82
|
labelFormatter: () => ""
|
|
83
83
|
}),
|
|
84
|
-
/* @__PURE__ */ c(
|
|
84
|
+
/* @__PURE__ */ c(r, {
|
|
85
85
|
type: "monotone",
|
|
86
86
|
dataKey: "v",
|
|
87
87
|
stroke: u,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import "react";
|
|
2
|
+
import { Shield as e } from "lucide-react";
|
|
3
|
+
import { jsx as t, jsxs as n } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/security/SecurityEmptyState.tsx
|
|
5
|
+
function r({ onConfigureProviders: r }) {
|
|
6
|
+
return /* @__PURE__ */ n("div", {
|
|
7
|
+
"data-testid": "security-empty-state",
|
|
8
|
+
className: "flex flex-col items-center justify-center gap-3 p-8 rounded-md border border-dashed border-border-default bg-bg-sunken text-center",
|
|
9
|
+
children: [
|
|
10
|
+
/* @__PURE__ */ t(e, {
|
|
11
|
+
className: "h-8 w-8 text-text-tertiary",
|
|
12
|
+
"aria-hidden": "true"
|
|
13
|
+
}),
|
|
14
|
+
/* @__PURE__ */ n("div", { children: [/* @__PURE__ */ t("h3", {
|
|
15
|
+
className: "text-sm font-semibold text-text-primary",
|
|
16
|
+
children: "No scans yet"
|
|
17
|
+
}), /* @__PURE__ */ t("p", {
|
|
18
|
+
className: "text-xs text-text-secondary mt-1",
|
|
19
|
+
children: "Configure a security provider per stage to begin orchestrating scans."
|
|
20
|
+
})] }),
|
|
21
|
+
/* @__PURE__ */ t("button", {
|
|
22
|
+
type: "button",
|
|
23
|
+
onClick: r,
|
|
24
|
+
className: "px-3 py-1.5 rounded-md bg-action-primary-bg text-action-primary-text text-xs font-medium",
|
|
25
|
+
children: "Configure providers"
|
|
26
|
+
})
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { r as SecurityEmptyState };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=SecurityEmptyState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SecurityEmptyState.js","names":[],"sources":["../../../src/components/security/SecurityEmptyState.tsx"],"sourcesContent":["import React from 'react';\nimport { Shield } from 'lucide-react';\n\ninterface Props {\n onConfigureProviders: () => void;\n}\n\nexport function SecurityEmptyState({ onConfigureProviders }: Props): React.ReactElement {\n return (\n <div\n data-testid=\"security-empty-state\"\n className=\"flex flex-col items-center justify-center gap-3 p-8 rounded-md border border-dashed border-border-default bg-bg-sunken text-center\"\n >\n <Shield className=\"h-8 w-8 text-text-tertiary\" aria-hidden=\"true\" />\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary\">No scans yet</h3>\n <p className=\"text-xs text-text-secondary mt-1\">\n Configure a security provider per stage to begin orchestrating scans.\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onConfigureProviders}\n className=\"px-3 py-1.5 rounded-md bg-action-primary-bg text-action-primary-text text-xs font-medium\"\n >\n Configure providers\n </button>\n </div>\n );\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAmB,EAAE,2BAAmD;AACtF,QACE,kBAAC,OAAD;EACE,eAAY;EACZ,WAAU;YAFZ;GAIE,kBAAC,GAAD;IAAQ,WAAU;IAA6B,eAAY;IAAS,CAAA;GACpE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cAA0C;IAAiB,CAAA,EACzE,kBAAC,KAAD;IAAG,WAAU;cAAmC;IAE5C,CAAA,CACA,EAAA,CAAA;GACN,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,WAAU;cACX;IAEQ,CAAA;GACL"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import "react";
|
|
2
|
+
import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
3
|
+
//#region src/components/security/SecurityEvidenceList.tsx
|
|
4
|
+
var n = {
|
|
5
|
+
SARIF: "SARIF report",
|
|
6
|
+
SBOM_CYCLONEDX: "CycloneDX SBOM",
|
|
7
|
+
SBOM_SPDX: "SPDX SBOM",
|
|
8
|
+
GRYPE_JSON: "Grype scan JSON",
|
|
9
|
+
COSIGN_BUNDLE: "Cosign bundle",
|
|
10
|
+
PROVENANCE: "SLSA provenance",
|
|
11
|
+
OPA_DECISION: "OPA decision"
|
|
12
|
+
};
|
|
13
|
+
function r({ evidence: r }) {
|
|
14
|
+
return r.length === 0 ? /* @__PURE__ */ e("p", {
|
|
15
|
+
className: "text-xs text-text-secondary",
|
|
16
|
+
children: "No evidence artifacts yet."
|
|
17
|
+
}) : /* @__PURE__ */ e("div", {
|
|
18
|
+
"data-testid": "security-evidence-list",
|
|
19
|
+
className: "space-y-1",
|
|
20
|
+
children: r.map((r) => /* @__PURE__ */ t("a", {
|
|
21
|
+
href: r.downloadUrl ?? "#",
|
|
22
|
+
className: "block px-3 py-2 rounded-md border border-border-subtle hover:border-border-default hover:bg-bg-sunken text-sm text-action-primary-bg hover:underline",
|
|
23
|
+
children: [/* @__PURE__ */ t("div", {
|
|
24
|
+
className: "flex items-center justify-between gap-2",
|
|
25
|
+
children: [/* @__PURE__ */ e("span", { children: n[r.type] ?? r.type }), /* @__PURE__ */ e("span", {
|
|
26
|
+
className: "text-xs text-text-tertiary",
|
|
27
|
+
children: i(r.sizeBytes)
|
|
28
|
+
})]
|
|
29
|
+
}), /* @__PURE__ */ t("div", {
|
|
30
|
+
className: "text-xs text-text-tertiary font-mono truncate",
|
|
31
|
+
children: [r.sha256.slice(0, 16), "…"]
|
|
32
|
+
})]
|
|
33
|
+
}, r.id))
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function i(e) {
|
|
37
|
+
return e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(1)} KB` : `${(e / 1024 / 1024).toFixed(1)} MB`;
|
|
38
|
+
}
|
|
39
|
+
//#endregion
|
|
40
|
+
export { r as SecurityEvidenceList };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=SecurityEvidenceList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SecurityEvidenceList.js","names":[],"sources":["../../../src/components/security/SecurityEvidenceList.tsx"],"sourcesContent":["import React from 'react';\nimport type { SecurityEvidenceRow } from './types';\n\ninterface Props {\n evidence: SecurityEvidenceRow[];\n}\n\nconst TYPE_LABEL: Record<string, string> = {\n SARIF: 'SARIF report',\n SBOM_CYCLONEDX: 'CycloneDX SBOM',\n SBOM_SPDX: 'SPDX SBOM',\n GRYPE_JSON: 'Grype scan JSON',\n COSIGN_BUNDLE: 'Cosign bundle',\n PROVENANCE: 'SLSA provenance',\n OPA_DECISION: 'OPA decision',\n};\n\nexport function SecurityEvidenceList({ evidence }: Props): React.ReactElement {\n if (evidence.length === 0) {\n return <p className=\"text-xs text-text-secondary\">No evidence artifacts yet.</p>;\n }\n return (\n <div data-testid=\"security-evidence-list\" className=\"space-y-1\">\n {evidence.map((e) => (\n <a\n key={e.id}\n href={e.downloadUrl ?? '#'}\n className=\"block px-3 py-2 rounded-md border border-border-subtle hover:border-border-default hover:bg-bg-sunken text-sm text-action-primary-bg hover:underline\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span>{TYPE_LABEL[e.type] ?? e.type}</span>\n <span className=\"text-xs text-text-tertiary\">{formatBytes(e.sizeBytes)}</span>\n </div>\n <div className=\"text-xs text-text-tertiary font-mono truncate\">\n {e.sha256.slice(0, 16)}…\n </div>\n </a>\n ))}\n </div>\n );\n}\n\nfunction formatBytes(b: number): string {\n if (b < 1024) return `${b} B`;\n if (b < 1024 * 1024) return `${(b / 1024).toFixed(1)} KB`;\n return `${(b / 1024 / 1024).toFixed(1)} MB`;\n}\n"],"mappings":";;;AAOA,IAAM,IAAqC;CACzC,OAAO;CACP,gBAAgB;CAChB,WAAW;CACX,YAAY;CACZ,eAAe;CACf,YAAY;CACZ,cAAc;CACf;AAED,SAAgB,EAAqB,EAAE,eAAuC;AAI5E,QAHI,EAAS,WAAW,IACf,kBAAC,KAAD;EAAG,WAAU;YAA8B;EAA8B,CAAA,GAGhF,kBAAC,OAAD;EAAK,eAAY;EAAyB,WAAU;YACjD,EAAS,KAAK,MACb,kBAAC,KAAD;GAEE,MAAM,EAAE,eAAe;GACvB,WAAU;aAHZ,CAKE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD,EAAA,UAAO,EAAW,EAAE,SAAS,EAAE,MAAY,CAAA,EAC3C,kBAAC,QAAD;KAAM,WAAU;eAA8B,EAAY,EAAE,UAAU;KAAQ,CAAA,CAC1E;OACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAE,OAAO,MAAM,GAAG,GAAG,EAAC,IACnB;MACJ;KAXG,EAAE,GAWL,CACJ;EACE,CAAA;;AAIV,SAAS,EAAY,GAAmB;AAGtC,QAFI,IAAI,OAAa,GAAG,EAAE,MACtB,IAAI,OAAO,OAAa,IAAI,IAAI,MAAM,QAAQ,EAAE,CAAC,OAC9C,IAAI,IAAI,OAAO,MAAM,QAAQ,EAAE,CAAC"}
|