@burdenoff/microfe-vibecontrols 2026.527.15 → 2026.528.1
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/components/audit/AuditLogDetail.js +42 -18
- package/dist/components/audit/AuditLogDetail.js.map +1 -1
- package/dist/components/audit/AuditLogTable.js +6 -5
- package/dist/components/audit/AuditLogTable.js.map +1 -1
- package/dist/components/gitops/GitOpsProviderPicker.js +29 -0
- package/dist/components/gitops/GitOpsProviderPicker.js.map +1 -0
- package/dist/components/gitops/GitOpsSetup.js +148 -102
- package/dist/components/gitops/GitOpsSetup.js.map +1 -1
- package/dist/components/gitops/VibeGitOpsTab.js +231 -223
- package/dist/components/gitops/VibeGitOpsTab.js.map +1 -1
- package/dist/components/gitops/types.js +65 -0
- package/dist/components/gitops/types.js.map +1 -0
- package/dist/components/security/SecurityEmptyState.js +2 -32
- package/dist/components/security/SecurityTabPanel.js +40 -97
- package/dist/components/security/SecurityTabPanel.js.map +1 -1
- package/dist/components/security/index.js +1 -6
- package/dist/components/security/types.js +3 -5
- package/dist/components/security/types.js.map +1 -1
- package/dist/components/settings/SettingsForm.js +30 -32
- package/dist/components/settings/SettingsForm.js.map +1 -1
- package/dist/components/settings/WorkspaceDefaultsSection.js +113 -118
- package/dist/components/settings/WorkspaceDefaultsSection.js.map +1 -1
- package/dist/components/shared/ConfirmDialog.js +51 -108
- package/dist/components/shared/ConfirmDialog.js.map +1 -1
- package/dist/components/shared/EmptyState.js +9 -102
- package/dist/components/shared/EmptyState.js.map +1 -1
- package/dist/components/shared/PageHeader.js +16 -47
- package/dist/components/shared/PageHeader.js.map +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js +17 -14
- package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
- package/dist/constants/pluginCatalog.js +139 -4
- package/dist/constants/pluginCatalog.js.map +1 -1
- package/dist/hooks/useGitops.js +135 -0
- package/dist/hooks/useGitops.js.map +1 -0
- package/dist/pages/GettingStartedPage.js +6 -6
- package/dist/pages/PluginStandalonePage.js +12 -12
- package/dist/pages/VibeDetailsPage.js +4 -1
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/VibesPage.js +304 -291
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/services/gitopsApi.js +128 -0
- package/dist/services/gitopsApi.js.map +1 -0
- package/package.json +2 -2
- package/dist/components/security/SecurityEmptyState.js.map +0 -1
- package/dist/components/security/SecurityEvidenceList.js +0 -42
- package/dist/components/security/SecurityEvidenceList.js.map +0 -1
- package/dist/components/security/SecurityFindingsTable.js +0 -201
- package/dist/components/security/SecurityFindingsTable.js.map +0 -1
- package/dist/components/security/SecurityHeaderStrip.js +0 -67
- package/dist/components/security/SecurityHeaderStrip.js.map +0 -1
- package/dist/components/security/SecurityLifecycleStepper.js +0 -66
- package/dist/components/security/SecurityLifecycleStepper.js.map +0 -1
- package/dist/components/security/SecurityProviderDrawer.js +0 -187
- package/dist/components/security/SecurityProviderDrawer.js.map +0 -1
- package/dist/components/security/gql.js +0 -128
- package/dist/components/security/gql.js.map +0 -1
|
@@ -137,13 +137,26 @@ function h({ log: n, onClose: i }) {
|
|
|
137
137
|
className: "relative flex h-full w-full max-w-[480px] flex-col border-l border-border-default bg-bg-surface shadow-xl",
|
|
138
138
|
children: [/* @__PURE__ */ d("div", {
|
|
139
139
|
className: "flex items-center justify-between px-4 py-3 border-b border-border-default",
|
|
140
|
-
children: [/* @__PURE__ */ d("div", { children: [
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
140
|
+
children: [/* @__PURE__ */ d("div", { children: [
|
|
141
|
+
/* @__PURE__ */ u("h3", {
|
|
142
|
+
className: "text-sm font-semibold",
|
|
143
|
+
children: n.action.replace(/_/g, " ")
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ d("p", {
|
|
146
|
+
className: "text-xs text-text-secondary",
|
|
147
|
+
children: [n.resourceType.replace(/_/g, " "), n.resourceName ? ` · ${n.resourceName}` : ""]
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ d("details", {
|
|
150
|
+
className: "mt-1",
|
|
151
|
+
children: [/* @__PURE__ */ u("summary", {
|
|
152
|
+
className: "cursor-pointer text-[10px] uppercase tracking-wider text-text-secondary hover:text-text-primary",
|
|
153
|
+
children: "Event ID"
|
|
154
|
+
}), /* @__PURE__ */ u("span", {
|
|
155
|
+
className: "mt-1 block break-all font-mono text-[11px] text-text-secondary",
|
|
156
|
+
children: n.id
|
|
157
|
+
})]
|
|
158
|
+
})
|
|
159
|
+
] }), /* @__PURE__ */ u("button", {
|
|
147
160
|
type: "button",
|
|
148
161
|
"aria-label": o("audit.closeDetail", "Close audit log detail"),
|
|
149
162
|
onClick: i,
|
|
@@ -201,17 +214,28 @@ function h({ log: n, onClose: i }) {
|
|
|
201
214
|
children: n.description || "-"
|
|
202
215
|
})]
|
|
203
216
|
}),
|
|
204
|
-
/* @__PURE__ */ d("div", {
|
|
205
|
-
className: "
|
|
206
|
-
children: "
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
/* @__PURE__ */ d("div", {
|
|
218
|
+
className: "col-span-2",
|
|
219
|
+
children: [/* @__PURE__ */ u("span", {
|
|
220
|
+
className: "text-text-secondary text-xs",
|
|
221
|
+
children: "Actor"
|
|
222
|
+
}), /* @__PURE__ */ d("div", {
|
|
223
|
+
className: "flex items-center gap-2",
|
|
224
|
+
children: [/* @__PURE__ */ u("span", {
|
|
225
|
+
className: "capitalize",
|
|
226
|
+
children: (n.actorType || "unknown").toLowerCase().replace(/_/g, " ")
|
|
227
|
+
}), /* @__PURE__ */ d("details", {
|
|
228
|
+
className: "text-xs text-text-secondary",
|
|
229
|
+
children: [/* @__PURE__ */ u("summary", {
|
|
230
|
+
className: "cursor-pointer hover:text-text-primary",
|
|
231
|
+
children: "ID"
|
|
232
|
+
}), /* @__PURE__ */ u("span", {
|
|
233
|
+
className: "ml-2 break-all font-mono text-[11px]",
|
|
234
|
+
children: n.actorId
|
|
235
|
+
})]
|
|
236
|
+
})]
|
|
237
|
+
})]
|
|
238
|
+
}),
|
|
215
239
|
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("span", {
|
|
216
240
|
className: "text-text-secondary text-xs",
|
|
217
241
|
children: "Timestamp"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuditLogDetail.js","names":[],"sources":["../../../src/components/audit/AuditLogDetail.tsx"],"sourcesContent":["import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useEffect, useState } from 'react';\nimport { X, ChevronDown, ChevronRight, Copy, Check, Terminal } from 'lucide-react';\nimport type { VibeAuditLogDetailFragment } from '@/generated/wspace-operations';\nimport { StatusBadge } from '@/components/shared';\n\ninterface AuditLogDetailProps {\n log: VibeAuditLogDetailFragment;\n onClose: () => void;\n}\n\nfunction JsonViewer({ data, label }: { data: unknown; label: string }) {\n const [expanded, setExpanded] = useState(false);\n if (!data) return null;\n\n return (\n <div className=\"border border-border-primary rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setExpanded(!expanded)}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm font-medium bg-bg-secondary/50 hover:bg-bg-secondary\"\n >\n {expanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}\n {label}\n </button>\n {expanded && (\n <pre className=\"px-3 py-2 text-xs overflow-auto max-h-64 bg-bg-sunken\">\n {JSON.stringify(data, null, 2)}\n </pre>\n )}\n </div>\n );\n}\n\nfunction CommandBlock({\n command,\n output,\n exitCode,\n}: {\n command?: string | null;\n output?: string | null;\n exitCode?: number | null;\n}) {\n const [copied, setCopied] = useState(false);\n if (!command && !output) return null;\n\n const handleCopy = () => {\n if (command) {\n navigator.clipboard.writeText(command);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n };\n\n return (\n <div className=\"border border-border-primary rounded-lg overflow-hidden\">\n <div className=\"flex items-center justify-between px-3 py-2 bg-bg-secondary/50\">\n <span className=\"flex items-center gap-2 text-sm font-medium\">\n <Terminal size={14} />\n Command Execution\n {exitCode !== null && exitCode !== undefined && (\n <span\n className={`px-1.5 py-0.5 rounded text-xs ${exitCode === 0 ? 'bg-status-success-bg text-status-success-text' : 'bg-status-error-bg text-status-error-text'}`}\n >\n exit {exitCode}\n </span>\n )}\n </span>\n {command && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"p-1 rounded hover:bg-bg-secondary text-text-secondary\"\n title=\"Copy command\"\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n )}\n </div>\n {command && (\n <div className=\"px-3 py-2 bg-bg-sunken text-text-secondary font-mono text-xs\">\n <span className=\"text-status-success-text\">$</span> {command}\n </div>\n )}\n {output && (\n <pre className=\"px-3 py-2 text-xs bg-bg-sunken text-text-tertiary font-mono overflow-auto max-h-48\">\n {output}\n </pre>\n )}\n </div>\n );\n}\n\nfunction ChangesetViewer({ changeset }: { changeset: Record<string, unknown> | null | undefined }) {\n const [expanded, setExpanded] = useState(false);\n if (!changeset || typeof changeset !== 'object') return null;\n\n const changes = Object.entries(changeset as Record<string, { from: unknown; to: unknown }>);\n if (changes.length === 0) return null;\n\n return (\n <div className=\"border border-border-primary rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setExpanded(!expanded)}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm font-medium bg-bg-secondary/50 hover:bg-bg-secondary\"\n >\n {expanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}\n Changes ({changes.length} field{changes.length !== 1 ? 's' : ''})\n </button>\n {expanded && (\n <div className=\"px-3 py-2 space-y-2\">\n {changes.map(([field, change]) => (\n <div key={field} className=\"text-xs\">\n <span className=\"font-medium text-text-primary\">{field}</span>\n <div className=\"ml-4 mt-1 space-y-0.5\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-status-error-text font-mono\">-</span>\n <span className=\"text-status-error-text\">\n {JSON.stringify((change as { from: unknown }).from)}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-status-success-text font-mono\">+</span>\n <span className=\"text-status-success-text\">\n {JSON.stringify((change as { to: unknown }).to)}\n </span>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport function AuditLogDetail({ log, onClose }: AuditLogDetailProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [onClose]);\n\n return (\n <div className=\"fixed inset-0 z-[1000] flex justify-end bg-bg-overlay/40\">\n <button\n type=\"button\"\n aria-label={tr('audit.closeDetailOverlay', 'Close audit log detail')}\n className=\"absolute inset-0 cursor-default\"\n onClick={onClose}\n />\n <aside className=\"relative flex h-full w-full max-w-[480px] flex-col border-l border-border-default bg-bg-surface shadow-xl\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default\">\n <div>\n <h3 className=\"text-sm font-semibold\">Audit Log Detail</h3>\n <span className=\"text-xs text-text-secondary font-mono\">{log.id}</span>\n </div>\n <button\n type=\"button\"\n aria-label={tr('audit.closeDetail', 'Close audit log detail')}\n onClick={onClose}\n className=\"flex size-10 items-center justify-center rounded hover:bg-bg-secondary\"\n >\n <X size={16} />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {/* Summary */}\n <div className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <span className=\"text-text-secondary text-xs\">Action</span>\n <div className=\"font-medium\">{log.action}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Status</span>\n <div>\n <StatusBadge status={log.status} size=\"sm\" />\n </div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Resource Type</span>\n <div className=\"font-medium\">{log.resourceType.replace(/_/g, ' ')}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Resource ID</span>\n <div className=\"font-mono text-xs truncate\">{log.resourceId || '-'}</div>\n </div>\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Resource Name</span>\n <div>{log.resourceName || '-'}</div>\n </div>\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Description</span>\n <div className=\"text-text-secondary\">{log.description || '-'}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Actor</span>\n <div className=\"font-mono text-xs\">{log.actorId}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Actor Type</span>\n <div>{log.actorType || '-'}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Timestamp</span>\n <div className=\"text-xs\">{new Date(log.createdAt).toLocaleString()}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">IP Address</span>\n <div className=\"font-mono text-xs\">{log.ipAddress || '-'}</div>\n </div>\n {log.expiresAt && (\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Expires At</span>\n <div className=\"text-xs text-status-warning-text\">\n {new Date(log.expiresAt).toLocaleString()}\n </div>\n </div>\n )}\n {log.errorMessage && (\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Error</span>\n <div className=\"text-status-error-text text-xs\">{log.errorMessage}</div>\n </div>\n )}\n {log.deleteReason && (\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Delete Reason</span>\n <div className=\"text-xs\">{log.deleteReason}</div>\n </div>\n )}\n </div>\n\n {/* Command execution */}\n <CommandBlock command={log.command} output={log.output} exitCode={log.exitCode} />\n\n {/* Changeset */}\n <ChangesetViewer changeset={log.changeset as Record<string, unknown> | null} />\n\n {/* State snapshots */}\n <JsonViewer data={log.previousState} label=\"Previous State\" />\n <JsonViewer data={log.newState} label=\"New State\" />\n <JsonViewer data={log.metadata} label=\"Metadata\" />\n </div>\n </aside>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuditLogDetail.js","names":[],"sources":["../../../src/components/audit/AuditLogDetail.tsx"],"sourcesContent":["import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useEffect, useState } from 'react';\nimport { X, ChevronDown, ChevronRight, Copy, Check, Terminal } from 'lucide-react';\nimport type { VibeAuditLogDetailFragment } from '@/generated/wspace-operations';\nimport { StatusBadge } from '@/components/shared';\n\ninterface AuditLogDetailProps {\n log: VibeAuditLogDetailFragment;\n onClose: () => void;\n}\n\nfunction JsonViewer({ data, label }: { data: unknown; label: string }) {\n const [expanded, setExpanded] = useState(false);\n if (!data) return null;\n\n return (\n <div className=\"border border-border-primary rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setExpanded(!expanded)}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm font-medium bg-bg-secondary/50 hover:bg-bg-secondary\"\n >\n {expanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}\n {label}\n </button>\n {expanded && (\n <pre className=\"px-3 py-2 text-xs overflow-auto max-h-64 bg-bg-sunken\">\n {JSON.stringify(data, null, 2)}\n </pre>\n )}\n </div>\n );\n}\n\nfunction CommandBlock({\n command,\n output,\n exitCode,\n}: {\n command?: string | null;\n output?: string | null;\n exitCode?: number | null;\n}) {\n const [copied, setCopied] = useState(false);\n if (!command && !output) return null;\n\n const handleCopy = () => {\n if (command) {\n navigator.clipboard.writeText(command);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n };\n\n return (\n <div className=\"border border-border-primary rounded-lg overflow-hidden\">\n <div className=\"flex items-center justify-between px-3 py-2 bg-bg-secondary/50\">\n <span className=\"flex items-center gap-2 text-sm font-medium\">\n <Terminal size={14} />\n Command Execution\n {exitCode !== null && exitCode !== undefined && (\n <span\n className={`px-1.5 py-0.5 rounded text-xs ${exitCode === 0 ? 'bg-status-success-bg text-status-success-text' : 'bg-status-error-bg text-status-error-text'}`}\n >\n exit {exitCode}\n </span>\n )}\n </span>\n {command && (\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"p-1 rounded hover:bg-bg-secondary text-text-secondary\"\n title=\"Copy command\"\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n )}\n </div>\n {command && (\n <div className=\"px-3 py-2 bg-bg-sunken text-text-secondary font-mono text-xs\">\n <span className=\"text-status-success-text\">$</span> {command}\n </div>\n )}\n {output && (\n <pre className=\"px-3 py-2 text-xs bg-bg-sunken text-text-tertiary font-mono overflow-auto max-h-48\">\n {output}\n </pre>\n )}\n </div>\n );\n}\n\nfunction ChangesetViewer({ changeset }: { changeset: Record<string, unknown> | null | undefined }) {\n const [expanded, setExpanded] = useState(false);\n if (!changeset || typeof changeset !== 'object') return null;\n\n const changes = Object.entries(changeset as Record<string, { from: unknown; to: unknown }>);\n if (changes.length === 0) return null;\n\n return (\n <div className=\"border border-border-primary rounded-lg overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setExpanded(!expanded)}\n className=\"w-full flex items-center gap-2 px-3 py-2 text-sm font-medium bg-bg-secondary/50 hover:bg-bg-secondary\"\n >\n {expanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}\n Changes ({changes.length} field{changes.length !== 1 ? 's' : ''})\n </button>\n {expanded && (\n <div className=\"px-3 py-2 space-y-2\">\n {changes.map(([field, change]) => (\n <div key={field} className=\"text-xs\">\n <span className=\"font-medium text-text-primary\">{field}</span>\n <div className=\"ml-4 mt-1 space-y-0.5\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-status-error-text font-mono\">-</span>\n <span className=\"text-status-error-text\">\n {JSON.stringify((change as { from: unknown }).from)}\n </span>\n </div>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-status-success-text font-mono\">+</span>\n <span className=\"text-status-success-text\">\n {JSON.stringify((change as { to: unknown }).to)}\n </span>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport function AuditLogDetail({ log, onClose }: AuditLogDetailProps) {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n window.addEventListener('keydown', handleKeyDown);\n return () => window.removeEventListener('keydown', handleKeyDown);\n }, [onClose]);\n\n return (\n <div className=\"fixed inset-0 z-[1000] flex justify-end bg-bg-overlay/40\">\n <button\n type=\"button\"\n aria-label={tr('audit.closeDetailOverlay', 'Close audit log detail')}\n className=\"absolute inset-0 cursor-default\"\n onClick={onClose}\n />\n <aside className=\"relative flex h-full w-full max-w-[480px] flex-col border-l border-border-default bg-bg-surface shadow-xl\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default\">\n <div>\n <h3 className=\"text-sm font-semibold\">\n {log.action.replace(/_/g, ' ')}\n </h3>\n <p className=\"text-xs text-text-secondary\">\n {log.resourceType.replace(/_/g, ' ')}\n {log.resourceName ? ` · ${log.resourceName}` : ''}\n </p>\n <details className=\"mt-1\">\n <summary className=\"cursor-pointer text-[10px] uppercase tracking-wider text-text-secondary hover:text-text-primary\">\n Event ID\n </summary>\n <span className=\"mt-1 block break-all font-mono text-[11px] text-text-secondary\">\n {log.id}\n </span>\n </details>\n </div>\n <button\n type=\"button\"\n aria-label={tr('audit.closeDetail', 'Close audit log detail')}\n onClick={onClose}\n className=\"flex size-10 items-center justify-center rounded hover:bg-bg-secondary\"\n >\n <X size={16} />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-4 space-y-4\">\n {/* Summary */}\n <div className=\"grid grid-cols-2 gap-3 text-sm\">\n <div>\n <span className=\"text-text-secondary text-xs\">Action</span>\n <div className=\"font-medium\">{log.action}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Status</span>\n <div>\n <StatusBadge status={log.status} size=\"sm\" />\n </div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Resource Type</span>\n <div className=\"font-medium\">{log.resourceType.replace(/_/g, ' ')}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Resource ID</span>\n <div className=\"font-mono text-xs truncate\">{log.resourceId || '-'}</div>\n </div>\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Resource Name</span>\n <div>{log.resourceName || '-'}</div>\n </div>\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Description</span>\n <div className=\"text-text-secondary\">{log.description || '-'}</div>\n </div>\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Actor</span>\n <div className=\"flex items-center gap-2\">\n <span className=\"capitalize\">\n {(log.actorType || 'unknown').toLowerCase().replace(/_/g, ' ')}\n </span>\n <details className=\"text-xs text-text-secondary\">\n <summary className=\"cursor-pointer hover:text-text-primary\">\n ID\n </summary>\n <span className=\"ml-2 break-all font-mono text-[11px]\">\n {log.actorId}\n </span>\n </details>\n </div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">Timestamp</span>\n <div className=\"text-xs\">{new Date(log.createdAt).toLocaleString()}</div>\n </div>\n <div>\n <span className=\"text-text-secondary text-xs\">IP Address</span>\n <div className=\"font-mono text-xs\">{log.ipAddress || '-'}</div>\n </div>\n {log.expiresAt && (\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Expires At</span>\n <div className=\"text-xs text-status-warning-text\">\n {new Date(log.expiresAt).toLocaleString()}\n </div>\n </div>\n )}\n {log.errorMessage && (\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Error</span>\n <div className=\"text-status-error-text text-xs\">{log.errorMessage}</div>\n </div>\n )}\n {log.deleteReason && (\n <div className=\"col-span-2\">\n <span className=\"text-text-secondary text-xs\">Delete Reason</span>\n <div className=\"text-xs\">{log.deleteReason}</div>\n </div>\n )}\n </div>\n\n {/* Command execution */}\n <CommandBlock command={log.command} output={log.output} exitCode={log.exitCode} />\n\n {/* Changeset */}\n <ChangesetViewer changeset={log.changeset as Record<string, unknown> | null} />\n\n {/* State snapshots */}\n <JsonViewer data={log.previousState} label=\"Previous State\" />\n <JsonViewer data={log.newState} label=\"New State\" />\n <JsonViewer data={log.metadata} label=\"Metadata\" />\n </div>\n </aside>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -79,9 +79,9 @@ function f({ items: f, total: p, hasMore: m, page: h, pageSize: g, onPageChange:
|
|
|
79
79
|
}),
|
|
80
80
|
/* @__PURE__ */ s("div", {
|
|
81
81
|
className: "mt-3 flex items-center justify-between gap-3",
|
|
82
|
-
children: [/* @__PURE__ */
|
|
83
|
-
className: "min-w-0 truncate
|
|
84
|
-
children: n.
|
|
82
|
+
children: [/* @__PURE__ */ s("p", {
|
|
83
|
+
className: "min-w-0 truncate text-xs capitalize text-text-secondary",
|
|
84
|
+
children: [(n.actorType || "unknown").toLowerCase().replace(/_/g, " "), n.resourceName ? ` · ${n.resourceName}` : ""]
|
|
85
85
|
}), /* @__PURE__ */ o(e, {
|
|
86
86
|
status: n.status,
|
|
87
87
|
variant: c[n.status],
|
|
@@ -186,8 +186,9 @@ function f({ items: f, total: p, hasMore: m, page: h, pageSize: g, onPageChange:
|
|
|
186
186
|
children: n.resourceName || n.description || "-"
|
|
187
187
|
}),
|
|
188
188
|
/* @__PURE__ */ o("td", {
|
|
189
|
-
className: "max-w-[
|
|
190
|
-
|
|
189
|
+
className: "max-w-[140px] truncate px-4 py-3 text-xs capitalize text-text-secondary",
|
|
190
|
+
title: n.actorId,
|
|
191
|
+
children: (n.actorType || "unknown").toLowerCase().replace(/_/g, " ")
|
|
191
192
|
}),
|
|
192
193
|
/* @__PURE__ */ o("td", {
|
|
193
194
|
className: "px-4 py-3",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuditLogTable.js","names":[],"sources":["../../../src/components/audit/AuditLogTable.tsx"],"sourcesContent":["import { ChevronRight, Terminal, Trash2 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { StatusBadge } from '@/components/shared';\nimport { SelectionCheckbox } from '@/components/shared/SelectionCheckbox';\nimport type { VibeAuditLogFieldsFragment } from '@/generated/wspace-operations';\n\ninterface AuditLogTableProps {\n items: VibeAuditLogFieldsFragment[];\n total: number;\n hasMore: boolean;\n page: number;\n pageSize: number;\n onPageChange: (page: number) => void;\n onSelectLog: (id: string) => void;\n onDeleteLog: (id: string) => void;\n selectedLogId: string | null;\n selectedLogIds: Set<string>;\n allVisibleSelected: boolean;\n partiallySelected: boolean;\n onToggleLogSelection: (id: string, checked: boolean) => void;\n onToggleAllVisible: (checked: boolean) => void;\n}\n\nconst statusVariantMap: Record<string, 'success' | 'error' | 'warning' | 'info'> = {\n SUCCESS: 'success',\n FAILURE: 'error',\n DENIED: 'warning',\n ERROR: 'error',\n};\n\nconst actionColors: Record<string, string> = {\n CREATE: 'bg-status-success-bg text-status-success-text',\n UPDATE: 'bg-status-info-bg text-status-info-text',\n DELETE: 'bg-status-error-bg text-status-error-text',\n EXECUTE: 'bg-action-primary-bg/15 text-action-primary-text',\n EXPORT: 'bg-status-warning-bg text-status-warning-text',\n SHARE: 'bg-status-success-bg text-status-success-text',\n REVOKE: 'bg-status-warning-bg text-status-warning-text',\n ARCHIVE: 'bg-bg-muted text-text-secondary',\n RESTORE: 'bg-status-info-bg text-status-info-text',\n};\n\nfunction formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleString('en-US', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n}\n\nfunction formatResourceType(type: string): string {\n return type\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (character) => character.toUpperCase());\n}\n\nexport function AuditLogTable({\n items,\n total,\n hasMore,\n page,\n pageSize,\n onPageChange,\n onSelectLog,\n onDeleteLog,\n selectedLogId,\n selectedLogIds,\n allVisibleSelected,\n partiallySelected,\n onToggleLogSelection,\n onToggleAllVisible,\n}: AuditLogTableProps) {\n const { t } = useI18n();\n const totalPages = Math.max(1, Math.ceil(total / pageSize));\n\n const tr = (key: string, fallback: string) => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n return (\n <div>\n <div className=\"space-y-3 md:hidden\">\n {items.map((item) => {\n const isSelected = selectedLogIds.has(item.id);\n return (\n <article\n key={item.id}\n className={`rounded-lg border border-border-primary p-4 transition-colors ${\n selectedLogId === item.id ? 'bg-bg-secondary/50' : 'bg-bg-surface'\n }`}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3\">\n <SelectionCheckbox\n checked={isSelected}\n onChange={(checked) => onToggleLogSelection(item.id, checked)}\n ariaLabel={`Select audit log ${item.id}`}\n className=\"mt-1\"\n />\n <div className=\"min-w-0\">\n <p className=\"text-xs text-text-secondary\">{formatDate(item.createdAt)}</p>\n <p className=\"mt-1 truncate font-medium text-text-primary\">\n {item.resourceName || item.description || '-'}\n </p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {formatResourceType(item.resourceType)}\n </p>\n </div>\n </div>\n <span\n className={`inline-flex shrink-0 items-center gap-1 rounded px-2 py-0.5 text-xs font-medium ${\n actionColors[item.action] || 'bg-bg-secondary text-text-secondary'\n }`}\n >\n {item.command ? <Terminal size={12} /> : null}\n {item.action}\n </span>\n </div>\n <div className=\"mt-3 flex items-center justify-between gap-3\">\n <p className=\"min-w-0 truncate font-mono text-xs text-text-secondary\">\n {item.actorId}\n </p>\n <StatusBadge\n status={item.status}\n variant={statusVariantMap[item.status]}\n size=\"sm\"\n />\n </div>\n <div className=\"mt-4 flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => onSelectLog(item.id)}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-primary px-3 py-1.5 text-sm text-text-primary transition-colors hover:bg-bg-secondary\"\n >\n View details\n <ChevronRight size={14} />\n </button>\n <button\n type=\"button\"\n onClick={() => onDeleteLog(item.id)}\n className=\"rounded p-1 text-text-secondary transition-colors hover:bg-status-error-bg hover:text-status-error-text\"\n title={tr('audit.deleteAuditLog', 'Delete audit log')}\n >\n <Trash2 size={14} />\n </button>\n </div>\n </article>\n );\n })}\n </div>\n\n <div className=\"hidden overflow-x-auto rounded-lg border border-border-primary md:block\">\n <table className=\"w-full min-w-[860px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-primary bg-bg-secondary/50\">\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={onToggleAllVisible}\n ariaLabel=\"Select all visible audit logs\"\n />\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.time', 'Time')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.action', 'Action')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.resource', 'Resource')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.name', 'Name')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.actor', 'Actor')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.status', 'Status')}\n </th>\n <th className=\"px-4 py-3 text-right font-medium text-text-secondary\">\n {tr('audit.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => {\n const isSelected = selectedLogIds.has(item.id);\n return (\n <tr\n key={item.id}\n className={`border-b border-border-primary/50 transition-colors hover:bg-bg-secondary/30 ${\n selectedLogId === item.id ? 'bg-bg-secondary/50' : ''\n }`}\n >\n <td className=\"px-4 py-3 align-top\">\n <SelectionCheckbox\n checked={isSelected}\n onChange={(checked) => onToggleLogSelection(item.id, checked)}\n ariaLabel={`Select audit log ${item.id}`}\n />\n </td>\n <td className=\"whitespace-nowrap px-4 py-3 text-xs text-text-secondary\">\n {formatDate(item.createdAt)}\n </td>\n <td className=\"px-4 py-3\">\n <span\n className={`inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium ${\n actionColors[item.action] || 'bg-bg-secondary text-text-secondary'\n }`}\n >\n {item.command ? <Terminal size={12} /> : null}\n {item.action}\n </span>\n </td>\n <td className=\"px-4 py-3 text-xs text-text-secondary\">\n {formatResourceType(item.resourceType)}\n </td>\n <td\n className=\"max-w-[220px] truncate px-4 py-3\"\n title={item.resourceName || item.description || ''}\n >\n {item.resourceName || item.description || '-'}\n </td>\n <td className=\"max-w-[120px] truncate px-4 py-3 font-mono text-xs text-text-secondary\">\n {item.actorId}\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge\n status={item.status}\n variant={statusVariantMap[item.status]}\n size=\"sm\"\n />\n </td>\n <td className=\"px-4 py-3 text-right\">\n <div className=\"flex items-center justify-end gap-1\">\n <button\n type=\"button\"\n onClick={() => onSelectLog(item.id)}\n className=\"rounded p-1 text-text-secondary transition-colors hover:bg-bg-secondary hover:text-text-primary\"\n title={tr('audit.viewAuditLog', 'View details')}\n >\n <ChevronRight size={14} />\n </button>\n <button\n type=\"button\"\n onClick={() => onDeleteLog(item.id)}\n className=\"rounded p-1 text-text-secondary transition-colors hover:bg-status-error-bg hover:text-status-error-text\"\n title={tr('audit.deleteAuditLog', 'Delete audit log')}\n >\n <Trash2 size={14} />\n </button>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n\n <div className=\"mt-4 flex flex-col gap-3 text-sm text-text-secondary sm:flex-row sm:items-center sm:justify-between\">\n <span>\n {tr('audit.showing', 'Showing')} {page * pageSize + 1}-\n {Math.min((page + 1) * pageSize, total)} {tr('audit.of', 'of')} {total}\n </span>\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n disabled={page === 0}\n onClick={() => onPageChange(page - 1)}\n className=\"rounded border border-border-primary px-3 py-1 transition-colors hover:bg-bg-secondary disabled:opacity-50\"\n >\n {tr('audit.previous', 'Previous')}\n </button>\n <span>\n {tr('audit.page', 'Page')} {page + 1} {tr('audit.of', 'of')} {totalPages}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => onPageChange(page + 1)}\n className=\"rounded border border-border-primary px-3 py-1 transition-colors hover:bg-bg-secondary disabled:opacity-50\"\n >\n {tr('audit.next', 'Next')}\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AuditLogTable.js","names":[],"sources":["../../../src/components/audit/AuditLogTable.tsx"],"sourcesContent":["import { ChevronRight, Terminal, Trash2 } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { StatusBadge } from '@/components/shared';\nimport { SelectionCheckbox } from '@/components/shared/SelectionCheckbox';\nimport type { VibeAuditLogFieldsFragment } from '@/generated/wspace-operations';\n\ninterface AuditLogTableProps {\n items: VibeAuditLogFieldsFragment[];\n total: number;\n hasMore: boolean;\n page: number;\n pageSize: number;\n onPageChange: (page: number) => void;\n onSelectLog: (id: string) => void;\n onDeleteLog: (id: string) => void;\n selectedLogId: string | null;\n selectedLogIds: Set<string>;\n allVisibleSelected: boolean;\n partiallySelected: boolean;\n onToggleLogSelection: (id: string, checked: boolean) => void;\n onToggleAllVisible: (checked: boolean) => void;\n}\n\nconst statusVariantMap: Record<string, 'success' | 'error' | 'warning' | 'info'> = {\n SUCCESS: 'success',\n FAILURE: 'error',\n DENIED: 'warning',\n ERROR: 'error',\n};\n\nconst actionColors: Record<string, string> = {\n CREATE: 'bg-status-success-bg text-status-success-text',\n UPDATE: 'bg-status-info-bg text-status-info-text',\n DELETE: 'bg-status-error-bg text-status-error-text',\n EXECUTE: 'bg-action-primary-bg/15 text-action-primary-text',\n EXPORT: 'bg-status-warning-bg text-status-warning-text',\n SHARE: 'bg-status-success-bg text-status-success-text',\n REVOKE: 'bg-status-warning-bg text-status-warning-text',\n ARCHIVE: 'bg-bg-muted text-text-secondary',\n RESTORE: 'bg-status-info-bg text-status-info-text',\n};\n\nfunction formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleString('en-US', {\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n}\n\nfunction formatResourceType(type: string): string {\n return type\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (character) => character.toUpperCase());\n}\n\nexport function AuditLogTable({\n items,\n total,\n hasMore,\n page,\n pageSize,\n onPageChange,\n onSelectLog,\n onDeleteLog,\n selectedLogId,\n selectedLogIds,\n allVisibleSelected,\n partiallySelected,\n onToggleLogSelection,\n onToggleAllVisible,\n}: AuditLogTableProps) {\n const { t } = useI18n();\n const totalPages = Math.max(1, Math.ceil(total / pageSize));\n\n const tr = (key: string, fallback: string) => {\n const value = t(key);\n return value === key ? fallback : value;\n };\n\n return (\n <div>\n <div className=\"space-y-3 md:hidden\">\n {items.map((item) => {\n const isSelected = selectedLogIds.has(item.id);\n return (\n <article\n key={item.id}\n className={`rounded-lg border border-border-primary p-4 transition-colors ${\n selectedLogId === item.id ? 'bg-bg-secondary/50' : 'bg-bg-surface'\n }`}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3\">\n <SelectionCheckbox\n checked={isSelected}\n onChange={(checked) => onToggleLogSelection(item.id, checked)}\n ariaLabel={`Select audit log ${item.id}`}\n className=\"mt-1\"\n />\n <div className=\"min-w-0\">\n <p className=\"text-xs text-text-secondary\">{formatDate(item.createdAt)}</p>\n <p className=\"mt-1 truncate font-medium text-text-primary\">\n {item.resourceName || item.description || '-'}\n </p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {formatResourceType(item.resourceType)}\n </p>\n </div>\n </div>\n <span\n className={`inline-flex shrink-0 items-center gap-1 rounded px-2 py-0.5 text-xs font-medium ${\n actionColors[item.action] || 'bg-bg-secondary text-text-secondary'\n }`}\n >\n {item.command ? <Terminal size={12} /> : null}\n {item.action}\n </span>\n </div>\n <div className=\"mt-3 flex items-center justify-between gap-3\">\n <p className=\"min-w-0 truncate text-xs capitalize text-text-secondary\">\n {(item.actorType || 'unknown')\n .toLowerCase()\n .replace(/_/g, ' ')}\n {item.resourceName ? ` · ${item.resourceName}` : ''}\n </p>\n <StatusBadge\n status={item.status}\n variant={statusVariantMap[item.status]}\n size=\"sm\"\n />\n </div>\n <div className=\"mt-4 flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => onSelectLog(item.id)}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-primary px-3 py-1.5 text-sm text-text-primary transition-colors hover:bg-bg-secondary\"\n >\n View details\n <ChevronRight size={14} />\n </button>\n <button\n type=\"button\"\n onClick={() => onDeleteLog(item.id)}\n className=\"rounded p-1 text-text-secondary transition-colors hover:bg-status-error-bg hover:text-status-error-text\"\n title={tr('audit.deleteAuditLog', 'Delete audit log')}\n >\n <Trash2 size={14} />\n </button>\n </div>\n </article>\n );\n })}\n </div>\n\n <div className=\"hidden overflow-x-auto rounded-lg border border-border-primary md:block\">\n <table className=\"w-full min-w-[860px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-primary bg-bg-secondary/50\">\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n <SelectionCheckbox\n checked={allVisibleSelected}\n indeterminate={partiallySelected}\n onChange={onToggleAllVisible}\n ariaLabel=\"Select all visible audit logs\"\n />\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.time', 'Time')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.action', 'Action')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.resource', 'Resource')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.name', 'Name')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.actor', 'Actor')}\n </th>\n <th className=\"px-4 py-3 text-left font-medium text-text-secondary\">\n {tr('audit.status', 'Status')}\n </th>\n <th className=\"px-4 py-3 text-right font-medium text-text-secondary\">\n {tr('audit.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {items.map((item) => {\n const isSelected = selectedLogIds.has(item.id);\n return (\n <tr\n key={item.id}\n className={`border-b border-border-primary/50 transition-colors hover:bg-bg-secondary/30 ${\n selectedLogId === item.id ? 'bg-bg-secondary/50' : ''\n }`}\n >\n <td className=\"px-4 py-3 align-top\">\n <SelectionCheckbox\n checked={isSelected}\n onChange={(checked) => onToggleLogSelection(item.id, checked)}\n ariaLabel={`Select audit log ${item.id}`}\n />\n </td>\n <td className=\"whitespace-nowrap px-4 py-3 text-xs text-text-secondary\">\n {formatDate(item.createdAt)}\n </td>\n <td className=\"px-4 py-3\">\n <span\n className={`inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs font-medium ${\n actionColors[item.action] || 'bg-bg-secondary text-text-secondary'\n }`}\n >\n {item.command ? <Terminal size={12} /> : null}\n {item.action}\n </span>\n </td>\n <td className=\"px-4 py-3 text-xs text-text-secondary\">\n {formatResourceType(item.resourceType)}\n </td>\n <td\n className=\"max-w-[220px] truncate px-4 py-3\"\n title={item.resourceName || item.description || ''}\n >\n {item.resourceName || item.description || '-'}\n </td>\n <td\n className=\"max-w-[140px] truncate px-4 py-3 text-xs capitalize text-text-secondary\"\n title={item.actorId}\n >\n {(item.actorType || 'unknown')\n .toLowerCase()\n .replace(/_/g, ' ')}\n </td>\n <td className=\"px-4 py-3\">\n <StatusBadge\n status={item.status}\n variant={statusVariantMap[item.status]}\n size=\"sm\"\n />\n </td>\n <td className=\"px-4 py-3 text-right\">\n <div className=\"flex items-center justify-end gap-1\">\n <button\n type=\"button\"\n onClick={() => onSelectLog(item.id)}\n className=\"rounded p-1 text-text-secondary transition-colors hover:bg-bg-secondary hover:text-text-primary\"\n title={tr('audit.viewAuditLog', 'View details')}\n >\n <ChevronRight size={14} />\n </button>\n <button\n type=\"button\"\n onClick={() => onDeleteLog(item.id)}\n className=\"rounded p-1 text-text-secondary transition-colors hover:bg-status-error-bg hover:text-status-error-text\"\n title={tr('audit.deleteAuditLog', 'Delete audit log')}\n >\n <Trash2 size={14} />\n </button>\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n\n <div className=\"mt-4 flex flex-col gap-3 text-sm text-text-secondary sm:flex-row sm:items-center sm:justify-between\">\n <span>\n {tr('audit.showing', 'Showing')} {page * pageSize + 1}-\n {Math.min((page + 1) * pageSize, total)} {tr('audit.of', 'of')} {total}\n </span>\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n disabled={page === 0}\n onClick={() => onPageChange(page - 1)}\n className=\"rounded border border-border-primary px-3 py-1 transition-colors hover:bg-bg-secondary disabled:opacity-50\"\n >\n {tr('audit.previous', 'Previous')}\n </button>\n <span>\n {tr('audit.page', 'Page')} {page + 1} {tr('audit.of', 'of')} {totalPages}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => onPageChange(page + 1)}\n className=\"rounded border border-border-primary px-3 py-1 transition-colors hover:bg-bg-secondary disabled:opacity-50\"\n >\n {tr('audit.next', 'Next')}\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as e, jsxs as t } from "react/jsx-runtime";
|
|
2
|
+
//#region src/components/gitops/GitOpsProviderPicker.tsx
|
|
3
|
+
var n = {
|
|
4
|
+
github: "GitHub",
|
|
5
|
+
gitlab: "GitLab",
|
|
6
|
+
bitbucket: "Bitbucket",
|
|
7
|
+
azdevops: "Azure DevOps"
|
|
8
|
+
}, r = ({ providers: r, selected: i, onChange: a }) => r.length === 0 ? null : r.length === 1 && r[0] ? /* @__PURE__ */ e("span", {
|
|
9
|
+
className: "inline-flex items-center px-2 py-0.5 text-xs rounded-md bg-bg-sunken text-text-secondary",
|
|
10
|
+
"data-testid": "gitops-provider-badge",
|
|
11
|
+
children: n[r[0]]
|
|
12
|
+
}) : /* @__PURE__ */ t("select", {
|
|
13
|
+
"aria-label": "GitOps provider",
|
|
14
|
+
"data-testid": "gitops-provider-picker",
|
|
15
|
+
value: i ?? "",
|
|
16
|
+
onChange: (e) => a(e.target.value),
|
|
17
|
+
className: "px-2 py-1 text-xs rounded-md border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40",
|
|
18
|
+
children: [!i && /* @__PURE__ */ e("option", {
|
|
19
|
+
value: "",
|
|
20
|
+
children: "Select…"
|
|
21
|
+
}), r.map((t) => /* @__PURE__ */ e("option", {
|
|
22
|
+
value: t,
|
|
23
|
+
children: n[t]
|
|
24
|
+
}, t))]
|
|
25
|
+
});
|
|
26
|
+
//#endregion
|
|
27
|
+
export { r as GitOpsProviderPicker };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=GitOpsProviderPicker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GitOpsProviderPicker.js","names":[],"sources":["../../../src/components/gitops/GitOpsProviderPicker.tsx"],"sourcesContent":["/**\n * GitOpsProviderPicker — small select to switch between authenticated\n * providers (github / gitlab / bitbucket / azdevops).\n *\n * Only providers that the user has authenticated against are surfaced.\n */\nimport type { FC } from 'react';\n\nimport type { ProviderName } from './types';\n\nconst LABELS: Record<ProviderName, string> = {\n github: 'GitHub',\n gitlab: 'GitLab',\n bitbucket: 'Bitbucket',\n azdevops: 'Azure DevOps',\n};\n\ninterface GitOpsProviderPickerProps {\n providers: ProviderName[];\n selected: ProviderName | null;\n onChange: (next: ProviderName) => void;\n}\n\nexport const GitOpsProviderPicker: FC<GitOpsProviderPickerProps> = ({\n providers,\n selected,\n onChange,\n}) => {\n if (providers.length === 0) return null;\n if (providers.length === 1 && providers[0]) {\n return (\n <span\n className=\"inline-flex items-center px-2 py-0.5 text-xs rounded-md bg-bg-sunken text-text-secondary\"\n data-testid=\"gitops-provider-badge\"\n >\n {LABELS[providers[0]]}\n </span>\n );\n }\n return (\n <select\n aria-label=\"GitOps provider\"\n data-testid=\"gitops-provider-picker\"\n value={selected ?? ''}\n onChange={(e) => onChange(e.target.value as ProviderName)}\n className=\"px-2 py-1 text-xs rounded-md border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40\"\n >\n {!selected && <option value=\"\">Select…</option>}\n {providers.map((p) => (\n <option key={p} value={p}>\n {LABELS[p]}\n </option>\n ))}\n </select>\n );\n};\n"],"mappings":";;AAUA,IAAM,IAAuC;CAC3C,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,UAAU;CACX,EAQY,KAAuD,EAClE,cACA,aACA,kBAEI,EAAU,WAAW,IAAU,OAC/B,EAAU,WAAW,KAAK,EAAU,KAEpC,kBAAC,QAAD;CACE,WAAU;CACV,eAAY;WAEX,EAAO,EAAU;CACb,CAAA,GAIT,kBAAC,UAAD;CACE,cAAW;CACX,eAAY;CACZ,OAAO,KAAY;CACnB,WAAW,MAAM,EAAS,EAAE,OAAO,MAAsB;CACzD,WAAU;WALZ,CAOG,CAAC,KAAY,kBAAC,UAAD;EAAQ,OAAM;YAAG;EAAgB,CAAA,EAC9C,EAAU,KAAK,MACd,kBAAC,UAAD;EAAgB,OAAO;YACpB,EAAO;EACD,EAFI,EAEJ,CACT,CACK"}
|
|
@@ -1,150 +1,196 @@
|
|
|
1
1
|
import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
2
|
-
import {
|
|
2
|
+
import { useGitopsAuth as t } from "../../hooks/useGitops.js";
|
|
3
3
|
import { useCallback as n, useMemo as r, useState as i } from "react";
|
|
4
|
-
import {
|
|
5
|
-
import { jsx as
|
|
4
|
+
import { ExternalLink as a, GitMerge as o, Loader2 as s } from "lucide-react";
|
|
5
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
6
6
|
//#region src/components/gitops/GitOpsSetup.tsx
|
|
7
|
-
var
|
|
7
|
+
var u = [
|
|
8
8
|
{
|
|
9
|
-
value: "
|
|
10
|
-
label: "GitHub"
|
|
9
|
+
value: "github",
|
|
10
|
+
label: "GitHub",
|
|
11
|
+
tokenLabel: "Personal Access Token",
|
|
12
|
+
tokenPlaceholder: "ghp_xxxxxxxxxxxxxxxxxxxx",
|
|
13
|
+
helpUrl: "https://github.com/settings/tokens",
|
|
14
|
+
helpText: "Required scopes: repo, workflow, read:org, security_events"
|
|
11
15
|
},
|
|
12
16
|
{
|
|
13
|
-
value: "
|
|
14
|
-
label: "GitLab"
|
|
17
|
+
value: "gitlab",
|
|
18
|
+
label: "GitLab",
|
|
19
|
+
tokenLabel: "Personal Access Token",
|
|
20
|
+
tokenPlaceholder: "glpat-xxxxxxxxxxxxxxxxxxxx",
|
|
21
|
+
helpUrl: "https://gitlab.com/-/profile/personal_access_tokens",
|
|
22
|
+
helpText: "Required scope: api. For self-hosted instances, set the host below.",
|
|
23
|
+
showHost: !0
|
|
15
24
|
},
|
|
16
25
|
{
|
|
17
|
-
value: "
|
|
18
|
-
label: "Bitbucket"
|
|
26
|
+
value: "bitbucket",
|
|
27
|
+
label: "Bitbucket Cloud",
|
|
28
|
+
tokenLabel: "username:app_password",
|
|
29
|
+
tokenPlaceholder: "vignesh:ATBBxxxxxxxxxxxxxx",
|
|
30
|
+
helpUrl: "https://bitbucket.org/account/settings/app-passwords/",
|
|
31
|
+
helpText: "Required permissions: Repositories Read, Pull Requests Read, Pipelines Read"
|
|
19
32
|
},
|
|
20
33
|
{
|
|
21
|
-
value: "
|
|
22
|
-
label: "Azure DevOps"
|
|
34
|
+
value: "azdevops",
|
|
35
|
+
label: "Azure DevOps",
|
|
36
|
+
tokenLabel: "Personal Access Token",
|
|
37
|
+
tokenPlaceholder: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
|
38
|
+
helpUrl: "https://dev.azure.com/_usersSettings/tokens",
|
|
39
|
+
helpText: "Required scopes: Code Read, Pull Request Read, Build Read",
|
|
40
|
+
showOrg: !0
|
|
23
41
|
}
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
repoUrl: _.trim()
|
|
44
|
-
} } }), p();
|
|
42
|
+
], d = ({ ctx: d, onCreated: f, onCancel: p }) => {
|
|
43
|
+
let m = e(), [h, g] = i("github"), [_, v] = i(""), [y, b] = i(""), [x, S] = i(""), [C, w] = i(""), [T, E] = i(null), D = r(() => u.find((e) => e.value === h) ?? u[0], [h]), O = t(d), k = r(() => !(_.trim().length === 0 || D.showOrg && y.trim().length === 0), [
|
|
44
|
+
D.showOrg,
|
|
45
|
+
y,
|
|
46
|
+
_
|
|
47
|
+
]), A = n(async (e) => {
|
|
48
|
+
if (e.preventDefault(), w(""), E(null), !k) return;
|
|
49
|
+
let t = {};
|
|
50
|
+
D.showOrg && y && (t.organization = y.trim()), D.showHost && x && (t.host = x.trim());
|
|
51
|
+
try {
|
|
52
|
+
let e = await O.mutateAsync({
|
|
53
|
+
provider: h,
|
|
54
|
+
input: {
|
|
55
|
+
kind: "pat",
|
|
56
|
+
token: _.trim(),
|
|
57
|
+
meta: Object.keys(t).length ? t : void 0
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
E(e), e.ok ? (v(""), f()) : e.message && w(e.message);
|
|
45
61
|
} catch (e) {
|
|
46
|
-
w(e instanceof Error ? e.message : "Failed to
|
|
62
|
+
w(e instanceof Error ? e.message : "Failed to save credentials");
|
|
47
63
|
}
|
|
48
64
|
}, [
|
|
49
65
|
O,
|
|
50
|
-
T,
|
|
51
|
-
d,
|
|
52
|
-
h,
|
|
53
|
-
y,
|
|
54
|
-
_,
|
|
55
66
|
x,
|
|
56
|
-
|
|
67
|
+
k,
|
|
68
|
+
f,
|
|
69
|
+
D.showHost,
|
|
70
|
+
D.showOrg,
|
|
71
|
+
y,
|
|
72
|
+
h,
|
|
73
|
+
_
|
|
57
74
|
]);
|
|
58
|
-
return /* @__PURE__ */
|
|
75
|
+
return /* @__PURE__ */ c("div", {
|
|
59
76
|
className: "max-w-xl mx-auto",
|
|
60
|
-
children: /* @__PURE__ */
|
|
77
|
+
children: /* @__PURE__ */ l("div", {
|
|
61
78
|
className: "bg-bg-surface border border-border-default rounded-xl shadow-sm p-6 sm:p-8",
|
|
62
|
-
children: [/* @__PURE__ */
|
|
79
|
+
children: [/* @__PURE__ */ l("div", {
|
|
63
80
|
className: "flex flex-col items-center text-center mb-6",
|
|
64
81
|
children: [
|
|
65
|
-
/* @__PURE__ */
|
|
82
|
+
/* @__PURE__ */ c("div", {
|
|
66
83
|
className: "size-12 rounded-xl bg-bg-sunken flex items-center justify-center mb-4",
|
|
67
|
-
children: /* @__PURE__ */
|
|
84
|
+
children: /* @__PURE__ */ c(o, { className: "size-6 text-text-secondary" })
|
|
68
85
|
}),
|
|
69
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ c("h2", {
|
|
70
87
|
className: "text-lg font-semibold text-text-primary",
|
|
71
|
-
children: m("vibecontrols.gitops.setup.title", "Connect a
|
|
88
|
+
children: m("vibecontrols.gitops.setup.title", "Connect a provider")
|
|
72
89
|
}),
|
|
73
|
-
/* @__PURE__ */
|
|
90
|
+
/* @__PURE__ */ c("p", {
|
|
74
91
|
className: "text-sm text-text-secondary mt-1",
|
|
75
|
-
children: m("vibecontrols.gitops.setup.description", "
|
|
92
|
+
children: m("vibecontrols.gitops.setup.description", "Paste a personal access token. It is stored encrypted on your agent — never sent to the backend.")
|
|
76
93
|
})
|
|
77
94
|
]
|
|
78
|
-
}), /* @__PURE__ */
|
|
79
|
-
onSubmit:
|
|
95
|
+
}), /* @__PURE__ */ l("form", {
|
|
96
|
+
onSubmit: A,
|
|
80
97
|
className: "space-y-4",
|
|
81
98
|
children: [
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
htmlFor: "gitops-
|
|
99
|
+
/* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
|
|
100
|
+
htmlFor: "gitops-provider",
|
|
84
101
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
85
|
-
children: m("vibecontrols.gitops.setup.
|
|
86
|
-
}), /* @__PURE__ */
|
|
87
|
-
|
|
88
|
-
id: "gitops-name",
|
|
89
|
-
type: "text",
|
|
102
|
+
children: m("vibecontrols.gitops.setup.providerType", "Provider")
|
|
103
|
+
}), /* @__PURE__ */ c("select", {
|
|
104
|
+
id: "gitops-provider",
|
|
90
105
|
value: h,
|
|
91
106
|
onChange: (e) => g(e.target.value),
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
className: "block text-sm font-medium text-text-primary mb-1",
|
|
98
|
-
children: m("vibecontrols.gitops.setup.repoUrl", "Repository URL")
|
|
99
|
-
}), /* @__PURE__ */ s("input", {
|
|
100
|
-
"aria-label": "https://github.com/org/repo",
|
|
101
|
-
id: "gitops-url",
|
|
102
|
-
type: "url",
|
|
103
|
-
value: _,
|
|
104
|
-
onChange: (e) => D(e.target.value),
|
|
105
|
-
placeholder: "https://github.com/org/repo",
|
|
106
|
-
className: "w-full px-3 py-2 text-sm rounded-lg border border-border-default bg-bg-surface text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 focus:border-action-primary-bg transition-colors"
|
|
107
|
+
className: "w-full px-3 py-2 text-sm rounded-lg border border-border-default bg-bg-surface text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40",
|
|
108
|
+
children: u.map((e) => /* @__PURE__ */ c("option", {
|
|
109
|
+
value: e.value,
|
|
110
|
+
children: e.label
|
|
111
|
+
}, e.value))
|
|
107
112
|
})] }),
|
|
108
|
-
/* @__PURE__ */
|
|
109
|
-
htmlFor: "gitops-
|
|
113
|
+
D.showOrg && /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
|
|
114
|
+
htmlFor: "gitops-org",
|
|
110
115
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
111
|
-
children: m("vibecontrols.gitops.setup.
|
|
112
|
-
}), /* @__PURE__ */
|
|
113
|
-
id: "gitops-
|
|
116
|
+
children: m("vibecontrols.gitops.setup.organization", "Organisation")
|
|
117
|
+
}), /* @__PURE__ */ c("input", {
|
|
118
|
+
id: "gitops-org",
|
|
119
|
+
type: "text",
|
|
114
120
|
value: y,
|
|
115
121
|
onChange: (e) => b(e.target.value),
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
children: e.label
|
|
120
|
-
}, e.value))
|
|
122
|
+
placeholder: "my-org",
|
|
123
|
+
"aria-label": "Azure DevOps organisation",
|
|
124
|
+
className: "w-full px-3 py-2 text-sm rounded-lg border border-border-default bg-bg-surface text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40"
|
|
121
125
|
})] }),
|
|
122
|
-
/* @__PURE__ */
|
|
123
|
-
htmlFor: "gitops-
|
|
126
|
+
D.showHost && /* @__PURE__ */ l("div", { children: [/* @__PURE__ */ c("label", {
|
|
127
|
+
htmlFor: "gitops-host",
|
|
124
128
|
className: "block text-sm font-medium text-text-primary mb-1",
|
|
125
|
-
children: m("vibecontrols.gitops.setup.
|
|
126
|
-
}),
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}) : /* @__PURE__ */ s("select", {
|
|
130
|
-
id: "gitops-agent",
|
|
129
|
+
children: m("vibecontrols.gitops.setup.host", "GitLab host (optional, for self-hosted)")
|
|
130
|
+
}), /* @__PURE__ */ c("input", {
|
|
131
|
+
id: "gitops-host",
|
|
132
|
+
type: "url",
|
|
131
133
|
value: x,
|
|
132
134
|
onChange: (e) => S(e.target.value),
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
value: e.id,
|
|
136
|
-
children: e.name
|
|
137
|
-
}, e.id))
|
|
135
|
+
placeholder: "https://gitlab.acme.com",
|
|
136
|
+
className: "w-full px-3 py-2 text-sm rounded-lg border border-border-default bg-bg-surface text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40"
|
|
138
137
|
})] }),
|
|
139
|
-
|
|
138
|
+
/* @__PURE__ */ l("div", { children: [
|
|
139
|
+
/* @__PURE__ */ c("label", {
|
|
140
|
+
htmlFor: "gitops-token",
|
|
141
|
+
className: "block text-sm font-medium text-text-primary mb-1",
|
|
142
|
+
children: D.tokenLabel
|
|
143
|
+
}),
|
|
144
|
+
/* @__PURE__ */ c("input", {
|
|
145
|
+
id: "gitops-token",
|
|
146
|
+
type: "password",
|
|
147
|
+
value: _,
|
|
148
|
+
onChange: (e) => v(e.target.value),
|
|
149
|
+
placeholder: D.tokenPlaceholder,
|
|
150
|
+
"aria-label": "Personal access token",
|
|
151
|
+
autoComplete: "off",
|
|
152
|
+
className: "w-full px-3 py-2 text-sm rounded-lg border border-border-default bg-bg-surface text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40"
|
|
153
|
+
}),
|
|
154
|
+
/* @__PURE__ */ l("p", {
|
|
155
|
+
className: "text-xs text-text-secondary mt-1.5 flex items-center gap-1",
|
|
156
|
+
children: [
|
|
157
|
+
D.helpText,
|
|
158
|
+
" ",
|
|
159
|
+
/* @__PURE__ */ l("a", {
|
|
160
|
+
href: D.helpUrl,
|
|
161
|
+
target: "_blank",
|
|
162
|
+
rel: "noopener noreferrer",
|
|
163
|
+
className: "inline-flex items-center text-action-primary-bg hover:underline",
|
|
164
|
+
children: ["Create token ", /* @__PURE__ */ c(a, { className: "size-3 ml-0.5" })]
|
|
165
|
+
})
|
|
166
|
+
]
|
|
167
|
+
})
|
|
168
|
+
] }),
|
|
169
|
+
T?.ok && /* @__PURE__ */ l("div", {
|
|
170
|
+
className: "text-sm text-status-success-text bg-status-success-bg-subtle rounded-lg px-3 py-2",
|
|
171
|
+
children: [
|
|
172
|
+
m("vibecontrols.gitops.setup.validated", "Token validated"),
|
|
173
|
+
T.account ? ` — ${T.account}` : "",
|
|
174
|
+
T.scopes?.length ? ` (scopes: ${T.scopes.join(", ")})` : ""
|
|
175
|
+
]
|
|
176
|
+
}),
|
|
177
|
+
C && /* @__PURE__ */ c("div", {
|
|
140
178
|
className: "text-sm text-status-error-text bg-status-error-bg-subtle rounded-lg px-3 py-2",
|
|
141
179
|
children: C
|
|
142
180
|
}),
|
|
143
|
-
/* @__PURE__ */
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
181
|
+
/* @__PURE__ */ l("div", {
|
|
182
|
+
className: "flex items-center gap-3",
|
|
183
|
+
children: [/* @__PURE__ */ l("button", {
|
|
184
|
+
type: "submit",
|
|
185
|
+
disabled: O.isPending || !k,
|
|
186
|
+
className: "flex-1 flex items-center justify-center gap-2 px-4 py-2.5 text-sm font-medium rounded-lg bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
|
|
187
|
+
children: [O.isPending && /* @__PURE__ */ c(s, { className: "size-4 animate-spin" }), m("vibecontrols.gitops.setup.connect", "Save and connect")]
|
|
188
|
+
}), p && /* @__PURE__ */ c("button", {
|
|
189
|
+
type: "button",
|
|
190
|
+
onClick: p,
|
|
191
|
+
className: "px-4 py-2.5 text-sm font-medium rounded-lg border border-border-default text-text-secondary hover:text-text-primary transition-colors",
|
|
192
|
+
children: m("vibecontrols.gitops.setup.cancel", "Cancel")
|
|
193
|
+
})]
|
|
148
194
|
})
|
|
149
195
|
]
|
|
150
196
|
})]
|