@burdenoff/microfe-vibecontrols 2026.528.2 → 2026.528.3
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/README.md +1 -0
- package/dist/components/audit/AuditLogDetail.js.map +1 -1
- package/dist/components/audit/AuditLogTable.js.map +1 -1
- package/dist/components/settings/WorkspaceDefaultsSection.js.map +1 -1
- package/dist/components/shared/ConfirmDialog.js.map +1 -1
- package/dist/components/shared/EmptyState.js.map +1 -1
- package/dist/components/targets/TargetCard.js +82 -74
- package/dist/components/targets/TargetCard.js.map +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
- package/dist/generated/wspace-operations.js +1 -0
- package/dist/generated/wspace-operations.js.map +1 -1
- package/dist/generated/wspace-types.js.map +1 -1
- package/dist/pages/OverviewPage.js.map +1 -1
- package/dist/pages/SessionDetailsPage.js +10 -1
- package/dist/pages/SessionDetailsPage.js.map +1 -1
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +274 -259
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/VibeAuditPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/dist/pages/tunnels/ProvidersTab.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ VibeControls microfrontend for Burdenoff products - a modern development environ
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
7
|
This microfrontend provides:
|
|
8
|
+
|
|
8
9
|
- **Agents Management**: Control and monitor development agents
|
|
9
10
|
- **Sessions**: Terminal and SSH session management
|
|
10
11
|
- **Vibes**: Project workflow management
|
|
@@ -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\">\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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"}
|
|
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\">{log.action.replace(/_/g, ' ')}</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\">ID</summary>\n <span className=\"ml-2 break-all font-mono text-[11px]\">{log.actorId}</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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"}
|
|
@@ -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 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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"}
|
|
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').toLowerCase().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').toLowerCase().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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceDefaultsSection.js","names":[],"sources":["../../../src/components/settings/WorkspaceDefaultsSection.tsx"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { OptionalFields } from '@burdenoff/fe-libs/ui';\nimport { SectionCard, SelectField, ToggleField, NumberField, TextAreaField } from './SettingsForm';\n\ninterface AgentOption {\n id: string;\n name: string;\n isActive: boolean;\n}\n\ninterface WorkspaceDefaultsData {\n defaultAgent: string | null;\n defaultSessionType: string;\n autoStartSessions: boolean;\n defaultVibeType: string;\n autoGitSync: boolean;\n agentHeartbeatInterval: number;\n agentAutoReconnect: boolean;\n agentMaxSessions: number;\n logLevel: string;\n telemetryEnabled: boolean;\n autoUpdate: boolean;\n defaultEnvironmentVariables: string | null;\n}\n\ninterface WorkspaceDefaultsSectionProps {\n data: WorkspaceDefaultsData;\n onChange: (data: WorkspaceDefaultsData) => void;\n agents: AgentOption[];\n}\n\nexport function WorkspaceDefaultsSection({\n data,\n onChange,\n agents,\n}: WorkspaceDefaultsSectionProps) {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n },\n [t]\n );\n const defaultAgentOptions = useMemo(\n () => [\n { value: '', label: tr('settings.defaultAgentPlaceholder', 'Select default agent...') },\n ...agents.map((agent) => ({\n value: agent.id,\n label: `${agent.name} ${\n agent.isActive\n ? `(${tr('settings.agentStateActive', 'Active')})`\n : `(${tr('settings.agentStateOffline', 'Offline')})`\n }`,\n })),\n ],\n [agents, tr]\n );\n const sessionTypeOptions = useMemo(\n () => [\n { value: 'TMUX', label: tr('settings.sessionTypeTmux', 'Tmux') },\n { value: 'WEZTERM', label: tr('settings.sessionTypeWezTerm', 'WezTerm') },\n { value: 'ZELLIJ', label: tr('settings.sessionTypeZellij', 'Zellij') },\n { value: 'SSH', label: tr('settings.sessionTypeSsh', 'SSH') },\n { value: 'TERMINAL', label: tr('settings.sessionTypeTerminal', 'Terminal') },\n { value: 'SCRIPT', label: tr('settings.sessionTypeScript', 'Script') },\n ],\n [tr]\n );\n const vibeTypeOptions = useMemo(\n () => [\n { value: 'PROJECT', label: tr('settings.vibeTypeProject', 'Project') },\n { value: 'REPOSITORY', label: tr('settings.vibeTypeRepository', 'Repository') },\n { value: 'WORKSPACE', label: tr('settings.vibeTypeWorkspace', 'Workspace') },\n { value: 'MONOREPO', label: tr('settings.vibeTypeMonorepo', 'Monorepo') },\n { value: 'PACKAGE', label: tr('settings.vibeTypePackage', 'Package') },\n { value: 'CUSTOM', label: tr('settings.vibeTypeCustom', 'Custom') },\n ],\n [tr]\n );\n return (\n <div className=\"space-y-6\">\n <SectionCard\n title={tr('settings.generalDefaults', 'General Defaults')}\n description={tr(\n 'settings.generalDefaultsDescription',\n 'Defaults applied when you create a new session or vibe'\n )}\n >\n <SelectField\n label={tr('settings.defaultAgent', 'Default Agent')}\n value={data.defaultAgent || ''}\n onChange={(v) => onChange({ ...data, defaultAgent: v || null })}\n options={defaultAgentOptions}\n description={tr(\n 'settings.defaultAgentDescription',\n 'Agent used by default when creating new sessions'\n )}\n />\n <SelectField\n label={tr('settings.defaultSessionType', 'Default Session Type')}\n value={data.defaultSessionType}\n onChange={(v) => onChange({ ...data, defaultSessionType: v })}\n options={sessionTypeOptions}\n />\n <ToggleField\n label={tr('settings.autoStartSessions', 'Auto-start Sessions')}\n description={tr(\n 'settings.autoStartSessionsDescription',\n 'Automatically start sessions when a vibe is activated'\n )}\n value={data.autoStartSessions}\n onChange={(v) => onChange({ ...data, autoStartSessions: v })}\n />\n <SelectField\n label={tr('settings.defaultVibeType', 'Default Vibe Type')}\n value={data.defaultVibeType}\n onChange={(v) => onChange({ ...data, defaultVibeType: v })}\n options={vibeTypeOptions}\n />\n <ToggleField\n label={tr('settings.autoGitSync', 'Auto Git Sync')}\n description={tr(\n 'settings.autoGitSyncDescription',\n 'Automatically sync git status when a vibe is activated'\n )}\n value={data.autoGitSync}\n onChange={(v) => onChange({ ...data, autoGitSync: v })}\n />\n </SectionCard>\n\n <OptionalFields\n title={tr('settings.agentTuning', 'Agent tuning')}\n description={tr(\n 'settings.agentTuningDescription',\n 'Heartbeat, capacity, reconnect — most users keep the defaults'\n )}\n >\n <NumberField\n label={tr('settings.heartbeatInterval', 'Heartbeat Interval (seconds)')}\n value={data.agentHeartbeatInterval}\n onChange={(v) => onChange({ ...data, agentHeartbeatInterval: v })}\n min={10}\n max={300}\n description={tr(\n 'settings.heartbeatIntervalDescription',\n 'How often agents send heartbeat signals (10-300 seconds)'\n )}\n />\n <NumberField\n label={tr('settings.maxSessionsPerAgent', 'Max Sessions Per Agent')}\n value={data.agentMaxSessions}\n onChange={(v) => onChange({ ...data, agentMaxSessions: v })}\n min={1}\n max={100}\n />\n <ToggleField\n label={tr('settings.autoReconnect', 'Auto-reconnect')}\n description={tr(\n 'settings.autoReconnectDescription',\n 'Automatically reconnect agents after network interruptions'\n )}\n value={data.agentAutoReconnect}\n onChange={(v) => onChange({ ...data, agentAutoReconnect: v })}\n />\n <TextAreaField\n label={tr('settings.defaultEnvVars', 'Default Environment Variables')}\n value={data.defaultEnvironmentVariables || ''}\n onChange={(v) => onChange({ ...data, defaultEnvironmentVariables: v || null })}\n placeholder={tr(
|
|
1
|
+
{"version":3,"file":"WorkspaceDefaultsSection.js","names":[],"sources":["../../../src/components/settings/WorkspaceDefaultsSection.tsx"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { OptionalFields } from '@burdenoff/fe-libs/ui';\nimport { SectionCard, SelectField, ToggleField, NumberField, TextAreaField } from './SettingsForm';\n\ninterface AgentOption {\n id: string;\n name: string;\n isActive: boolean;\n}\n\ninterface WorkspaceDefaultsData {\n defaultAgent: string | null;\n defaultSessionType: string;\n autoStartSessions: boolean;\n defaultVibeType: string;\n autoGitSync: boolean;\n agentHeartbeatInterval: number;\n agentAutoReconnect: boolean;\n agentMaxSessions: number;\n logLevel: string;\n telemetryEnabled: boolean;\n autoUpdate: boolean;\n defaultEnvironmentVariables: string | null;\n}\n\ninterface WorkspaceDefaultsSectionProps {\n data: WorkspaceDefaultsData;\n onChange: (data: WorkspaceDefaultsData) => void;\n agents: AgentOption[];\n}\n\nexport function WorkspaceDefaultsSection({\n data,\n onChange,\n agents,\n}: WorkspaceDefaultsSectionProps) {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n },\n [t]\n );\n const defaultAgentOptions = useMemo(\n () => [\n { value: '', label: tr('settings.defaultAgentPlaceholder', 'Select default agent...') },\n ...agents.map((agent) => ({\n value: agent.id,\n label: `${agent.name} ${\n agent.isActive\n ? `(${tr('settings.agentStateActive', 'Active')})`\n : `(${tr('settings.agentStateOffline', 'Offline')})`\n }`,\n })),\n ],\n [agents, tr]\n );\n const sessionTypeOptions = useMemo(\n () => [\n { value: 'TMUX', label: tr('settings.sessionTypeTmux', 'Tmux') },\n { value: 'WEZTERM', label: tr('settings.sessionTypeWezTerm', 'WezTerm') },\n { value: 'ZELLIJ', label: tr('settings.sessionTypeZellij', 'Zellij') },\n { value: 'SSH', label: tr('settings.sessionTypeSsh', 'SSH') },\n { value: 'TERMINAL', label: tr('settings.sessionTypeTerminal', 'Terminal') },\n { value: 'SCRIPT', label: tr('settings.sessionTypeScript', 'Script') },\n ],\n [tr]\n );\n const vibeTypeOptions = useMemo(\n () => [\n { value: 'PROJECT', label: tr('settings.vibeTypeProject', 'Project') },\n { value: 'REPOSITORY', label: tr('settings.vibeTypeRepository', 'Repository') },\n { value: 'WORKSPACE', label: tr('settings.vibeTypeWorkspace', 'Workspace') },\n { value: 'MONOREPO', label: tr('settings.vibeTypeMonorepo', 'Monorepo') },\n { value: 'PACKAGE', label: tr('settings.vibeTypePackage', 'Package') },\n { value: 'CUSTOM', label: tr('settings.vibeTypeCustom', 'Custom') },\n ],\n [tr]\n );\n return (\n <div className=\"space-y-6\">\n <SectionCard\n title={tr('settings.generalDefaults', 'General Defaults')}\n description={tr(\n 'settings.generalDefaultsDescription',\n 'Defaults applied when you create a new session or vibe'\n )}\n >\n <SelectField\n label={tr('settings.defaultAgent', 'Default Agent')}\n value={data.defaultAgent || ''}\n onChange={(v) => onChange({ ...data, defaultAgent: v || null })}\n options={defaultAgentOptions}\n description={tr(\n 'settings.defaultAgentDescription',\n 'Agent used by default when creating new sessions'\n )}\n />\n <SelectField\n label={tr('settings.defaultSessionType', 'Default Session Type')}\n value={data.defaultSessionType}\n onChange={(v) => onChange({ ...data, defaultSessionType: v })}\n options={sessionTypeOptions}\n />\n <ToggleField\n label={tr('settings.autoStartSessions', 'Auto-start Sessions')}\n description={tr(\n 'settings.autoStartSessionsDescription',\n 'Automatically start sessions when a vibe is activated'\n )}\n value={data.autoStartSessions}\n onChange={(v) => onChange({ ...data, autoStartSessions: v })}\n />\n <SelectField\n label={tr('settings.defaultVibeType', 'Default Vibe Type')}\n value={data.defaultVibeType}\n onChange={(v) => onChange({ ...data, defaultVibeType: v })}\n options={vibeTypeOptions}\n />\n <ToggleField\n label={tr('settings.autoGitSync', 'Auto Git Sync')}\n description={tr(\n 'settings.autoGitSyncDescription',\n 'Automatically sync git status when a vibe is activated'\n )}\n value={data.autoGitSync}\n onChange={(v) => onChange({ ...data, autoGitSync: v })}\n />\n </SectionCard>\n\n <OptionalFields\n title={tr('settings.agentTuning', 'Agent tuning')}\n description={tr(\n 'settings.agentTuningDescription',\n 'Heartbeat, capacity, reconnect — most users keep the defaults'\n )}\n >\n <NumberField\n label={tr('settings.heartbeatInterval', 'Heartbeat Interval (seconds)')}\n value={data.agentHeartbeatInterval}\n onChange={(v) => onChange({ ...data, agentHeartbeatInterval: v })}\n min={10}\n max={300}\n description={tr(\n 'settings.heartbeatIntervalDescription',\n 'How often agents send heartbeat signals (10-300 seconds)'\n )}\n />\n <NumberField\n label={tr('settings.maxSessionsPerAgent', 'Max Sessions Per Agent')}\n value={data.agentMaxSessions}\n onChange={(v) => onChange({ ...data, agentMaxSessions: v })}\n min={1}\n max={100}\n />\n <ToggleField\n label={tr('settings.autoReconnect', 'Auto-reconnect')}\n description={tr(\n 'settings.autoReconnectDescription',\n 'Automatically reconnect agents after network interruptions'\n )}\n value={data.agentAutoReconnect}\n onChange={(v) => onChange({ ...data, agentAutoReconnect: v })}\n />\n <TextAreaField\n label={tr('settings.defaultEnvVars', 'Default Environment Variables')}\n value={data.defaultEnvironmentVariables || ''}\n onChange={(v) => onChange({ ...data, defaultEnvironmentVariables: v || null })}\n placeholder={tr('settings.defaultEnvVarsPlaceholder', 'KEY=value\\nANOTHER_KEY=value')}\n description={tr(\n 'settings.defaultEnvVarsDescription',\n 'Environment variables applied to all new vibes (one per line, KEY=value format)'\n )}\n />\n </OptionalFields>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/components/shared/ConfirmDialog.tsx"],"sourcesContent":["import { AlertTriangle } from 'lucide-react';\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface ConfirmDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onConfirm: () => void;\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: 'danger' | 'warning' | 'default';\n isLoading?: boolean;\n}\n\nconst VARIANT_STYLES: Record<\n NonNullable<ConfirmDialogProps['variant']>,\n { iconWrap: string; confirmBtn: string }\n> = {\n danger: {\n iconWrap: 'bg-status-error-bg-subtle text-status-error-text',\n confirmBtn: 'bg-status-error-bg text-text-inverse hover:bg-status-error-text-hover',\n },\n warning: {\n iconWrap: 'bg-status-warning-bg-subtle text-status-warning-text',\n confirmBtn: 'bg-status-warning-bg text-text-primary hover:bg-status-warning-text-hover',\n },\n default: {\n iconWrap: 'bg-action-primary-bg text-action-primary-text',\n confirmBtn: 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover',\n },\n};\n\nexport function ConfirmDialog({\n isOpen,\n onClose,\n onConfirm,\n title,\n message,\n confirmLabel,\n cancelLabel,\n variant = 'default',\n isLoading = false,\n}: ConfirmDialogProps) {\n const tr = useTr();\n const resolvedConfirmLabel =\n confirmLabel ?? tr('vibecontrols.shared.confirmDialog.confirm', 'Confirm');\n const resolvedCancelLabel =\n cancelLabel ?? tr('vibecontrols.shared.confirmDialog.cancel', 'Cancel');\n const styles = VARIANT_STYLES[variant];\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <ResponsiveDialogHeader>\n <div className=\"flex items-start gap-3\">\n <div\n className={`flex-shrink-0 size-10 rounded-full flex items-center justify-center ${styles.iconWrap}`}\n aria-hidden=\"true\"\n >\n <AlertTriangle className=\"size-5\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <ResponsiveDialogTitle>{title}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription className=\"mt-1\"
|
|
1
|
+
{"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/components/shared/ConfirmDialog.tsx"],"sourcesContent":["import { AlertTriangle } from 'lucide-react';\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { useTr } from '../../shared/hooks/useTr';\n\ninterface ConfirmDialogProps {\n isOpen: boolean;\n onClose: () => void;\n onConfirm: () => void;\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: 'danger' | 'warning' | 'default';\n isLoading?: boolean;\n}\n\nconst VARIANT_STYLES: Record<\n NonNullable<ConfirmDialogProps['variant']>,\n { iconWrap: string; confirmBtn: string }\n> = {\n danger: {\n iconWrap: 'bg-status-error-bg-subtle text-status-error-text',\n confirmBtn: 'bg-status-error-bg text-text-inverse hover:bg-status-error-text-hover',\n },\n warning: {\n iconWrap: 'bg-status-warning-bg-subtle text-status-warning-text',\n confirmBtn: 'bg-status-warning-bg text-text-primary hover:bg-status-warning-text-hover',\n },\n default: {\n iconWrap: 'bg-action-primary-bg text-action-primary-text',\n confirmBtn: 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover',\n },\n};\n\nexport function ConfirmDialog({\n isOpen,\n onClose,\n onConfirm,\n title,\n message,\n confirmLabel,\n cancelLabel,\n variant = 'default',\n isLoading = false,\n}: ConfirmDialogProps) {\n const tr = useTr();\n const resolvedConfirmLabel =\n confirmLabel ?? tr('vibecontrols.shared.confirmDialog.confirm', 'Confirm');\n const resolvedCancelLabel =\n cancelLabel ?? tr('vibecontrols.shared.confirmDialog.cancel', 'Cancel');\n const styles = VARIANT_STYLES[variant];\n\n return (\n <ResponsiveDialog\n open={isOpen}\n onOpenChange={(open) => {\n if (!open) onClose();\n }}\n >\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <ResponsiveDialogHeader>\n <div className=\"flex items-start gap-3\">\n <div\n className={`flex-shrink-0 size-10 rounded-full flex items-center justify-center ${styles.iconWrap}`}\n aria-hidden=\"true\"\n >\n <AlertTriangle className=\"size-5\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <ResponsiveDialogTitle>{title}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription className=\"mt-1\">{message}</ResponsiveDialogDescription>\n </div>\n </div>\n </ResponsiveDialogHeader>\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={onClose}\n disabled={isLoading}\n className=\"min-h-11 px-4 py-2 text-sm font-medium text-text-primary bg-bg-surface border border-border-default rounded-md hover:bg-bg-elevated transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40\"\n >\n {resolvedCancelLabel}\n </button>\n <button\n type=\"button\"\n onClick={onConfirm}\n disabled={isLoading}\n className={`min-h-11 px-4 py-2 text-sm font-medium rounded-md transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40 ${styles.confirmBtn}`}\n >\n {isLoading\n ? tr('vibecontrols.shared.confirmDialog.processing', 'Processing...')\n : resolvedConfirmLabel}\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n"],"mappings":";;;;;AAuBA,IAAM,IAGF;CACF,QAAQ;EACN,UAAU;EACV,YAAY;EACb;CACD,SAAS;EACP,UAAU;EACV,YAAY;EACb;CACD,SAAS;EACP,UAAU;EACV,YAAY;EACb;CACF;AAED,SAAgB,EAAc,EAC5B,WACA,YACA,cACA,UACA,YACA,iBACA,gBACA,aAAU,WACV,eAAY,MACS;CACrB,IAAM,IAAK,GAAO,EACZ,IACJ,KAAgB,EAAG,6CAA6C,UAAU,EACtE,IACJ,KAAe,EAAG,4CAA4C,SAAS,EACnE,IAAS,EAAe;AAE9B,QACE,kBAAC,GAAD;EACE,MAAM;EACN,eAAe,MAAS;AACtB,GAAK,KAAM,GAAS;;YAGtB,kBAAC,GAAD;GAAyB,WAAU;aAAnC,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KACE,WAAW,uEAAuE,EAAO;KACzF,eAAY;eAEZ,kBAAC,GAAD,EAAe,WAAU,UAAW,CAAA;KAChC,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAA,UAAwB,GAA8B,CAAA,EACtD,kBAAC,GAAD;MAA6B,WAAU;gBAAQ;MAAsC,CAAA,CACjF;OACF;OACiB,CAAA,EACzB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU;IACV,WAAU;cAET;IACM,CAAA,EACT,kBAAC,UAAD;IACE,MAAK;IACL,SAAS;IACT,UAAU;IACV,WAAW,2JAA2J,EAAO;cAE5K,IACG,EAAG,gDAAgD,gBAAgB,GACnE;IACG,CAAA,CACc,EAAA,CAAA,CACD;;EACT,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/components/shared/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { EmptyState as CanonicalEmptyState } from '@burdenoff/fe-libs/ui';\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n}\n\n/**\n * Local wrapper around `EmptyState` from `@burdenoff/fe-libs/ui`.\n *\n * Keeps the existing microfe-vibecontrols call sites stable while routing all\n * empty-state rendering through the canonical primitive.\n */\nexport function EmptyState({ icon, title, description, action }: EmptyStateProps) {\n return (\n <CanonicalEmptyState
|
|
1
|
+
{"version":3,"file":"EmptyState.js","names":[],"sources":["../../../src/components/shared/EmptyState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { EmptyState as CanonicalEmptyState } from '@burdenoff/fe-libs/ui';\n\ninterface EmptyStateProps {\n icon?: ReactNode;\n title: string;\n description?: string;\n action?: ReactNode;\n}\n\n/**\n * Local wrapper around `EmptyState` from `@burdenoff/fe-libs/ui`.\n *\n * Keeps the existing microfe-vibecontrols call sites stable while routing all\n * empty-state rendering through the canonical primitive.\n */\nexport function EmptyState({ icon, title, description, action }: EmptyStateProps) {\n return (\n <CanonicalEmptyState icon={icon} title={title} description={description} action={action} />\n );\n}\n"],"mappings":";;;AAgBA,SAAgB,EAAW,EAAE,SAAM,UAAO,gBAAa,aAA2B;AAChF,QACE,kBAAC,GAAD;EAA2B;EAAa;EAAoB;EAAqB;EAAU,CAAA"}
|
|
@@ -2,11 +2,11 @@ import { useTr as e } from "../../shared/hooks/useTr.js";
|
|
|
2
2
|
import { StatusBadge as t } from "../shared/StatusBadge.js";
|
|
3
3
|
import "../shared/index.js";
|
|
4
4
|
import { useState as n } from "react";
|
|
5
|
-
import { CheckCircle as r, Download as i, FlaskConical as a,
|
|
6
|
-
import { AnimatePresence as
|
|
7
|
-
import { Fragment as
|
|
5
|
+
import { CheckCircle as r, Download as i, FlaskConical as a, Loader2 as o, MoreVertical as s, Pencil as c, Server as l, Terminal as u, Trash2 as d, X as f } from "lucide-react";
|
|
6
|
+
import { AnimatePresence as p, motion as m } from "framer-motion";
|
|
7
|
+
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
8
8
|
//#region src/components/targets/TargetCard.tsx
|
|
9
|
-
var
|
|
9
|
+
var v = {
|
|
10
10
|
connected: {
|
|
11
11
|
variant: "success",
|
|
12
12
|
label: "Connected"
|
|
@@ -19,15 +19,15 @@ var _ = {
|
|
|
19
19
|
variant: "neutral",
|
|
20
20
|
label: "Unknown"
|
|
21
21
|
}
|
|
22
|
-
},
|
|
22
|
+
}, y = {
|
|
23
23
|
DIRECT: "bg-accent-blue-subtle text-accent-blue",
|
|
24
24
|
SSH: "bg-status-success-bg-subtle text-status-success-text",
|
|
25
25
|
RDP: "bg-status-warning-bg-subtle text-status-warning-text",
|
|
26
26
|
VNC: "bg-accent-purple-subtle text-accent-purple"
|
|
27
|
-
},
|
|
28
|
-
let
|
|
29
|
-
return /* @__PURE__ */
|
|
30
|
-
id: `target-row-${
|
|
27
|
+
}, b = ({ target: b, onTest: x, onTerminal: S, onOpenDetail: C, onInstallAgent: w, onUninstallAgent: T, onDelete: E, onEdit: D, selected: O = !1, onToggleSelect: k, highlighted: A = !1, isStartingTerminal: j = !1 }) => {
|
|
28
|
+
let M = e(), [N, P] = n(!1), F = b.agents.length > 0;
|
|
29
|
+
return /* @__PURE__ */ _(m.div, {
|
|
30
|
+
id: `target-row-${b.id}`,
|
|
31
31
|
whileHover: {
|
|
32
32
|
y: -1,
|
|
33
33
|
transition: {
|
|
@@ -41,78 +41,78 @@ var _ = {
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
whileTap: { scale: .99 },
|
|
44
|
-
className: `bg-bg-surface border rounded-lg p-4 h-full hover:border-border-strong hover:shadow-md transition-all cursor-pointer ${
|
|
45
|
-
onClick: () => (
|
|
44
|
+
className: `bg-bg-surface border rounded-lg p-4 h-full hover:border-border-strong hover:shadow-md transition-all cursor-pointer ${O ? "border-action-primary-bg ring-1 ring-action-primary-bg/30" : A ? "border-action-primary-bg bg-action-primary-bg/5 shadow-sm" : "border-border-default"}`,
|
|
45
|
+
onClick: () => (C ?? S)?.(b.id),
|
|
46
46
|
children: [
|
|
47
|
-
/* @__PURE__ */
|
|
47
|
+
/* @__PURE__ */ _("div", {
|
|
48
48
|
className: "flex items-start justify-between gap-2",
|
|
49
|
-
children: [/* @__PURE__ */
|
|
49
|
+
children: [/* @__PURE__ */ _("div", {
|
|
50
50
|
className: "flex items-start gap-2 sm:gap-3 min-w-0 flex-1",
|
|
51
51
|
children: [
|
|
52
|
-
|
|
52
|
+
k && /* @__PURE__ */ g("button", {
|
|
53
53
|
type: "button",
|
|
54
54
|
onClick: (e) => {
|
|
55
|
-
e.stopPropagation(),
|
|
55
|
+
e.stopPropagation(), k();
|
|
56
56
|
},
|
|
57
|
-
className: `flex-shrink-0 size-5 min-w-[1.25rem] min-h-[1.25rem] rounded border transition-colors mt-0.5 ${
|
|
58
|
-
children:
|
|
57
|
+
className: `flex-shrink-0 size-5 min-w-[1.25rem] min-h-[1.25rem] rounded border transition-colors mt-0.5 ${O ? "bg-action-primary-bg border-action-primary-bg text-action-primary-text" : "border-border-default hover:border-border-strong bg-bg-surface"} flex items-center justify-center`,
|
|
58
|
+
children: O && /* @__PURE__ */ g("svg", {
|
|
59
59
|
className: "size-3",
|
|
60
60
|
fill: "none",
|
|
61
61
|
viewBox: "0 0 24 24",
|
|
62
62
|
stroke: "currentColor",
|
|
63
63
|
strokeWidth: 3,
|
|
64
|
-
children: /* @__PURE__ */
|
|
64
|
+
children: /* @__PURE__ */ g("path", {
|
|
65
65
|
strokeLinecap: "round",
|
|
66
66
|
strokeLinejoin: "round",
|
|
67
67
|
d: "M5 13l4 4L19 7"
|
|
68
68
|
})
|
|
69
69
|
})
|
|
70
70
|
}),
|
|
71
|
-
/* @__PURE__ */
|
|
71
|
+
/* @__PURE__ */ g("div", {
|
|
72
72
|
className: "flex-shrink-0 size-8 sm:w-10 sm:h-10 rounded-lg bg-bg-sunken flex items-center justify-center",
|
|
73
|
-
children: /* @__PURE__ */
|
|
73
|
+
children: /* @__PURE__ */ g(l, { className: "size-4 sm:w-5 sm:h-5 text-text-secondary" })
|
|
74
74
|
}),
|
|
75
|
-
/* @__PURE__ */
|
|
75
|
+
/* @__PURE__ */ _("div", {
|
|
76
76
|
className: "min-w-0 flex-1",
|
|
77
|
-
children: [/* @__PURE__ */
|
|
77
|
+
children: [/* @__PURE__ */ _("div", {
|
|
78
78
|
className: "flex items-center gap-1.5 sm:gap-2 flex-wrap",
|
|
79
|
-
children: [/* @__PURE__ */
|
|
79
|
+
children: [/* @__PURE__ */ g("h3", {
|
|
80
80
|
className: "font-semibold text-text-primary truncate max-w-[120px] sm:max-w-none text-sm sm:text-base",
|
|
81
|
-
children:
|
|
82
|
-
}), /* @__PURE__ */
|
|
83
|
-
className: `inline-flex items-center px-1.5 py-0.5 text-xs font-semibold rounded ${
|
|
84
|
-
children:
|
|
81
|
+
children: b.name
|
|
82
|
+
}), /* @__PURE__ */ g("span", {
|
|
83
|
+
className: `inline-flex items-center px-1.5 py-0.5 text-xs font-semibold rounded ${y[b.type]}`,
|
|
84
|
+
children: b.type
|
|
85
85
|
})]
|
|
86
|
-
}), /* @__PURE__ */
|
|
86
|
+
}), /* @__PURE__ */ g("p", {
|
|
87
87
|
className: "text-xs sm:text-sm text-text-secondary truncate",
|
|
88
|
-
children:
|
|
88
|
+
children: b.host ? `${b.username ? `${b.username}@` : ""}${b.host}${b.port ? `:${b.port}` : ""}` : b.label || `ID: ${b.id.slice(0, 8)}`
|
|
89
89
|
})]
|
|
90
90
|
})
|
|
91
91
|
]
|
|
92
|
-
}), /* @__PURE__ */
|
|
92
|
+
}), /* @__PURE__ */ _("div", {
|
|
93
93
|
className: "flex items-center gap-1 sm:gap-2 flex-shrink-0",
|
|
94
|
-
children: [/* @__PURE__ */
|
|
95
|
-
status:
|
|
96
|
-
variant:
|
|
97
|
-
}), /* @__PURE__ */
|
|
94
|
+
children: [/* @__PURE__ */ g(t, {
|
|
95
|
+
status: v[b.status].label,
|
|
96
|
+
variant: v[b.status].variant
|
|
97
|
+
}), /* @__PURE__ */ _("div", {
|
|
98
98
|
className: "relative",
|
|
99
|
-
children: [/* @__PURE__ */
|
|
99
|
+
children: [/* @__PURE__ */ g("button", {
|
|
100
100
|
type: "button",
|
|
101
101
|
onClick: (e) => {
|
|
102
|
-
e.stopPropagation(),
|
|
102
|
+
e.stopPropagation(), P(!N);
|
|
103
103
|
},
|
|
104
104
|
className: "p-1 sm:p-1.5 rounded hover:bg-bg-sunken transition-colors flex items-center justify-center",
|
|
105
105
|
"aria-label": "Target actions menu",
|
|
106
|
-
children: /* @__PURE__ */
|
|
107
|
-
}), /* @__PURE__ */
|
|
106
|
+
children: /* @__PURE__ */ g(s, { className: "size-4 text-text-primary opacity-70 hover:opacity-100" })
|
|
107
|
+
}), /* @__PURE__ */ g(p, { children: N && /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g("div", {
|
|
108
108
|
role: "button",
|
|
109
109
|
tabIndex: 0,
|
|
110
110
|
onKeyDown: (e) => {
|
|
111
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
111
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), P(!1));
|
|
112
112
|
},
|
|
113
113
|
className: "fixed inset-0 z-10",
|
|
114
|
-
onClick: () =>
|
|
115
|
-
}), /* @__PURE__ */
|
|
114
|
+
onClick: () => P(!1)
|
|
115
|
+
}), /* @__PURE__ */ _(m.div, {
|
|
116
116
|
initial: {
|
|
117
117
|
opacity: 0,
|
|
118
118
|
scale: .95,
|
|
@@ -131,97 +131,105 @@ var _ = {
|
|
|
131
131
|
transition: { duration: .15 },
|
|
132
132
|
className: "absolute right-0 mt-1 w-44 bg-bg-surface border border-border-default rounded-lg shadow-lg z-20",
|
|
133
133
|
children: [
|
|
134
|
-
|
|
134
|
+
x && /* @__PURE__ */ _("button", {
|
|
135
135
|
type: "button",
|
|
136
136
|
onClick: (e) => {
|
|
137
|
-
e.stopPropagation(), b
|
|
137
|
+
e.stopPropagation(), x(b.id), P(!1);
|
|
138
138
|
},
|
|
139
139
|
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg transition-colors",
|
|
140
|
-
children: [/* @__PURE__ */
|
|
140
|
+
children: [/* @__PURE__ */ g(a, { className: "size-4" }), M("vibecontrols.targets.testConnection", "Test Connection")]
|
|
141
141
|
}),
|
|
142
|
-
|
|
142
|
+
S && /* @__PURE__ */ g("button", {
|
|
143
143
|
type: "button",
|
|
144
|
+
disabled: j,
|
|
144
145
|
onClick: (e) => {
|
|
145
|
-
e.stopPropagation(),
|
|
146
|
+
e.stopPropagation(), !j && (S(b.id), P(!1));
|
|
146
147
|
},
|
|
147
|
-
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors",
|
|
148
|
-
children: [/* @__PURE__ */ h(
|
|
148
|
+
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors disabled:opacity-60 disabled:cursor-not-allowed",
|
|
149
|
+
children: j ? /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(o, { className: "size-4 animate-spin" }), M("vibecontrols.targets.startingTerminal", "Starting…")] }) : /* @__PURE__ */ _(h, { children: [/* @__PURE__ */ g(u, { className: "size-4" }), M("vibecontrols.targets.openTerminal", "Open Terminal")] })
|
|
149
150
|
}),
|
|
150
|
-
|
|
151
|
+
D && /* @__PURE__ */ _("button", {
|
|
151
152
|
type: "button",
|
|
152
153
|
onClick: (e) => {
|
|
153
|
-
e.stopPropagation(),
|
|
154
|
+
e.stopPropagation(), D(b), P(!1);
|
|
154
155
|
},
|
|
155
156
|
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken transition-colors",
|
|
156
|
-
children: [/* @__PURE__ */
|
|
157
|
+
children: [/* @__PURE__ */ g(c, { className: "size-4" }), M("vibecontrols.targets.editTarget", "Edit Target")]
|
|
157
158
|
}),
|
|
158
|
-
|
|
159
|
+
b.type !== "DIRECT" && !F && w && /* @__PURE__ */ _("button", {
|
|
159
160
|
type: "button",
|
|
160
161
|
onClick: (e) => {
|
|
161
|
-
e.stopPropagation(),
|
|
162
|
+
e.stopPropagation(), w(b), P(!1);
|
|
162
163
|
},
|
|
163
164
|
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-action-primary-bg hover:bg-bg-sunken transition-colors",
|
|
164
|
-
children: [/* @__PURE__ */
|
|
165
|
+
children: [/* @__PURE__ */ g(i, { className: "size-4" }), M("vibecontrols.targets.installAgent", "Install Agent")]
|
|
165
166
|
}),
|
|
166
|
-
|
|
167
|
+
b.type !== "DIRECT" && F && T && /* @__PURE__ */ _("button", {
|
|
167
168
|
type: "button",
|
|
168
169
|
onClick: (e) => {
|
|
169
|
-
e.stopPropagation(),
|
|
170
|
+
e.stopPropagation(), T(b), P(!1);
|
|
170
171
|
},
|
|
171
172
|
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken transition-colors",
|
|
172
|
-
children: [/* @__PURE__ */
|
|
173
|
+
children: [/* @__PURE__ */ g(d, { className: "size-4" }), M("vibecontrols.targets.uninstallAgent", "Uninstall Agent")]
|
|
173
174
|
}),
|
|
174
|
-
|
|
175
|
+
E && /* @__PURE__ */ _("button", {
|
|
175
176
|
type: "button",
|
|
176
177
|
onClick: (e) => {
|
|
177
|
-
e.stopPropagation(),
|
|
178
|
+
e.stopPropagation(), E(b.id), P(!1);
|
|
178
179
|
},
|
|
179
180
|
className: "flex items-center gap-2 w-full px-3 py-2 text-sm text-status-error-text hover:bg-bg-sunken rounded-b-lg transition-colors",
|
|
180
|
-
children: [/* @__PURE__ */
|
|
181
|
+
children: [/* @__PURE__ */ g(f, { className: "size-4" }), M("vibecontrols.targets.deleteTarget", "Delete Target")]
|
|
181
182
|
})
|
|
182
183
|
]
|
|
183
184
|
})] }) })]
|
|
184
185
|
})]
|
|
185
186
|
})]
|
|
186
187
|
}),
|
|
187
|
-
/* @__PURE__ */
|
|
188
|
+
j && /* @__PURE__ */ _("div", {
|
|
189
|
+
className: "mt-3 inline-flex items-center gap-2 rounded-md border border-action-primary-border bg-action-primary-bg/10 px-2.5 py-1 text-xs text-action-primary-text",
|
|
190
|
+
children: [/* @__PURE__ */ g(o, {
|
|
191
|
+
size: 12,
|
|
192
|
+
className: "animate-spin"
|
|
193
|
+
}), M("vibecontrols.targets.startingTerminalHint", "Starting terminal session…")]
|
|
194
|
+
}),
|
|
195
|
+
/* @__PURE__ */ _("div", {
|
|
188
196
|
className: "mt-3 flex items-center gap-3 text-sm",
|
|
189
197
|
children: [
|
|
190
|
-
|
|
198
|
+
F ? /* @__PURE__ */ _("span", {
|
|
191
199
|
className: "inline-flex items-center gap-1 rounded-full border border-status-success-border px-2 py-0.5 text-xs bg-status-success-bg-subtle text-status-success-text",
|
|
192
200
|
children: [
|
|
193
|
-
/* @__PURE__ */
|
|
201
|
+
/* @__PURE__ */ g(r, { size: 10 }),
|
|
194
202
|
"Agent: ",
|
|
195
|
-
|
|
203
|
+
b.agents[0].name
|
|
196
204
|
]
|
|
197
|
-
}) : /* @__PURE__ */
|
|
205
|
+
}) : /* @__PURE__ */ g("span", {
|
|
198
206
|
className: "inline-flex items-center gap-1 rounded-full border border-border-default px-2 py-0.5 text-xs bg-bg-sunken text-text-tertiary",
|
|
199
207
|
children: "No agent"
|
|
200
208
|
}),
|
|
201
|
-
|
|
209
|
+
b.label && !b.host && /* @__PURE__ */ g("span", {
|
|
202
210
|
className: "text-xs text-text-tertiary",
|
|
203
|
-
children:
|
|
211
|
+
children: b.label
|
|
204
212
|
}),
|
|
205
|
-
|
|
213
|
+
b.host && b.label && /* @__PURE__ */ g("span", {
|
|
206
214
|
className: "text-xs text-text-tertiary",
|
|
207
|
-
children:
|
|
215
|
+
children: b.label
|
|
208
216
|
})
|
|
209
217
|
]
|
|
210
218
|
}),
|
|
211
|
-
|
|
219
|
+
b.tags.length > 0 && /* @__PURE__ */ _("div", {
|
|
212
220
|
className: "mt-2 flex flex-wrap gap-1",
|
|
213
|
-
children: [
|
|
221
|
+
children: [b.tags.slice(0, 4).map((e) => /* @__PURE__ */ g("span", {
|
|
214
222
|
className: "px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded",
|
|
215
223
|
children: e
|
|
216
|
-
}, e)),
|
|
224
|
+
}, e)), b.tags.length > 4 && /* @__PURE__ */ _("span", {
|
|
217
225
|
className: "px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded",
|
|
218
|
-
children: ["+",
|
|
226
|
+
children: ["+", b.tags.length - 4]
|
|
219
227
|
})]
|
|
220
228
|
})
|
|
221
229
|
]
|
|
222
230
|
});
|
|
223
231
|
};
|
|
224
232
|
//#endregion
|
|
225
|
-
export {
|
|
233
|
+
export { b as TargetCard };
|
|
226
234
|
|
|
227
235
|
//# sourceMappingURL=TargetCard.js.map
|