@burdenoff/microfe-vibecontrols 2026.623.1 → 2026.623.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/actions/ActionCard.js +2 -2
- package/dist/components/actions/ActionCard.js.map +1 -1
- package/dist/components/actions/ExecutionHistory.js +1 -1
- package/dist/components/actions/ExecutionHistory.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerAdminBar.js +1 -1
- package/dist/components/agent-manager/AgentManagerAdminBar.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerChatPane.js +2 -2
- package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerInputArea.js +4 -4
- package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerLayout.js +1 -1
- package/dist/components/agent-manager/AgentManagerLayout.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerMessageItem.js +1 -1
- package/dist/components/agent-manager/AgentManagerMessageItem.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerSidebar.js +5 -5
- package/dist/components/agent-manager/AgentManagerSidebar.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerTab.js +1 -1
- package/dist/components/agent-manager/AgentManagerTab.js.map +1 -1
- package/dist/components/agent-manager/AgentManagerTabBar.js +1 -1
- package/dist/components/agent-manager/AgentManagerTabBar.js.map +1 -1
- package/dist/components/agent-manager/BridleConfigPanel.js +23 -23
- package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/PluginInstallModal.js +1 -1
- package/dist/components/agent-manager/PluginInstallModal.js.map +1 -1
- package/dist/components/agent-manager/ProfilesPanel.js +5 -5
- package/dist/components/agent-manager/ProfilesPanel.js.map +1 -1
- package/dist/components/agent-manager/controls/AutonomySelector.js +1 -1
- package/dist/components/agent-manager/controls/AutonomySelector.js.map +1 -1
- package/dist/components/agent-manager/controls/SdkSelector.js +1 -1
- package/dist/components/agent-manager/controls/SdkSelector.js.map +1 -1
- package/dist/components/agent-manager/controls/VoiceToggle.js +1 -1
- package/dist/components/agent-manager/controls/VoiceToggle.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionConfigPanel.js +6 -6
- package/dist/components/agent-manager/detail/SessionConfigPanel.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionLogsPanel.js +5 -5
- package/dist/components/agent-manager/detail/SessionLogsPanel.js.map +1 -1
- package/dist/components/agent-manager/detail/SessionToolsPanel.js +1 -1
- package/dist/components/agent-manager/detail/SessionToolsPanel.js.map +1 -1
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js +2 -2
- package/dist/components/agent-manager/dialogs/NewSessionDialog.js.map +1 -1
- package/dist/components/agent-manager/dialogs/RenameSessionDialog.js +1 -1
- package/dist/components/agent-manager/dialogs/RenameSessionDialog.js.map +1 -1
- package/dist/components/agents/AgentCard.js +14 -11
- package/dist/components/agents/AgentCard.js.map +1 -1
- package/dist/components/ai/AIContextsTab.js +1 -1
- package/dist/components/ai/AIContextsTab.js.map +1 -1
- package/dist/components/ai/AIOverviewTab.js +4 -4
- package/dist/components/ai/AIOverviewTab.js.map +1 -1
- package/dist/components/ai/AIPlanPanel.js +4 -4
- package/dist/components/ai/AIPlanPanel.js.map +1 -1
- package/dist/components/ai/AIPlaygroundTab.js +1 -1
- package/dist/components/ai/AIPlaygroundTab.js.map +1 -1
- package/dist/components/ai/AIPromptsTab.js +2 -2
- package/dist/components/ai/AIPromptsTab.js.map +1 -1
- package/dist/components/ai/AIProviderCredentialsCard.js +4 -4
- package/dist/components/ai/AIProviderCredentialsCard.js.map +1 -1
- package/dist/components/ai/AIQueueTab.js +4 -4
- package/dist/components/ai/AIQueueTab.js.map +1 -1
- package/dist/components/ai/AISessionsTab.js +4 -4
- package/dist/components/ai/AISessionsTab.js.map +1 -1
- package/dist/components/ai/AITasksTab.js +1 -1
- package/dist/components/ai/AITasksTab.js.map +1 -1
- package/dist/components/ai/ClaudeCredentialsCard.js +3 -3
- package/dist/components/ai/ClaudeCredentialsCard.js.map +1 -1
- package/dist/components/ai/PluginHarnessPicker.js +3 -3
- package/dist/components/ai/PluginHarnessPicker.js.map +1 -1
- package/dist/components/analytics/AnalyticsBreakdownChart.js +8 -8
- package/dist/components/analytics/AnalyticsBreakdownChart.js.map +1 -1
- package/dist/components/analytics/AnalyticsTimeSeriesChart.js +5 -5
- package/dist/components/analytics/AnalyticsTimeSeriesChart.js.map +1 -1
- package/dist/components/audit/AuditDeleteDialog.js +2 -2
- package/dist/components/audit/AuditDeleteDialog.js.map +1 -1
- package/dist/components/audit/AuditExportButton.js +5 -5
- package/dist/components/audit/AuditExportButton.js.map +1 -1
- package/dist/components/audit/AuditLogDetail.js +9 -9
- package/dist/components/audit/AuditLogDetail.js.map +1 -1
- package/dist/components/audit/AuditLogFilters.js +1 -1
- package/dist/components/audit/AuditLogFilters.js.map +1 -1
- package/dist/components/audit/AuditLogStats.js +1 -1
- package/dist/components/audit/AuditLogStats.js.map +1 -1
- package/dist/components/audit/AuditLogTable.js +28 -28
- package/dist/components/audit/AuditLogTable.js.map +1 -1
- package/dist/components/catalog/CatalogCard.js +3 -3
- package/dist/components/catalog/CatalogCard.js.map +1 -1
- package/dist/components/catalog/CatalogForm.js +1 -1
- package/dist/components/catalog/CatalogForm.js.map +1 -1
- package/dist/components/common/ActionAgentTargetNotice.js +6 -6
- package/dist/components/common/ActionAgentTargetNotice.js.map +1 -1
- package/dist/components/common/CommandEditor.js +1 -1
- package/dist/components/common/CommandEditor.js.map +1 -1
- package/dist/components/docs/DocsPageTree.js +1 -1
- package/dist/components/docs/DocsPageTree.js.map +1 -1
- package/dist/components/docs/DocsPreviewPanel.js +1 -1
- package/dist/components/docs/DocsPreviewPanel.js.map +1 -1
- package/dist/components/docs/DocsRevisionHistory.js +4 -4
- package/dist/components/docs/DocsRevisionHistory.js.map +1 -1
- package/dist/components/docs/DocsSettingsPanel.js +7 -7
- package/dist/components/docs/DocsSettingsPanel.js.map +1 -1
- package/dist/components/docs/DocsTabPanel.js +1 -1
- package/dist/components/docs/DocsTabPanel.js.map +1 -1
- package/dist/components/graph/ConnectionPermissionsDialog.js +2 -2
- package/dist/components/graph/ConnectionPermissionsDialog.js.map +1 -1
- package/dist/components/graph/MeshDeployWizard.js +3 -3
- package/dist/components/graph/MeshDeployWizard.js.map +1 -1
- package/dist/components/graph/MeshRequestPanel.js +2 -2
- package/dist/components/graph/MeshRequestPanel.js.map +1 -1
- package/dist/components/idp-components/ComponentCard.js +5 -5
- package/dist/components/idp-components/ComponentCard.js.map +1 -1
- package/dist/components/idp-components/ComponentForm.js +1 -1
- package/dist/components/idp-components/ComponentForm.js.map +1 -1
- package/dist/components/idp-components/DependencyGraphTab.js +7 -7
- package/dist/components/idp-components/DependencyGraphTab.js.map +1 -1
- package/dist/components/logs/LogViewer.js +14 -14
- package/dist/components/logs/LogViewer.js.map +1 -1
- package/dist/components/notes/NoteCard.js +1 -1
- package/dist/components/notes/NoteCard.js.map +1 -1
- package/dist/components/notes/NoteEditor.js +2 -2
- package/dist/components/notes/NoteEditor.js.map +1 -1
- package/dist/components/notes/NoteList.js +1 -1
- package/dist/components/notes/NoteList.js.map +1 -1
- package/dist/components/notes/NotesTabPanel.js +1 -1
- package/dist/components/notes/NotesTabPanel.js.map +1 -1
- package/dist/components/scorecard/ScorecardEmptyState.js +1 -1
- package/dist/components/scorecard/ScorecardEmptyState.js.map +1 -1
- package/dist/components/scorecard/ScorecardPanel.js +3 -3
- package/dist/components/scorecard/ScorecardPanel.js.map +1 -1
- package/dist/components/security/SecurityScanList.js +11 -11
- package/dist/components/security/SecurityScanList.js.map +1 -1
- package/dist/components/sessions/SessionCard.js +26 -19
- package/dist/components/sessions/SessionCard.js.map +1 -1
- package/dist/components/sessions/SessionStatusBadge.js +7 -7
- package/dist/components/sessions/SessionStatusBadge.js.map +1 -1
- package/dist/components/shared/AgentSelector.js +4 -4
- package/dist/components/shared/AgentSelector.js.map +1 -1
- package/dist/components/shared/AgentSetupBanner.js +3 -3
- package/dist/components/shared/AgentSetupBanner.js.map +1 -1
- package/dist/components/shared/Card.js +4 -4
- package/dist/components/shared/Card.js.map +1 -1
- package/dist/components/shared/ErrorState.js +15 -9
- package/dist/components/shared/ErrorState.js.map +1 -1
- package/dist/components/shared/FilterDropdown.js +2 -2
- package/dist/components/shared/FilterDropdown.js.map +1 -1
- package/dist/components/shared/PageSkeleton.js +6 -6
- package/dist/components/shared/PageSkeleton.js.map +1 -1
- package/dist/components/shared/SearchInput.js +1 -1
- package/dist/components/shared/SearchInput.js.map +1 -1
- package/dist/components/shared/StatCard.js +7 -7
- package/dist/components/shared/StatCard.js.map +1 -1
- package/dist/components/templates/PublishTemplateForm.js +2 -2
- package/dist/components/templates/PublishTemplateForm.js.map +1 -1
- package/dist/components/templates/TemplateCard.js +5 -5
- package/dist/components/templates/TemplateCard.js.map +1 -1
- package/dist/components/templates/TemplateWizard.js +2 -2
- package/dist/components/templates/TemplateWizard.js.map +1 -1
- package/dist/components/tunnels/DomainVerificationBadge.js +4 -4
- package/dist/components/tunnels/DomainVerificationBadge.js.map +1 -1
- package/dist/components/tunnels/ProviderBadge.js +1 -1
- package/dist/components/tunnels/ProviderBadge.js.map +1 -1
- package/dist/components/tunnels/TunnelCard.js +16 -16
- package/dist/components/tunnels/TunnelCard.js.map +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js +1 -1
- package/dist/components/tunnels/TunnelCreateWizard.js.map +1 -1
- package/dist/components/tunnels/TunnelPublicAccessPanel.js +1 -1
- package/dist/components/tunnels/TunnelPublicAccessPanel.js.map +1 -1
- package/dist/components/tunnels/TunnelStatusBadge.js +4 -4
- package/dist/components/tunnels/TunnelStatusBadge.js.map +1 -1
- package/dist/components/vibecalendar/LogsDrawer.js +2 -2
- package/dist/components/vibecalendar/LogsDrawer.js.map +1 -1
- package/dist/components/vibecalendar/ScheduleTaskModal.js +5 -5
- package/dist/components/vibecalendar/ScheduleTaskModal.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalAgendaView.js +2 -2
- package/dist/components/vibecalendar/VibeCalAgendaView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalDayView.js +3 -3
- package/dist/components/vibecalendar/VibeCalDayView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalMonthView.js +1 -1
- package/dist/components/vibecalendar/VibeCalMonthView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalWeekView.js +4 -4
- package/dist/components/vibecalendar/VibeCalWeekView.js.map +1 -1
- package/dist/components/vibecalendar/VibeCalendarHeader.js +4 -4
- package/dist/components/vibecalendar/VibeCalendarHeader.js.map +1 -1
- package/dist/components/vibecalendar/VibeTaskBlock.js +2 -2
- package/dist/components/vibecalendar/VibeTaskBlock.js.map +1 -1
- package/dist/components/vibecalendar/types.js +6 -6
- package/dist/components/vibecalendar/types.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckButtonForm.js +9 -9
- package/dist/components/vibedeck/VibeDeckButtonForm.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckButtonTile.js +6 -6
- package/dist/components/vibedeck/VibeDeckButtonTile.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckExecutionLog.js +10 -10
- package/dist/components/vibedeck/VibeDeckExecutionLog.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckForm.js +8 -8
- package/dist/components/vibedeck/VibeDeckForm.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckGrid.js +2 -2
- package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js +2 -2
- package/dist/components/vibedeck/VibeDeckPublicLinkPanel.js.map +1 -1
- package/dist/components/vibedeck/VibeDeckSwitcher.js +8 -8
- package/dist/components/vibedeck/VibeDeckSwitcher.js.map +1 -1
- package/dist/components/vibes/VibeCard.js +22 -18
- package/dist/components/vibes/VibeCard.js.map +1 -1
- package/dist/components/vibes/VibeList.js +16 -12
- package/dist/components/vibes/VibeList.js.map +1 -1
- package/dist/pages/ActionsPage.js +4 -3
- package/dist/pages/ActionsPage.js.map +1 -1
- package/dist/pages/AgentDetailsPage.js +9 -9
- package/dist/pages/AgentDetailsPage.js.map +1 -1
- package/dist/pages/AgentsLandingPage.js +4 -4
- package/dist/pages/AgentsLandingPage.js.map +1 -1
- package/dist/pages/AgentsPage.js +14 -14
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/AnalyticsPage.js +8 -8
- package/dist/pages/AnalyticsPage.js.map +1 -1
- package/dist/pages/CatalogDetailPage.js +11 -11
- package/dist/pages/CatalogDetailPage.js.map +1 -1
- package/dist/pages/CatalogPage.js +12 -9
- package/dist/pages/CatalogPage.js.map +1 -1
- package/dist/pages/ComponentDetailPage.js +7 -7
- package/dist/pages/ComponentDetailPage.js.map +1 -1
- package/dist/pages/ComponentsPage.js +12 -9
- package/dist/pages/ComponentsPage.js.map +1 -1
- package/dist/pages/EnvTopologyPage.js +2 -2
- package/dist/pages/EnvTopologyPage.js.map +1 -1
- package/dist/pages/GettingStartedPage.js +12 -12
- package/dist/pages/GettingStartedPage.js.map +1 -1
- package/dist/pages/HealthPage.js +12 -12
- package/dist/pages/HealthPage.js.map +1 -1
- package/dist/pages/LogsPage.js +4 -4
- package/dist/pages/LogsPage.js.map +1 -1
- package/dist/pages/NoteDetailsPage.js +5 -5
- package/dist/pages/NoteDetailsPage.js.map +1 -1
- package/dist/pages/OverviewPage.js +74 -41
- package/dist/pages/OverviewPage.js.map +1 -1
- package/dist/pages/PluginsCatalogPage.js +6 -3
- package/dist/pages/PluginsCatalogPage.js.map +1 -1
- package/dist/pages/ScheduledJobDetailPage.js +7 -7
- package/dist/pages/ScheduledJobDetailPage.js.map +1 -1
- package/dist/pages/SessionDetailsPage.js +21 -21
- package/dist/pages/SessionDetailsPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +20 -20
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/SettingsPage.js +64 -52
- package/dist/pages/SettingsPage.js.map +1 -1
- package/dist/pages/SharedSessionPage.js +21 -21
- package/dist/pages/SharedSessionPage.js.map +1 -1
- package/dist/pages/SharedVibeDeckPage.js +5 -5
- package/dist/pages/SharedVibeDeckPage.js.map +1 -1
- package/dist/pages/TargetDetailsPage.js +56 -65
- package/dist/pages/TargetDetailsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +4 -4
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/TemplateDetailPage.js +10 -10
- package/dist/pages/TemplateDetailPage.js.map +1 -1
- package/dist/pages/TemplatesPage.js +6 -5
- package/dist/pages/TemplatesPage.js.map +1 -1
- package/dist/pages/VibeAuditPage.js +3 -3
- package/dist/pages/VibeAuditPage.js.map +1 -1
- package/dist/pages/VibeCalendarPage.js +3 -3
- package/dist/pages/VibeCalendarPage.js.map +1 -1
- package/dist/pages/VibeDeckPage.js +3 -3
- package/dist/pages/VibeDeckPage.js.map +1 -1
- package/dist/pages/VibeDetailsPage.js +15 -15
- package/dist/pages/VibeDetailsPage.js.map +1 -1
- package/dist/pages/VibeTaskDetailPage.js +5 -5
- package/dist/pages/VibeTaskDetailPage.js.map +1 -1
- package/dist/pages/VibesPage.js +18 -18
- package/dist/pages/VibesPage.js.map +1 -1
- package/dist/pages/WebhooksPage.js +11 -11
- package/dist/pages/WebhooksPage.js.map +1 -1
- package/dist/pages/ai/AIBookmarksPage.js +1 -1
- package/dist/pages/ai/AIBookmarksPage.js.map +1 -1
- package/dist/pages/ai/AISessionDetailPage.js +6 -6
- package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
- package/dist/pages/tunnels/AuditTab.js +1 -1
- package/dist/pages/tunnels/AuditTab.js.map +1 -1
- package/dist/pages/tunnels/DomainsTab.js +1 -1
- package/dist/pages/tunnels/DomainsTab.js.map +1 -1
- package/dist/pages/tunnels/ProvidersTab.js +1 -1
- package/dist/pages/tunnels/ProvidersTab.js.map +1 -1
- package/dist/pages/tunnels/SessionsTab.js +1 -1
- package/dist/pages/tunnels/SessionsTab.js.map +1 -1
- package/dist/pages/tunnels/TunnelDetailsPage.js +3 -3
- package/dist/pages/tunnels/TunnelDetailsPage.js.map +1 -1
- package/dist/pages/tunnels/UsageTab.js +1 -1
- package/dist/pages/tunnels/UsageTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js +16 -16
- package/dist/pages/tunnels/tabs/TunnelDomainsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js +1 -1
- package/dist/pages/tunnels/tabs/TunnelOverviewTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js +52 -49
- package/dist/pages/tunnels/tabs/TunnelSessionsTab.js.map +1 -1
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js +9 -9
- package/dist/pages/tunnels/tabs/TunnelSettingsTab.js.map +1 -1
- package/package.json +1 -1
|
@@ -146,12 +146,12 @@ function h({ rootAgentId: h, destinations: g, initialDestinationId: _, onClose:
|
|
|
146
146
|
children: [/* @__PURE__ */ l("button", {
|
|
147
147
|
type: "button",
|
|
148
148
|
onClick: () => C("command"),
|
|
149
|
-
className: `px-3 py-2 text-sm rounded-md border transition-colors ${S === "command" ? "border-action-primary-bg bg-
|
|
149
|
+
className: `px-3 py-2 text-sm rounded-md border transition-colors ${S === "command" ? "border-action-primary-bg bg-[var(--color-accent-soft)] text-action-primary-bg" : "border-border-default text-text-secondary hover:bg-bg-sunken"}`,
|
|
150
150
|
children: y("mesh.request.command", "Command")
|
|
151
151
|
}), /* @__PURE__ */ l("button", {
|
|
152
152
|
type: "button",
|
|
153
153
|
onClick: () => C("api"),
|
|
154
|
-
className: `px-3 py-2 text-sm rounded-md border transition-colors ${S === "api" ? "border-action-primary-bg bg-
|
|
154
|
+
className: `px-3 py-2 text-sm rounded-md border transition-colors ${S === "api" ? "border-action-primary-bg bg-[var(--color-accent-soft)] text-action-primary-bg" : "border-border-default text-text-secondary hover:bg-bg-sunken"}`,
|
|
155
155
|
children: y("mesh.request.api", "API")
|
|
156
156
|
})]
|
|
157
157
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MeshRequestPanel.js","names":[],"sources":["../../../src/components/graph/MeshRequestPanel.tsx"],"sourcesContent":["/**\n * MeshRequestPanel — run a request against a destination agent THROUGH the mesh.\n *\n * The backend computes the hop path from the chosen root (source) agent to the\n * destination, so the panel only supplies `rootAgentId` + `destinationAgentId`\n * + the request. Two request modes:\n * - COMMAND: type a `vibe` argv; we POST to\n * `/api/profiles/default/agent/commands/run` with body `{ argv }`.\n * - API: raw method + path + optional JSON body.\n *\n * The AgentProxyResponse is rendered like AgentMaintenanceTab's output pane,\n * and a hops breadcrumb is shown when the response surfaces hop info.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { Loader2, Play, ChevronRight, Network } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useExecuteAgentMeshRequestMutation } from '@/generated/wspace-operations';\nimport type { MeshAgentUi } from './meshTypes';\n\ntype RequestMode = 'command' | 'api';\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\nfunction asRecord(v: unknown): Record<string, unknown> | null {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null;\n}\nfunction jstr(obj: Record<string, unknown> | null, key: string): string | null {\n const v = obj?.[key];\n return typeof v === 'string' ? v : null;\n}\n\nfunction extractHops(data: Record<string, unknown> | null): string[] {\n if (!data) return [];\n const raw = data.hops ?? asRecord(data.meta)?.hops;\n if (Array.isArray(raw)) return raw.filter((h): h is string => typeof h === 'string');\n return [];\n}\n\nconst INPUT_CLASS =\n 'px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40';\n\ninterface MeshRequestPanelProps {\n /** The root/source agent the request is dispatched from. */\n rootAgentId: string | null;\n /** Candidate destination agents (typically the workspace mesh agents). */\n destinations: MeshAgentUi[];\n /** Pre-selected destination (e.g. clicked node). */\n initialDestinationId?: string | null;\n onClose?: () => void;\n}\n\nexport function MeshRequestPanel({\n rootAgentId,\n destinations,\n initialDestinationId,\n onClose,\n}: MeshRequestPanelProps) {\n const tr = useTr();\n\n const [destinationId, setDestinationId] = useState<string>(\n initialDestinationId ?? destinations[0]?.id ?? ''\n );\n const [mode, setMode] = useState<RequestMode>('command');\n const [argv, setArgv] = useState('status');\n const [method, setMethod] = useState<HttpMethod>('GET');\n const [path, setPath] = useState('/api/health');\n const [bodyText, setBodyText] = useState('');\n const [output, setOutput] = useState<{ body: string; error?: boolean } | null>(null);\n const [hops, setHops] = useState<string[]>([]);\n\n const [execute, { loading }] = useExecuteAgentMeshRequestMutation();\n\n const destName = useCallback(\n (id: string) => destinations.find((d) => d.id === id)?.name ?? id,\n [destinations]\n );\n\n const canRun = useMemo(() => {\n if (!rootAgentId || !destinationId) return false;\n if (mode === 'command') return argv.trim().length > 0;\n return path.trim().length > 0;\n }, [rootAgentId, destinationId, mode, argv, path]);\n\n const handleRun = useCallback(async () => {\n if (!rootAgentId || !destinationId) return;\n setOutput(null);\n setHops([]);\n\n let requestInput: {\n method: string;\n path: string;\n body?: Record<string, unknown>;\n };\n\n if (mode === 'command') {\n const parts = argv.trim().split(/\\s+/).filter(Boolean);\n requestInput = {\n method: 'POST',\n path: '/api/profiles/default/agent/commands/run',\n body: { argv: parts },\n };\n } else {\n let parsedBody: Record<string, unknown> | undefined;\n if (bodyText.trim().length > 0) {\n try {\n const parsed: unknown = JSON.parse(bodyText);\n parsedBody = asRecord(parsed) ?? undefined;\n if (!parsedBody) {\n setOutput({\n body: tr('mesh.request.bodyNotObject', 'Body must be a JSON object.'),\n error: true,\n });\n return;\n }\n } catch {\n setOutput({\n body: tr('mesh.request.invalidJson', 'Request body is not valid JSON.'),\n error: true,\n });\n return;\n }\n }\n requestInput = { method, path: path.trim(), body: parsedBody };\n }\n\n try {\n const res = await execute({\n variables: {\n rootAgentId,\n destinationAgentId: destinationId,\n request: requestInput,\n },\n });\n const proxy = res.data?.executeAgentMeshRequest;\n const data = asRecord(proxy?.data);\n setHops(extractHops(data));\n\n if (res.error || proxy?.error || proxy?.ok === false) {\n setOutput({\n body:\n proxy?.error ??\n res.error?.message ??\n jstr(data, 'error') ??\n tr('mesh.request.failed', 'Request failed'),\n error: true,\n });\n return;\n }\n\n const stdout = jstr(data, 'stdout');\n const text = proxy?.text;\n const pretty = data ? JSON.stringify(data, null, 2) : (text ?? '(no output)');\n setOutput({ body: stdout || text || pretty });\n } catch (err) {\n setOutput({ body: err instanceof Error ? err.message : String(err), error: true });\n }\n }, [rootAgentId, destinationId, mode, argv, method, path, bodyText, execute, tr]);\n\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Network className=\"size-4 text-text-secondary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr('mesh.request.title', 'Run mesh request')}\n </h3>\n </div>\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-xs text-text-muted hover:text-text-primary\"\n >\n {tr('common.close', 'Close')}\n </button>\n )}\n </div>\n\n {!rootAgentId && (\n <p className=\"text-xs text-status-warning-text\">\n {tr('mesh.request.noRoot', 'Select a reachable root agent to dispatch from.')}\n </p>\n )}\n\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs text-text-muted\" htmlFor=\"mesh-dest\">\n {tr('mesh.request.destination', 'Destination agent')}\n </label>\n <select\n id=\"mesh-dest\"\n value={destinationId}\n onChange={(e) => setDestinationId(e.target.value)}\n className={`${INPUT_CLASS} min-w-44`}\n >\n {destinations.length === 0 && (\n <option value=\"\">{tr('mesh.request.noDest', 'No agents')}</option>\n )}\n {destinations.map((d) => (\n <option key={d.id} value={d.id}>\n {d.name} ({d.hostname})\n </option>\n ))}\n </select>\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-text-muted\">{tr('mesh.request.mode', 'Mode')}</span>\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n onClick={() => setMode('command')}\n className={`px-3 py-2 text-sm rounded-md border transition-colors ${\n mode === 'command'\n ? 'border-action-primary-bg bg-action-primary-bg/10 text-action-primary-bg'\n : 'border-border-default text-text-secondary hover:bg-bg-sunken'\n }`}\n >\n {tr('mesh.request.command', 'Command')}\n </button>\n <button\n type=\"button\"\n onClick={() => setMode('api')}\n className={`px-3 py-2 text-sm rounded-md border transition-colors ${\n mode === 'api'\n ? 'border-action-primary-bg bg-action-primary-bg/10 text-action-primary-bg'\n : 'border-border-default text-text-secondary hover:bg-bg-sunken'\n }`}\n >\n {tr('mesh.request.api', 'API')}\n </button>\n </div>\n </div>\n </div>\n\n {mode === 'command' ? (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs text-text-muted\" htmlFor=\"mesh-argv\">\n {tr('mesh.request.argv', 'Command (vibe …)')}\n </label>\n <input\n id=\"mesh-argv\"\n type=\"text\"\n value={argv}\n onChange={(e) => setArgv(e.target.value)}\n placeholder=\"status --json\"\n className={`${INPUT_CLASS} font-mono w-full`}\n />\n </div>\n ) : (\n <div className=\"space-y-2\">\n <div className=\"flex gap-2\">\n <select\n value={method}\n onChange={(e) => setMethod(e.target.value as HttpMethod)}\n className={`${INPUT_CLASS} w-28`}\n aria-label={tr('mesh.request.method', 'Method')}\n >\n {(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as HttpMethod[]).map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={path}\n onChange={(e) => setPath(e.target.value)}\n placeholder=\"/api/health\"\n className={`${INPUT_CLASS} font-mono flex-1`}\n aria-label={tr('mesh.request.path', 'Path')}\n />\n </div>\n <textarea\n value={bodyText}\n onChange={(e) => setBodyText(e.target.value)}\n placeholder={tr('mesh.request.bodyPlaceholder', 'JSON body (optional)')}\n rows={3}\n className={`${INPUT_CLASS} font-mono w-full resize-y`}\n aria-label={tr('mesh.request.body', 'Request body')}\n />\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={() => void handleRun()}\n disabled={!canRun || loading}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {loading ? <Loader2 className=\"size-4 animate-spin\" /> : <Play className=\"size-4\" />}\n {tr('mesh.request.run', 'Run')}\n </button>\n\n {hops.length > 0 && (\n <div className=\"flex flex-wrap items-center gap-1 text-xs text-text-tertiary\">\n <span className=\"font-medium text-text-secondary\">\n {tr('mesh.request.hops', 'Hops:')}\n </span>\n {hops.map((hop, idx) => (\n <span key={`${hop}-${idx}`} className=\"inline-flex items-center gap-1\">\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-text-primary\">\n {destName(hop)}\n </span>\n {idx < hops.length - 1 && <ChevronRight className=\"size-3\" />}\n </span>\n ))}\n </div>\n )}\n\n {output && (\n <pre\n className={`text-xs whitespace-pre-wrap break-words max-h-80 overflow-auto rounded-md p-3 ${\n output.error\n ? 'bg-status-error-bg-subtle text-status-error-text'\n : 'bg-bg-sunken text-text-primary'\n }`}\n >\n {output.body}\n </pre>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MeshRequestPanel.js","names":[],"sources":["../../../src/components/graph/MeshRequestPanel.tsx"],"sourcesContent":["/**\n * MeshRequestPanel — run a request against a destination agent THROUGH the mesh.\n *\n * The backend computes the hop path from the chosen root (source) agent to the\n * destination, so the panel only supplies `rootAgentId` + `destinationAgentId`\n * + the request. Two request modes:\n * - COMMAND: type a `vibe` argv; we POST to\n * `/api/profiles/default/agent/commands/run` with body `{ argv }`.\n * - API: raw method + path + optional JSON body.\n *\n * The AgentProxyResponse is rendered like AgentMaintenanceTab's output pane,\n * and a hops breadcrumb is shown when the response surfaces hop info.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { Loader2, Play, ChevronRight, Network } from 'lucide-react';\nimport { useTr } from '../../shared/hooks/useTr';\nimport { useExecuteAgentMeshRequestMutation } from '@/generated/wspace-operations';\nimport type { MeshAgentUi } from './meshTypes';\n\ntype RequestMode = 'command' | 'api';\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\nfunction asRecord(v: unknown): Record<string, unknown> | null {\n return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null;\n}\nfunction jstr(obj: Record<string, unknown> | null, key: string): string | null {\n const v = obj?.[key];\n return typeof v === 'string' ? v : null;\n}\n\nfunction extractHops(data: Record<string, unknown> | null): string[] {\n if (!data) return [];\n const raw = data.hops ?? asRecord(data.meta)?.hops;\n if (Array.isArray(raw)) return raw.filter((h): h is string => typeof h === 'string');\n return [];\n}\n\nconst INPUT_CLASS =\n 'px-3 py-2 text-sm rounded-md bg-bg-sunken border border-border-default text-text-primary focus:outline-none focus:ring-2 focus:ring-action-primary-bg/40';\n\ninterface MeshRequestPanelProps {\n /** The root/source agent the request is dispatched from. */\n rootAgentId: string | null;\n /** Candidate destination agents (typically the workspace mesh agents). */\n destinations: MeshAgentUi[];\n /** Pre-selected destination (e.g. clicked node). */\n initialDestinationId?: string | null;\n onClose?: () => void;\n}\n\nexport function MeshRequestPanel({\n rootAgentId,\n destinations,\n initialDestinationId,\n onClose,\n}: MeshRequestPanelProps) {\n const tr = useTr();\n\n const [destinationId, setDestinationId] = useState<string>(\n initialDestinationId ?? destinations[0]?.id ?? ''\n );\n const [mode, setMode] = useState<RequestMode>('command');\n const [argv, setArgv] = useState('status');\n const [method, setMethod] = useState<HttpMethod>('GET');\n const [path, setPath] = useState('/api/health');\n const [bodyText, setBodyText] = useState('');\n const [output, setOutput] = useState<{ body: string; error?: boolean } | null>(null);\n const [hops, setHops] = useState<string[]>([]);\n\n const [execute, { loading }] = useExecuteAgentMeshRequestMutation();\n\n const destName = useCallback(\n (id: string) => destinations.find((d) => d.id === id)?.name ?? id,\n [destinations]\n );\n\n const canRun = useMemo(() => {\n if (!rootAgentId || !destinationId) return false;\n if (mode === 'command') return argv.trim().length > 0;\n return path.trim().length > 0;\n }, [rootAgentId, destinationId, mode, argv, path]);\n\n const handleRun = useCallback(async () => {\n if (!rootAgentId || !destinationId) return;\n setOutput(null);\n setHops([]);\n\n let requestInput: {\n method: string;\n path: string;\n body?: Record<string, unknown>;\n };\n\n if (mode === 'command') {\n const parts = argv.trim().split(/\\s+/).filter(Boolean);\n requestInput = {\n method: 'POST',\n path: '/api/profiles/default/agent/commands/run',\n body: { argv: parts },\n };\n } else {\n let parsedBody: Record<string, unknown> | undefined;\n if (bodyText.trim().length > 0) {\n try {\n const parsed: unknown = JSON.parse(bodyText);\n parsedBody = asRecord(parsed) ?? undefined;\n if (!parsedBody) {\n setOutput({\n body: tr('mesh.request.bodyNotObject', 'Body must be a JSON object.'),\n error: true,\n });\n return;\n }\n } catch {\n setOutput({\n body: tr('mesh.request.invalidJson', 'Request body is not valid JSON.'),\n error: true,\n });\n return;\n }\n }\n requestInput = { method, path: path.trim(), body: parsedBody };\n }\n\n try {\n const res = await execute({\n variables: {\n rootAgentId,\n destinationAgentId: destinationId,\n request: requestInput,\n },\n });\n const proxy = res.data?.executeAgentMeshRequest;\n const data = asRecord(proxy?.data);\n setHops(extractHops(data));\n\n if (res.error || proxy?.error || proxy?.ok === false) {\n setOutput({\n body:\n proxy?.error ??\n res.error?.message ??\n jstr(data, 'error') ??\n tr('mesh.request.failed', 'Request failed'),\n error: true,\n });\n return;\n }\n\n const stdout = jstr(data, 'stdout');\n const text = proxy?.text;\n const pretty = data ? JSON.stringify(data, null, 2) : (text ?? '(no output)');\n setOutput({ body: stdout || text || pretty });\n } catch (err) {\n setOutput({ body: err instanceof Error ? err.message : String(err), error: true });\n }\n }, [rootAgentId, destinationId, mode, argv, method, path, bodyText, execute, tr]);\n\n return (\n <div className=\"rounded-lg border border-border-default bg-bg-surface p-4 space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-2\">\n <Network className=\"size-4 text-text-secondary\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {tr('mesh.request.title', 'Run mesh request')}\n </h3>\n </div>\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-xs text-text-muted hover:text-text-primary\"\n >\n {tr('common.close', 'Close')}\n </button>\n )}\n </div>\n\n {!rootAgentId && (\n <p className=\"text-xs text-status-warning-text\">\n {tr('mesh.request.noRoot', 'Select a reachable root agent to dispatch from.')}\n </p>\n )}\n\n <div className=\"flex flex-wrap items-end gap-2\">\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs text-text-muted\" htmlFor=\"mesh-dest\">\n {tr('mesh.request.destination', 'Destination agent')}\n </label>\n <select\n id=\"mesh-dest\"\n value={destinationId}\n onChange={(e) => setDestinationId(e.target.value)}\n className={`${INPUT_CLASS} min-w-44`}\n >\n {destinations.length === 0 && (\n <option value=\"\">{tr('mesh.request.noDest', 'No agents')}</option>\n )}\n {destinations.map((d) => (\n <option key={d.id} value={d.id}>\n {d.name} ({d.hostname})\n </option>\n ))}\n </select>\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <span className=\"text-xs text-text-muted\">{tr('mesh.request.mode', 'Mode')}</span>\n <div className=\"flex gap-1\">\n <button\n type=\"button\"\n onClick={() => setMode('command')}\n className={`px-3 py-2 text-sm rounded-md border transition-colors ${\n mode === 'command'\n ? 'border-action-primary-bg bg-[var(--color-accent-soft)] text-action-primary-bg'\n : 'border-border-default text-text-secondary hover:bg-bg-sunken'\n }`}\n >\n {tr('mesh.request.command', 'Command')}\n </button>\n <button\n type=\"button\"\n onClick={() => setMode('api')}\n className={`px-3 py-2 text-sm rounded-md border transition-colors ${\n mode === 'api'\n ? 'border-action-primary-bg bg-[var(--color-accent-soft)] text-action-primary-bg'\n : 'border-border-default text-text-secondary hover:bg-bg-sunken'\n }`}\n >\n {tr('mesh.request.api', 'API')}\n </button>\n </div>\n </div>\n </div>\n\n {mode === 'command' ? (\n <div className=\"flex flex-col gap-1\">\n <label className=\"text-xs text-text-muted\" htmlFor=\"mesh-argv\">\n {tr('mesh.request.argv', 'Command (vibe …)')}\n </label>\n <input\n id=\"mesh-argv\"\n type=\"text\"\n value={argv}\n onChange={(e) => setArgv(e.target.value)}\n placeholder=\"status --json\"\n className={`${INPUT_CLASS} font-mono w-full`}\n />\n </div>\n ) : (\n <div className=\"space-y-2\">\n <div className=\"flex gap-2\">\n <select\n value={method}\n onChange={(e) => setMethod(e.target.value as HttpMethod)}\n className={`${INPUT_CLASS} w-28`}\n aria-label={tr('mesh.request.method', 'Method')}\n >\n {(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as HttpMethod[]).map((m) => (\n <option key={m} value={m}>\n {m}\n </option>\n ))}\n </select>\n <input\n type=\"text\"\n value={path}\n onChange={(e) => setPath(e.target.value)}\n placeholder=\"/api/health\"\n className={`${INPUT_CLASS} font-mono flex-1`}\n aria-label={tr('mesh.request.path', 'Path')}\n />\n </div>\n <textarea\n value={bodyText}\n onChange={(e) => setBodyText(e.target.value)}\n placeholder={tr('mesh.request.bodyPlaceholder', 'JSON body (optional)')}\n rows={3}\n className={`${INPUT_CLASS} font-mono w-full resize-y`}\n aria-label={tr('mesh.request.body', 'Request body')}\n />\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={() => void handleRun()}\n disabled={!canRun || loading}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-md bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {loading ? <Loader2 className=\"size-4 animate-spin\" /> : <Play className=\"size-4\" />}\n {tr('mesh.request.run', 'Run')}\n </button>\n\n {hops.length > 0 && (\n <div className=\"flex flex-wrap items-center gap-1 text-xs text-text-tertiary\">\n <span className=\"font-medium text-text-secondary\">\n {tr('mesh.request.hops', 'Hops:')}\n </span>\n {hops.map((hop, idx) => (\n <span key={`${hop}-${idx}`} className=\"inline-flex items-center gap-1\">\n <span className=\"rounded bg-bg-sunken px-1.5 py-0.5 text-text-primary\">\n {destName(hop)}\n </span>\n {idx < hops.length - 1 && <ChevronRight className=\"size-3\" />}\n </span>\n ))}\n </div>\n )}\n\n {output && (\n <pre\n className={`text-xs whitespace-pre-wrap break-words max-h-80 overflow-auto rounded-md p-3 ${\n output.error\n ? 'bg-status-error-bg-subtle text-status-error-text'\n : 'bg-bg-sunken text-text-primary'\n }`}\n >\n {output.body}\n </pre>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -14,10 +14,10 @@ var v = {
|
|
|
14
14
|
INFRASTRUCTURE: a,
|
|
15
15
|
CUSTOM: r
|
|
16
16
|
}, y = {
|
|
17
|
-
EXPERIMENTAL: "bg-status-warning-bg text-status-warning-text",
|
|
18
|
-
ACTIVE: "bg-status-success-bg text-status-success-text",
|
|
19
|
-
DEPRECATED: "bg-status-error-bg text-status-error-text",
|
|
20
|
-
END_OF_LIFE: "bg-status-error-bg text-status-error-text"
|
|
17
|
+
EXPERIMENTAL: "bg-status-warning-bg-subtle text-status-warning-text",
|
|
18
|
+
ACTIVE: "bg-status-success-bg-subtle text-status-success-text",
|
|
19
|
+
DEPRECATED: "bg-status-error-bg-subtle text-status-error-text",
|
|
20
|
+
END_OF_LIFE: "bg-status-error-bg-subtle text-status-error-text"
|
|
21
21
|
}, b = ({ component: i, onOpen: a, onEdit: o, onArchive: s, className: c = "" }) => {
|
|
22
22
|
let { t: u } = t(), f = (e, t) => {
|
|
23
23
|
let n = u(e);
|
|
@@ -45,7 +45,7 @@ var v = {
|
|
|
45
45
|
children: [/* @__PURE__ */ _("div", {
|
|
46
46
|
className: "flex items-start gap-2 sm:gap-3 min-w-0 flex-1",
|
|
47
47
|
children: [/* @__PURE__ */ g("div", {
|
|
48
|
-
className: "flex-shrink-0 size-8 sm:w-10 sm:h-10 rounded-lg bg-
|
|
48
|
+
className: "flex-shrink-0 size-8 sm:w-10 sm:h-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center",
|
|
49
49
|
children: /* @__PURE__ */ g(S, { className: "size-4 sm:w-5 sm:h-5 text-action-primary-bg" })
|
|
50
50
|
}), /* @__PURE__ */ _("div", {
|
|
51
51
|
className: "min-w-0 flex-1",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentCard.js","names":[],"sources":["../../../src/components/idp-components/ComponentCard.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n Box,\n Globe,\n Library,\n Server,\n Smartphone,\n Database,\n Cog,\n Tag,\n MoreVertical,\n Settings,\n Archive,\n Code,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nexport interface ComponentCardData {\n id: string;\n name: string;\n description: string | null;\n type:\n | 'SERVICE'\n | 'FRONTEND'\n | 'LIBRARY'\n | 'API'\n | 'MOBILE'\n | 'DATABASE'\n | 'INFRASTRUCTURE'\n | 'CUSTOM';\n lifecycle: 'EXPERIMENTAL' | 'ACTIVE' | 'DEPRECATED' | 'END_OF_LIFE';\n version: string | null;\n language: string | null;\n framework: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ComponentCardProps {\n component: ComponentCardData;\n onOpen?: (component: ComponentCardData) => void;\n onEdit?: (component: ComponentCardData) => void;\n onArchive?: (component: ComponentCardData) => void;\n className?: string;\n}\n\nconst typeIcons: Record<string, typeof Box> = {\n SERVICE: Server,\n FRONTEND: Globe,\n LIBRARY: Library,\n API: Code,\n MOBILE: Smartphone,\n DATABASE: Database,\n INFRASTRUCTURE: Cog,\n CUSTOM: Box,\n};\n\nconst lifecycleStyles: Record<string, string> = {\n EXPERIMENTAL: 'bg-status-warning-bg text-status-warning-text',\n ACTIVE: 'bg-status-success-bg text-status-success-text',\n DEPRECATED: 'bg-status-error-bg text-status-error-text',\n END_OF_LIFE: 'bg-status-error-bg text-status-error-text',\n};\n\nexport const ComponentCard: FC<ComponentCardProps> = ({\n component,\n onOpen,\n onEdit,\n onArchive,\n className = '',\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [showMenu, setShowMenu] = useState(false);\n\n const Icon = typeIcons[component.type] || Box;\n\n return (\n <motion.div\n whileHover={{ y: -2, transition: { duration: 0.15, ease: [0.4, 0, 0.2, 1] } }}\n whileTap={{ scale: 0.98 }}\n className={`bg-bg-surface border border-border-default rounded-lg p-4 hover:border-border-strong hover:shadow-md transition-all cursor-pointer ${className}`}\n onClick={() => onOpen?.(component)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-2 sm:gap-3 min-w-0 flex-1\">\n <div className=\"flex-shrink-0 size-8 sm:w-10 sm:h-10 rounded-lg bg-
|
|
1
|
+
{"version":3,"file":"ComponentCard.js","names":[],"sources":["../../../src/components/idp-components/ComponentCard.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport {\n Box,\n Globe,\n Library,\n Server,\n Smartphone,\n Database,\n Cog,\n Tag,\n MoreVertical,\n Settings,\n Archive,\n Code,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nexport interface ComponentCardData {\n id: string;\n name: string;\n description: string | null;\n type:\n | 'SERVICE'\n | 'FRONTEND'\n | 'LIBRARY'\n | 'API'\n | 'MOBILE'\n | 'DATABASE'\n | 'INFRASTRUCTURE'\n | 'CUSTOM';\n lifecycle: 'EXPERIMENTAL' | 'ACTIVE' | 'DEPRECATED' | 'END_OF_LIFE';\n version: string | null;\n language: string | null;\n framework: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface ComponentCardProps {\n component: ComponentCardData;\n onOpen?: (component: ComponentCardData) => void;\n onEdit?: (component: ComponentCardData) => void;\n onArchive?: (component: ComponentCardData) => void;\n className?: string;\n}\n\nconst typeIcons: Record<string, typeof Box> = {\n SERVICE: Server,\n FRONTEND: Globe,\n LIBRARY: Library,\n API: Code,\n MOBILE: Smartphone,\n DATABASE: Database,\n INFRASTRUCTURE: Cog,\n CUSTOM: Box,\n};\n\nconst lifecycleStyles: Record<string, string> = {\n EXPERIMENTAL: 'bg-status-warning-bg-subtle text-status-warning-text',\n ACTIVE: 'bg-status-success-bg-subtle text-status-success-text',\n DEPRECATED: 'bg-status-error-bg-subtle text-status-error-text',\n END_OF_LIFE: 'bg-status-error-bg-subtle text-status-error-text',\n};\n\nexport const ComponentCard: FC<ComponentCardProps> = ({\n component,\n onOpen,\n onEdit,\n onArchive,\n className = '',\n}) => {\n const { t } = useI18n();\n const tr = (key: string, fallback: string) => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [showMenu, setShowMenu] = useState(false);\n\n const Icon = typeIcons[component.type] || Box;\n\n return (\n <motion.div\n whileHover={{ y: -2, transition: { duration: 0.15, ease: [0.4, 0, 0.2, 1] } }}\n whileTap={{ scale: 0.98 }}\n className={`bg-bg-surface border border-border-default rounded-lg p-4 hover:border-border-strong hover:shadow-md transition-all cursor-pointer ${className}`}\n onClick={() => onOpen?.(component)}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-start gap-2 sm:gap-3 min-w-0 flex-1\">\n <div className=\"flex-shrink-0 size-8 sm:w-10 sm:h-10 rounded-lg bg-[var(--color-accent-soft)] flex items-center justify-center\">\n <Icon className=\"size-4 sm:w-5 sm:h-5 text-action-primary-bg\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"font-semibold text-text-primary truncate text-sm sm:text-base\">\n {component.name}\n </h3>\n <div className=\"flex items-center gap-2 mt-0.5 flex-wrap\">\n <span className=\"text-xs text-text-secondary\">{component.type}</span>\n <span\n className={`inline-flex items-center px-1.5 py-0.5 text-xs rounded ${lifecycleStyles[component.lifecycle] || 'bg-bg-sunken text-text-secondary'}`}\n >\n {tr(\n `component.lifecycle.${component.lifecycle.toLowerCase()}`,\n component.lifecycle\n )}\n </span>\n </div>\n </div>\n </div>\n {(onEdit || onArchive) && (\n <div className=\"relative flex-shrink-0\">\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n setShowMenu(!showMenu);\n }}\n className=\"p-1 sm:p-1.5 rounded hover:bg-bg-sunken transition-colors\"\n >\n <MoreVertical className=\"size-4 text-text-secondary\" />\n </button>\n <AnimatePresence>\n {showMenu && (\n <motion.div\n initial={{ opacity: 0, scale: 0.95, y: -4 }}\n animate={{ opacity: 1, scale: 1, y: 0 }}\n exit={{ opacity: 0, scale: 0.95, y: -4 }}\n transition={{ duration: 0.15 }}\n className=\"absolute right-0 mt-1 w-40 bg-bg-surface border border-border-default rounded-lg shadow-lg z-10\"\n >\n {onEdit && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onEdit(component);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-t-lg\"\n >\n <Settings className=\"size-4\" />\n {tr('common.edit', 'Edit')}\n </motion.button>\n )}\n {onArchive && (\n <motion.button\n whileTap={{ scale: 0.97 }}\n onClick={(e) => {\n e.stopPropagation();\n onArchive(component);\n setShowMenu(false);\n }}\n className=\"flex items-center gap-2 w-full px-3 py-2 text-sm text-text-primary hover:bg-bg-sunken rounded-b-lg\"\n >\n <Archive className=\"size-4\" />\n {tr('common.archive', 'Archive')}\n </motion.button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n )}\n </div>\n\n {component.description && (\n <p className=\"mt-2 text-sm text-text-secondary line-clamp-2\">{component.description}</p>\n )}\n\n {/* Metadata row */}\n <div className=\"mt-3 flex items-center gap-3 text-xs text-text-secondary flex-wrap\">\n {component.version && (\n <span className=\"font-mono bg-bg-sunken px-1.5 py-0.5 rounded\">v{component.version}</span>\n )}\n {component.language && <span>{component.language}</span>}\n {component.framework && <span className=\"text-text-muted\">{component.framework}</span>}\n </div>\n\n {component.tags.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1\">\n {component.tags.slice(0, 3).map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\"\n >\n <Tag className=\"size-3\" />\n {tag}\n </span>\n ))}\n {component.tags.length > 3 && (\n <span className=\"px-2 py-0.5 text-xs bg-bg-sunken text-text-secondary rounded\">\n +{component.tags.length - 3}\n </span>\n )}\n </div>\n )}\n </motion.div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ var l = ({ isOpen: l, onClose: u, onSubmit: d, initialData: f, title: p, extraSe
|
|
|
30
30
|
className: "space-y-4",
|
|
31
31
|
children: [
|
|
32
32
|
M && /* @__PURE__ */ s("div", {
|
|
33
|
-
className: "p-3 bg-status-error-bg text-status-error-text text-sm rounded-md",
|
|
33
|
+
className: "p-3 bg-status-error-bg-subtle text-status-error-text text-sm rounded-md",
|
|
34
34
|
children: M
|
|
35
35
|
}),
|
|
36
36
|
/* @__PURE__ */ c("div", { children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentForm.js","names":[],"sources":["../../../src/components/idp-components/ComponentForm.tsx"],"sourcesContent":["import { useRef, useState } from 'react';\nimport type { FC, ReactNode } from 'react';\nimport { X, ChevronDown, ChevronRight, Github } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nexport interface ComponentFormData {\n name: string;\n description: string;\n type:\n | 'SERVICE'\n | 'FRONTEND'\n | 'LIBRARY'\n | 'API'\n | 'MOBILE'\n | 'DATABASE'\n | 'INFRASTRUCTURE'\n | 'CUSTOM';\n lifecycle: 'EXPERIMENTAL' | 'ACTIVE' | 'DEPRECATED' | 'END_OF_LIFE';\n language: string;\n framework: string;\n version: string;\n ownerName: string;\n tags: string[];\n repositoryUrl?: string;\n documentationUrl?: string;\n dependencies?: Array<{ name: string; version?: string; type?: string }> | null;\n sbomData?: Record<string, unknown> | null;\n}\n\nexport interface ComponentFormProps {\n isOpen: boolean;\n onClose: () => void;\n onSubmit: (data: ComponentFormData) => Promise<void>;\n initialData?: Partial<ComponentFormData>;\n title?: string;\n /** Optional extra content (e.g. a draft EntityTagPicker) rendered above the footer. */\n extraSection?: ReactNode;\n}\n\nexport const ComponentForm: FC<ComponentFormProps> = ({\n isOpen,\n onClose,\n onSubmit,\n initialData,\n title,\n extraSection,\n}) => {\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 const nameRef = useRef<HTMLInputElement>(null);\n const descriptionRef = useRef<HTMLTextAreaElement>(null);\n const typeRef = useRef<HTMLSelectElement>(null);\n const lifecycleRef = useRef<HTMLSelectElement>(null);\n const languageRef = useRef<HTMLInputElement>(null);\n const frameworkRef = useRef<HTMLInputElement>(null);\n const versionRef = useRef<HTMLInputElement>(null);\n const ownerNameRef = useRef<HTMLInputElement>(null);\n const tagsRef = useRef<HTMLInputElement>(null);\n const repositoryUrlRef = useRef<HTMLInputElement>(null);\n const documentationUrlRef = useRef<HTMLInputElement>(null);\n const dependenciesRef = useRef<HTMLTextAreaElement>(null);\n const sbomDataRef = useRef<HTMLTextAreaElement>(null);\n\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [fieldErrors, setFieldErrors] = useState<{\n name?: string;\n repositoryUrl?: string;\n dependencies?: string;\n sbomData?: string;\n }>({});\n const [showAdvanced, setShowAdvanced] = useState(false);\n\n if (!isOpen) return null;\n\n const handleSubmit = async () => {\n const name = nameRef.current?.value?.trim();\n if (!name) {\n setFieldErrors({ name: tr('component.nameRequired', 'Name is required') });\n setError(tr('component.fillRequired', 'Please fill in all required fields'));\n return;\n }\n\n const repoUrl = repositoryUrlRef.current?.value?.trim();\n if (!repoUrl) {\n setFieldErrors({\n repositoryUrl: tr('component.repositoryUrlRequired', 'Repository URL is required'),\n });\n setError(tr('component.fillRequired', 'Please fill in all required fields'));\n return;\n }\n if (!/^https?:\\/\\/.+\\/.+/.test(repoUrl)) {\n setFieldErrors({\n repositoryUrl: tr(\n 'component.repositoryUrlInvalid',\n 'Enter a valid repository URL (e.g. https://github.com/org/repo)'\n ),\n });\n setError(tr('component.fillRequired', 'Please fix the errors above'));\n return;\n }\n\n const newFieldErrors: {\n name?: string;\n repositoryUrl?: string;\n dependencies?: string;\n sbomData?: string;\n } = {};\n\n let parsedDependencies: ComponentFormData['dependencies'] = null;\n const depsRaw = dependenciesRef.current?.value?.trim();\n if (depsRaw) {\n try {\n parsedDependencies = JSON.parse(depsRaw);\n if (!Array.isArray(parsedDependencies)) throw new Error('Must be a JSON array');\n } catch {\n newFieldErrors.dependencies =\n 'Invalid JSON — must be an array like [{\"name\":\"react\",\"version\":\"19.0.0\"}]';\n }\n }\n\n let parsedSbom: ComponentFormData['sbomData'] = null;\n const sbomRaw = sbomDataRef.current?.value?.trim();\n if (sbomRaw) {\n try {\n parsedSbom = JSON.parse(sbomRaw);\n } catch {\n newFieldErrors.sbomData = 'Invalid JSON — paste a valid CycloneDX or SPDX document';\n }\n }\n\n if (Object.keys(newFieldErrors).length > 0) {\n setFieldErrors(newFieldErrors);\n setError(tr('component.fillRequired', 'Please fix the errors above'));\n return;\n }\n\n setFieldErrors({});\n\n const data: ComponentFormData = {\n name,\n description: descriptionRef.current?.value?.trim() || '',\n type: (typeRef.current?.value as ComponentFormData['type']) || 'SERVICE',\n lifecycle: (lifecycleRef.current?.value as ComponentFormData['lifecycle']) || 'EXPERIMENTAL',\n language: languageRef.current?.value?.trim() || '',\n framework: frameworkRef.current?.value?.trim() || '',\n version: versionRef.current?.value?.trim() || '',\n ownerName: ownerNameRef.current?.value?.trim() || '',\n tags: tagsRef.current?.value\n ? tagsRef.current.value\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n : [],\n repositoryUrl: repositoryUrlRef.current?.value?.trim() || undefined,\n documentationUrl: documentationUrlRef.current?.value?.trim() || undefined,\n dependencies: parsedDependencies,\n sbomData: parsedSbom,\n };\n\n setLoading(true);\n setError(null);\n try {\n await onSubmit(data);\n onClose();\n } catch (err) {\n setError(\n err instanceof Error ? err.message : tr('component.failedSave', 'Failed to save component')\n );\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 flex items-center justify-center z-50 p-4\"\n style={{ backgroundColor: 'rgba(0,0,0,0.55)' }}\n >\n <div className=\"bg-bg-surface rounded-lg p-6 w-full max-w-lg max-h-[90vh] overflow-y-auto\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {title || tr('component.createComponent', 'Create Component')}\n </h2>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors text-text-secondary\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n <div className=\"space-y-4\">\n {error && (\n <div className=\"p-3 bg-status-error-bg text-status-error-text text-sm rounded-md\">\n {error}\n </div>\n )}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.nameLabel', 'Name *')}\n </label>\n <input\n aria-label=\"control\"\n ref={nameRef}\n type=\"text\"\n defaultValue={initialData?.name || ''}\n placeholder={tr('component.namePlaceholder', 'my-service')}\n onChange={() =>\n fieldErrors.name && setFieldErrors((e) => ({ ...e, name: undefined }))\n }\n className={`w-full px-3 py-2 bg-bg-sunken border rounded-md text-text-primary placeholder:text-text-placeholder ${fieldErrors.name ? 'border-status-error-border' : 'border-border-default'}`}\n />\n {fieldErrors.name && (\n <p className=\"mt-1 text-xs text-status-error-text\">{fieldErrors.name}</p>\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.descriptionLabel', 'Description')}\n </label>\n <textarea\n aria-label=\"control\"\n ref={descriptionRef}\n defaultValue={initialData?.description || ''}\n placeholder={tr('component.descriptionPlaceholder', 'Describe this component...')}\n rows={3}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder resize-none\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n <span className=\"flex items-center gap-1.5\">\n <Github className=\"size-3.5\" />\n {tr('component.repositoryUrl', 'Repository URL')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </span>\n </label>\n <input\n aria-label=\"https://github.com/org/repo\"\n ref={repositoryUrlRef}\n type=\"url\"\n defaultValue={initialData?.repositoryUrl || ''}\n placeholder=\"https://github.com/org/repo\"\n onChange={() =>\n fieldErrors.repositoryUrl &&\n setFieldErrors((e) => ({ ...e, repositoryUrl: undefined }))\n }\n className={`w-full px-3 py-2 bg-bg-sunken border rounded-md text-text-primary placeholder:text-text-placeholder text-sm ${fieldErrors.repositoryUrl ? 'border-status-error-border' : 'border-border-default'}`}\n />\n {fieldErrors.repositoryUrl && (\n <p className=\"mt-1 text-xs text-status-error-text\">{fieldErrors.repositoryUrl}</p>\n )}\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.typeLabel', 'Type')}\n </label>\n <select\n ref={typeRef}\n defaultValue={initialData?.type || 'SERVICE'}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n >\n <option value=\"SERVICE\">{tr('component.typeService', 'Service')}</option>\n <option value=\"FRONTEND\">{tr('component.typeFrontend', 'Frontend')}</option>\n <option value=\"LIBRARY\">{tr('component.typeLibrary', 'Library')}</option>\n <option value=\"API\">{tr('component.typeApi', 'API')}</option>\n <option value=\"MOBILE\">{tr('component.typeMobile', 'Mobile')}</option>\n <option value=\"DATABASE\">{tr('component.typeDatabase', 'Database')}</option>\n <option value=\"INFRASTRUCTURE\">\n {tr('component.typeInfrastructure', 'Infrastructure')}\n </option>\n <option value=\"CUSTOM\">{tr('component.typeCustom', 'Custom')}</option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.lifecycleLabel', 'Lifecycle')}\n </label>\n <select\n ref={lifecycleRef}\n defaultValue={initialData?.lifecycle || 'EXPERIMENTAL'}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n >\n <option value=\"EXPERIMENTAL\">\n {tr('component.lifecycleExperimental', 'Experimental')}\n </option>\n <option value=\"ACTIVE\">{tr('component.lifecycleActive', 'Active')}</option>\n <option value=\"DEPRECATED\">\n {tr('component.lifecycleDeprecated', 'Deprecated')}\n </option>\n <option value=\"END_OF_LIFE\">\n {tr('component.lifecycleEndOfLife', 'End of Life')}\n </option>\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.languageLabel', 'Language')}\n </label>\n <input\n aria-label=\"control\"\n ref={languageRef}\n type=\"text\"\n defaultValue={initialData?.language || ''}\n placeholder={tr('component.languagePlaceholder', 'TypeScript')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.frameworkLabel', 'Framework')}\n </label>\n <input\n aria-label=\"control\"\n ref={frameworkRef}\n type=\"text\"\n defaultValue={initialData?.framework || ''}\n placeholder={tr('component.frameworkPlaceholder', 'React')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.versionLabel', 'Version')}\n </label>\n <input\n aria-label=\"control\"\n ref={versionRef}\n type=\"text\"\n defaultValue={initialData?.version || ''}\n placeholder={tr('component.versionPlaceholder', '1.0.0')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.ownerLabel', 'Owner')}\n </label>\n <input\n aria-label=\"control\"\n ref={ownerNameRef}\n type=\"text\"\n defaultValue={initialData?.ownerName || ''}\n placeholder={tr('component.ownerPlaceholder', 'team-name')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.tagsLabel', 'Tags (comma-separated)')}\n </label>\n <input\n aria-label=\"control\"\n ref={tagsRef}\n type=\"text\"\n defaultValue={initialData?.tags?.join(', ') || ''}\n placeholder={tr('component.tagsPlaceholder', 'backend, api, graphql')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n\n {/* Advanced section */}\n <div className=\"border border-border-default rounded-md overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n className=\"w-full flex items-center justify-between px-3 py-2 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors text-sm font-medium text-text-secondary\"\n >\n <span>{tr('component.advancedSection', 'Advanced (Docs, Dependencies, SBOM)')}</span>\n {showAdvanced ? (\n <ChevronDown className=\"size-4\" />\n ) : (\n <ChevronRight className=\"size-4\" />\n )}\n </button>\n {showAdvanced && (\n <div className=\"p-3 space-y-4 border-t border-border-default\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.documentationUrl', 'Documentation URL')}\n </label>\n <input\n aria-label=\"https://docs.example.com\"\n ref={documentationUrlRef}\n type=\"url\"\n defaultValue={initialData?.documentationUrl || ''}\n placeholder=\"https://docs.example.com\"\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder text-sm\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.dependencies', 'Dependencies (JSON array)')}\n </label>\n <textarea\n aria-label=\"control\"\n ref={dependenciesRef}\n rows={4}\n defaultValue={\n initialData?.dependencies\n ? JSON.stringify(initialData.dependencies, null, 2)\n : ''\n }\n placeholder={\n '[\\n {\"name\": \"react\", \"version\": \"19.0.0\", \"type\": \"runtime\"},\\n {\"name\": \"typescript\", \"version\": \"5.9.0\", \"type\": \"dev\"}\\n]'\n }\n className={`w-full px-3 py-2 bg-bg-sunken border rounded-md text-text-primary placeholder:text-text-muted font-mono text-xs resize-y ${fieldErrors.dependencies ? 'border-status-error-border' : 'border-border-default'}`}\n />\n {fieldErrors.dependencies && (\n <p className=\"mt-1 text-xs text-status-error-text\">\n {fieldErrors.dependencies}\n </p>\n )}\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'component.dependenciesHint',\n 'Used to build the Dependency Graph in Catalogs. Each entry: {name, version, type}.'\n )}\n </p>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.sbomData', 'SBOM Data (CycloneDX / SPDX JSON)')}\n </label>\n <textarea\n aria-label=\"control\"\n ref={sbomDataRef}\n rows={5}\n defaultValue={\n initialData?.sbomData ? JSON.stringify(initialData.sbomData, null, 2) : ''\n }\n placeholder={\n '{\\n \"bomFormat\": \"CycloneDX\",\\n \"specVersion\": \"1.4\",\\n \"components\": [...]\\n}'\n }\n className={`w-full px-3 py-2 bg-bg-sunken border rounded-md text-text-primary placeholder:text-text-muted font-mono text-xs resize-y ${fieldErrors.sbomData ? 'border-status-error-border' : 'border-border-default'}`}\n />\n {fieldErrors.sbomData && (\n <p className=\"mt-1 text-xs text-status-error-text\">{fieldErrors.sbomData}</p>\n )}\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'component.sbomDataHint',\n 'Paste output from syft, trivy, or npm sbom. Aggregated per-catalog in the SBOM tab.'\n )}\n </p>\n </div>\n </div>\n )}\n </div>\n </div>\n {extraSection && (\n <div className=\"mt-4 border-t border-border-default pt-4\">{extraSection}</div>\n )}\n <div className=\"flex flex-col sm:flex-row justify-end gap-3 mt-6\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={loading}\n className=\"px-4 py-2 text-text-primary hover:bg-bg-sunken rounded-md transition-colors disabled:opacity-50\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={loading}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {loading\n ? tr('common.saving', 'Saving...')\n : initialData?.name\n ? tr('common.save', 'Save')\n : tr('component.createComponent', 'Create Component')}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ComponentForm.js","names":[],"sources":["../../../src/components/idp-components/ComponentForm.tsx"],"sourcesContent":["import { useRef, useState } from 'react';\nimport type { FC, ReactNode } from 'react';\nimport { X, ChevronDown, ChevronRight, Github } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nexport interface ComponentFormData {\n name: string;\n description: string;\n type:\n | 'SERVICE'\n | 'FRONTEND'\n | 'LIBRARY'\n | 'API'\n | 'MOBILE'\n | 'DATABASE'\n | 'INFRASTRUCTURE'\n | 'CUSTOM';\n lifecycle: 'EXPERIMENTAL' | 'ACTIVE' | 'DEPRECATED' | 'END_OF_LIFE';\n language: string;\n framework: string;\n version: string;\n ownerName: string;\n tags: string[];\n repositoryUrl?: string;\n documentationUrl?: string;\n dependencies?: Array<{ name: string; version?: string; type?: string }> | null;\n sbomData?: Record<string, unknown> | null;\n}\n\nexport interface ComponentFormProps {\n isOpen: boolean;\n onClose: () => void;\n onSubmit: (data: ComponentFormData) => Promise<void>;\n initialData?: Partial<ComponentFormData>;\n title?: string;\n /** Optional extra content (e.g. a draft EntityTagPicker) rendered above the footer. */\n extraSection?: ReactNode;\n}\n\nexport const ComponentForm: FC<ComponentFormProps> = ({\n isOpen,\n onClose,\n onSubmit,\n initialData,\n title,\n extraSection,\n}) => {\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 const nameRef = useRef<HTMLInputElement>(null);\n const descriptionRef = useRef<HTMLTextAreaElement>(null);\n const typeRef = useRef<HTMLSelectElement>(null);\n const lifecycleRef = useRef<HTMLSelectElement>(null);\n const languageRef = useRef<HTMLInputElement>(null);\n const frameworkRef = useRef<HTMLInputElement>(null);\n const versionRef = useRef<HTMLInputElement>(null);\n const ownerNameRef = useRef<HTMLInputElement>(null);\n const tagsRef = useRef<HTMLInputElement>(null);\n const repositoryUrlRef = useRef<HTMLInputElement>(null);\n const documentationUrlRef = useRef<HTMLInputElement>(null);\n const dependenciesRef = useRef<HTMLTextAreaElement>(null);\n const sbomDataRef = useRef<HTMLTextAreaElement>(null);\n\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [fieldErrors, setFieldErrors] = useState<{\n name?: string;\n repositoryUrl?: string;\n dependencies?: string;\n sbomData?: string;\n }>({});\n const [showAdvanced, setShowAdvanced] = useState(false);\n\n if (!isOpen) return null;\n\n const handleSubmit = async () => {\n const name = nameRef.current?.value?.trim();\n if (!name) {\n setFieldErrors({ name: tr('component.nameRequired', 'Name is required') });\n setError(tr('component.fillRequired', 'Please fill in all required fields'));\n return;\n }\n\n const repoUrl = repositoryUrlRef.current?.value?.trim();\n if (!repoUrl) {\n setFieldErrors({\n repositoryUrl: tr('component.repositoryUrlRequired', 'Repository URL is required'),\n });\n setError(tr('component.fillRequired', 'Please fill in all required fields'));\n return;\n }\n if (!/^https?:\\/\\/.+\\/.+/.test(repoUrl)) {\n setFieldErrors({\n repositoryUrl: tr(\n 'component.repositoryUrlInvalid',\n 'Enter a valid repository URL (e.g. https://github.com/org/repo)'\n ),\n });\n setError(tr('component.fillRequired', 'Please fix the errors above'));\n return;\n }\n\n const newFieldErrors: {\n name?: string;\n repositoryUrl?: string;\n dependencies?: string;\n sbomData?: string;\n } = {};\n\n let parsedDependencies: ComponentFormData['dependencies'] = null;\n const depsRaw = dependenciesRef.current?.value?.trim();\n if (depsRaw) {\n try {\n parsedDependencies = JSON.parse(depsRaw);\n if (!Array.isArray(parsedDependencies)) throw new Error('Must be a JSON array');\n } catch {\n newFieldErrors.dependencies =\n 'Invalid JSON — must be an array like [{\"name\":\"react\",\"version\":\"19.0.0\"}]';\n }\n }\n\n let parsedSbom: ComponentFormData['sbomData'] = null;\n const sbomRaw = sbomDataRef.current?.value?.trim();\n if (sbomRaw) {\n try {\n parsedSbom = JSON.parse(sbomRaw);\n } catch {\n newFieldErrors.sbomData = 'Invalid JSON — paste a valid CycloneDX or SPDX document';\n }\n }\n\n if (Object.keys(newFieldErrors).length > 0) {\n setFieldErrors(newFieldErrors);\n setError(tr('component.fillRequired', 'Please fix the errors above'));\n return;\n }\n\n setFieldErrors({});\n\n const data: ComponentFormData = {\n name,\n description: descriptionRef.current?.value?.trim() || '',\n type: (typeRef.current?.value as ComponentFormData['type']) || 'SERVICE',\n lifecycle: (lifecycleRef.current?.value as ComponentFormData['lifecycle']) || 'EXPERIMENTAL',\n language: languageRef.current?.value?.trim() || '',\n framework: frameworkRef.current?.value?.trim() || '',\n version: versionRef.current?.value?.trim() || '',\n ownerName: ownerNameRef.current?.value?.trim() || '',\n tags: tagsRef.current?.value\n ? tagsRef.current.value\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n : [],\n repositoryUrl: repositoryUrlRef.current?.value?.trim() || undefined,\n documentationUrl: documentationUrlRef.current?.value?.trim() || undefined,\n dependencies: parsedDependencies,\n sbomData: parsedSbom,\n };\n\n setLoading(true);\n setError(null);\n try {\n await onSubmit(data);\n onClose();\n } catch (err) {\n setError(\n err instanceof Error ? err.message : tr('component.failedSave', 'Failed to save component')\n );\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 flex items-center justify-center z-50 p-4\"\n style={{ backgroundColor: 'rgba(0,0,0,0.55)' }}\n >\n <div className=\"bg-bg-surface rounded-lg p-6 w-full max-w-lg max-h-[90vh] overflow-y-auto\">\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {title || tr('component.createComponent', 'Create Component')}\n </h2>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-1 rounded hover:bg-bg-sunken transition-colors text-text-secondary\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n <div className=\"space-y-4\">\n {error && (\n <div className=\"p-3 bg-status-error-bg-subtle text-status-error-text text-sm rounded-md\">\n {error}\n </div>\n )}\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.nameLabel', 'Name *')}\n </label>\n <input\n aria-label=\"control\"\n ref={nameRef}\n type=\"text\"\n defaultValue={initialData?.name || ''}\n placeholder={tr('component.namePlaceholder', 'my-service')}\n onChange={() =>\n fieldErrors.name && setFieldErrors((e) => ({ ...e, name: undefined }))\n }\n className={`w-full px-3 py-2 bg-bg-sunken border rounded-md text-text-primary placeholder:text-text-placeholder ${fieldErrors.name ? 'border-status-error-border' : 'border-border-default'}`}\n />\n {fieldErrors.name && (\n <p className=\"mt-1 text-xs text-status-error-text\">{fieldErrors.name}</p>\n )}\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.descriptionLabel', 'Description')}\n </label>\n <textarea\n aria-label=\"control\"\n ref={descriptionRef}\n defaultValue={initialData?.description || ''}\n placeholder={tr('component.descriptionPlaceholder', 'Describe this component...')}\n rows={3}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder resize-none\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n <span className=\"flex items-center gap-1.5\">\n <Github className=\"size-3.5\" />\n {tr('component.repositoryUrl', 'Repository URL')}{' '}\n <span className=\"text-status-error-text\">*</span>\n </span>\n </label>\n <input\n aria-label=\"https://github.com/org/repo\"\n ref={repositoryUrlRef}\n type=\"url\"\n defaultValue={initialData?.repositoryUrl || ''}\n placeholder=\"https://github.com/org/repo\"\n onChange={() =>\n fieldErrors.repositoryUrl &&\n setFieldErrors((e) => ({ ...e, repositoryUrl: undefined }))\n }\n className={`w-full px-3 py-2 bg-bg-sunken border rounded-md text-text-primary placeholder:text-text-placeholder text-sm ${fieldErrors.repositoryUrl ? 'border-status-error-border' : 'border-border-default'}`}\n />\n {fieldErrors.repositoryUrl && (\n <p className=\"mt-1 text-xs text-status-error-text\">{fieldErrors.repositoryUrl}</p>\n )}\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.typeLabel', 'Type')}\n </label>\n <select\n ref={typeRef}\n defaultValue={initialData?.type || 'SERVICE'}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n >\n <option value=\"SERVICE\">{tr('component.typeService', 'Service')}</option>\n <option value=\"FRONTEND\">{tr('component.typeFrontend', 'Frontend')}</option>\n <option value=\"LIBRARY\">{tr('component.typeLibrary', 'Library')}</option>\n <option value=\"API\">{tr('component.typeApi', 'API')}</option>\n <option value=\"MOBILE\">{tr('component.typeMobile', 'Mobile')}</option>\n <option value=\"DATABASE\">{tr('component.typeDatabase', 'Database')}</option>\n <option value=\"INFRASTRUCTURE\">\n {tr('component.typeInfrastructure', 'Infrastructure')}\n </option>\n <option value=\"CUSTOM\">{tr('component.typeCustom', 'Custom')}</option>\n </select>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.lifecycleLabel', 'Lifecycle')}\n </label>\n <select\n ref={lifecycleRef}\n defaultValue={initialData?.lifecycle || 'EXPERIMENTAL'}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary\"\n >\n <option value=\"EXPERIMENTAL\">\n {tr('component.lifecycleExperimental', 'Experimental')}\n </option>\n <option value=\"ACTIVE\">{tr('component.lifecycleActive', 'Active')}</option>\n <option value=\"DEPRECATED\">\n {tr('component.lifecycleDeprecated', 'Deprecated')}\n </option>\n <option value=\"END_OF_LIFE\">\n {tr('component.lifecycleEndOfLife', 'End of Life')}\n </option>\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.languageLabel', 'Language')}\n </label>\n <input\n aria-label=\"control\"\n ref={languageRef}\n type=\"text\"\n defaultValue={initialData?.language || ''}\n placeholder={tr('component.languagePlaceholder', 'TypeScript')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.frameworkLabel', 'Framework')}\n </label>\n <input\n aria-label=\"control\"\n ref={frameworkRef}\n type=\"text\"\n defaultValue={initialData?.framework || ''}\n placeholder={tr('component.frameworkPlaceholder', 'React')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n </div>\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.versionLabel', 'Version')}\n </label>\n <input\n aria-label=\"control\"\n ref={versionRef}\n type=\"text\"\n defaultValue={initialData?.version || ''}\n placeholder={tr('component.versionPlaceholder', '1.0.0')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.ownerLabel', 'Owner')}\n </label>\n <input\n aria-label=\"control\"\n ref={ownerNameRef}\n type=\"text\"\n defaultValue={initialData?.ownerName || ''}\n placeholder={tr('component.ownerPlaceholder', 'team-name')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.tagsLabel', 'Tags (comma-separated)')}\n </label>\n <input\n aria-label=\"control\"\n ref={tagsRef}\n type=\"text\"\n defaultValue={initialData?.tags?.join(', ') || ''}\n placeholder={tr('component.tagsPlaceholder', 'backend, api, graphql')}\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder\"\n />\n </div>\n\n {/* Advanced section */}\n <div className=\"border border-border-default rounded-md overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setShowAdvanced((v) => !v)}\n className=\"w-full flex items-center justify-between px-3 py-2 bg-bg-sunken hover:bg-bg-sunken/80 transition-colors text-sm font-medium text-text-secondary\"\n >\n <span>{tr('component.advancedSection', 'Advanced (Docs, Dependencies, SBOM)')}</span>\n {showAdvanced ? (\n <ChevronDown className=\"size-4\" />\n ) : (\n <ChevronRight className=\"size-4\" />\n )}\n </button>\n {showAdvanced && (\n <div className=\"p-3 space-y-4 border-t border-border-default\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.documentationUrl', 'Documentation URL')}\n </label>\n <input\n aria-label=\"https://docs.example.com\"\n ref={documentationUrlRef}\n type=\"url\"\n defaultValue={initialData?.documentationUrl || ''}\n placeholder=\"https://docs.example.com\"\n className=\"w-full px-3 py-2 bg-bg-sunken border border-border-default rounded-md text-text-primary placeholder:text-text-placeholder text-sm\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.dependencies', 'Dependencies (JSON array)')}\n </label>\n <textarea\n aria-label=\"control\"\n ref={dependenciesRef}\n rows={4}\n defaultValue={\n initialData?.dependencies\n ? JSON.stringify(initialData.dependencies, null, 2)\n : ''\n }\n placeholder={\n '[\\n {\"name\": \"react\", \"version\": \"19.0.0\", \"type\": \"runtime\"},\\n {\"name\": \"typescript\", \"version\": \"5.9.0\", \"type\": \"dev\"}\\n]'\n }\n className={`w-full px-3 py-2 bg-bg-sunken border rounded-md text-text-primary placeholder:text-text-muted font-mono text-xs resize-y ${fieldErrors.dependencies ? 'border-status-error-border' : 'border-border-default'}`}\n />\n {fieldErrors.dependencies && (\n <p className=\"mt-1 text-xs text-status-error-text\">\n {fieldErrors.dependencies}\n </p>\n )}\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'component.dependenciesHint',\n 'Used to build the Dependency Graph in Catalogs. Each entry: {name, version, type}.'\n )}\n </p>\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n {tr('component.sbomData', 'SBOM Data (CycloneDX / SPDX JSON)')}\n </label>\n <textarea\n aria-label=\"control\"\n ref={sbomDataRef}\n rows={5}\n defaultValue={\n initialData?.sbomData ? JSON.stringify(initialData.sbomData, null, 2) : ''\n }\n placeholder={\n '{\\n \"bomFormat\": \"CycloneDX\",\\n \"specVersion\": \"1.4\",\\n \"components\": [...]\\n}'\n }\n className={`w-full px-3 py-2 bg-bg-sunken border rounded-md text-text-primary placeholder:text-text-muted font-mono text-xs resize-y ${fieldErrors.sbomData ? 'border-status-error-border' : 'border-border-default'}`}\n />\n {fieldErrors.sbomData && (\n <p className=\"mt-1 text-xs text-status-error-text\">{fieldErrors.sbomData}</p>\n )}\n <p className=\"mt-1 text-xs text-text-muted\">\n {tr(\n 'component.sbomDataHint',\n 'Paste output from syft, trivy, or npm sbom. Aggregated per-catalog in the SBOM tab.'\n )}\n </p>\n </div>\n </div>\n )}\n </div>\n </div>\n {extraSection && (\n <div className=\"mt-4 border-t border-border-default pt-4\">{extraSection}</div>\n )}\n <div className=\"flex flex-col sm:flex-row justify-end gap-3 mt-6\">\n <button\n type=\"button\"\n onClick={onClose}\n disabled={loading}\n className=\"px-4 py-2 text-text-primary hover:bg-bg-sunken rounded-md transition-colors disabled:opacity-50\"\n >\n {tr('common.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={loading}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors disabled:opacity-50\"\n >\n {loading\n ? tr('common.saving', 'Saving...')\n : initialData?.name\n ? tr('common.save', 'Save')\n : tr('component.createComponent', 'Create Component')}\n </button>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -45,12 +45,12 @@ function p(e) {
|
|
|
45
45
|
case "peer": return {
|
|
46
46
|
...t,
|
|
47
47
|
backgroundColor: "var(--color-status-info-border)",
|
|
48
|
-
color: "
|
|
48
|
+
color: "var(--color-text-inverse)"
|
|
49
49
|
};
|
|
50
50
|
case "dev": return {
|
|
51
51
|
...t,
|
|
52
52
|
backgroundColor: "var(--color-border-strong)",
|
|
53
|
-
color: "
|
|
53
|
+
color: "var(--color-text-inverse)"
|
|
54
54
|
};
|
|
55
55
|
case "optional": return {
|
|
56
56
|
...t,
|
|
@@ -60,7 +60,7 @@ function p(e) {
|
|
|
60
60
|
default: return {
|
|
61
61
|
...t,
|
|
62
62
|
backgroundColor: "var(--color-action-primary-bg)",
|
|
63
|
-
color: "
|
|
63
|
+
color: "var(--color-action-primary-text)"
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -106,7 +106,7 @@ function h(e, t) {
|
|
|
106
106
|
style: {
|
|
107
107
|
fontSize: 10,
|
|
108
108
|
marginTop: 3,
|
|
109
|
-
backgroundColor: "
|
|
109
|
+
backgroundColor: "var(--color-accent-soft)",
|
|
110
110
|
borderRadius: 4,
|
|
111
111
|
padding: "1px 6px",
|
|
112
112
|
display: "inline-block",
|
|
@@ -128,13 +128,13 @@ function g(e, t, n) {
|
|
|
128
128
|
data: { label: h(e, t) },
|
|
129
129
|
style: {
|
|
130
130
|
backgroundColor: "var(--color-action-primary-bg)",
|
|
131
|
-
color: "
|
|
131
|
+
color: "var(--color-action-primary-text)",
|
|
132
132
|
borderRadius: 10,
|
|
133
133
|
padding: "10px 16px",
|
|
134
134
|
width: 160,
|
|
135
135
|
fontWeight: 700,
|
|
136
136
|
fontSize: 13,
|
|
137
|
-
boxShadow: "
|
|
137
|
+
boxShadow: "var(--shadow-elevation-2)",
|
|
138
138
|
border: "none",
|
|
139
139
|
textAlign: "center"
|
|
140
140
|
}
|
|
@@ -178,7 +178,7 @@ function _({ componentName: t, componentType: s, deps: d, canvasHeight: f }) {
|
|
|
178
178
|
d
|
|
179
179
|
]), [h, , _] = u(p), [v, , y] = l(m);
|
|
180
180
|
return /* @__PURE__ */ n("div", {
|
|
181
|
-
className: "w-full rounded-lg border border-border-default overflow-hidden bg-bg-
|
|
181
|
+
className: "w-full rounded-lg border border-border-default overflow-hidden bg-bg-surface",
|
|
182
182
|
style: { height: f },
|
|
183
183
|
children: /* @__PURE__ */ r(c, {
|
|
184
184
|
nodes: h,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DependencyGraphTab.js","names":[],"sources":["../../../src/components/idp-components/DependencyGraphTab.tsx"],"sourcesContent":["/**\n * DependencyGraphTab — React Flow visualization of a component's dependency graph.\n *\n * Root component node sits on the RIGHT; dependency nodes stack on the LEFT.\n * Edges flow LEFT → RIGHT with type-specific styling.\n * A compact table below the canvas lists all dependencies.\n */\n\nimport { useMemo } from 'react';\nimport { PackageOpen } from 'lucide-react';\nimport '@xyflow/react/dist/style.css';\nimport {\n ReactFlow,\n Background,\n Controls,\n useNodesState,\n useEdgesState,\n type Node,\n type Edge,\n MarkerType,\n BackgroundVariant,\n} from '@xyflow/react';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface DependencyGraphTabProps {\n componentName: string;\n componentType: string;\n dependencies: Array<{ name: string; version?: string | null; type?: string | null }> | null;\n}\n\ntype DepType = 'runtime' | 'dev' | 'peer' | 'optional' | null;\n\nconst MAX_GRAPH_DEPS = 40;\n\n// ---------------------------------------------------------------------------\n// Inline style helpers (React Flow nodes render in a portal — no Tailwind)\n// ---------------------------------------------------------------------------\n\nfunction depNodeStyle(type: DepType): React.CSSProperties {\n switch (type) {\n case 'peer':\n return {\n backgroundColor: 'var(--color-status-info-bg)',\n border: '1px solid var(--color-status-info-border)',\n color: 'var(--color-text-primary)',\n };\n case 'dev':\n return {\n backgroundColor: 'var(--color-bg-sunken)',\n border: '1px dashed var(--color-border-default)',\n color: 'var(--color-text-secondary)',\n };\n case 'optional':\n return {\n backgroundColor: 'var(--color-bg-sunken)',\n border: '1px solid var(--color-border-default)',\n color: 'var(--color-text-primary)',\n opacity: 0.7,\n };\n default:\n // runtime or null\n return {\n backgroundColor: 'var(--color-bg-sunken)',\n border: '1px solid var(--color-border-default)',\n color: 'var(--color-text-primary)',\n };\n }\n}\n\nfunction depTypeBadgeStyle(type: DepType): React.CSSProperties {\n const base: React.CSSProperties = {\n display: 'inline-block',\n fontSize: 10,\n fontWeight: 600,\n borderRadius: 4,\n padding: '1px 5px',\n marginLeft: 4,\n textTransform: 'uppercase',\n letterSpacing: '0.04em',\n };\n switch (type) {\n case 'peer':\n return { ...base, backgroundColor: 'var(--color-status-info-border)', color: '#fff' };\n case 'dev':\n return { ...base, backgroundColor: 'var(--color-border-strong)', color: '#fff' };\n case 'optional':\n return {\n ...base,\n backgroundColor: 'var(--color-border-default)',\n color: 'var(--color-text-secondary)',\n };\n default:\n return { ...base, backgroundColor: 'var(--color-action-primary-bg)', color: '#fff' };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Label renderers (ReactNode — React Flow default node accepts ReactNode label)\n// ---------------------------------------------------------------------------\n\nfunction makeDepLabel(dep: {\n name: string;\n version?: string | null;\n type?: string | null;\n}): React.ReactNode {\n const depType = (dep.type ?? null) as DepType;\n return (\n <div style={{ lineHeight: 1.4 }}>\n <div\n style={{\n fontWeight: 600,\n maxWidth: 180,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {dep.name}\n {depType && <span style={depTypeBadgeStyle(depType)}>{depType}</span>}\n </div>\n {dep.version && (\n <div style={{ fontSize: 10, color: 'var(--color-text-muted)', marginTop: 2 }}>\n {dep.version}\n </div>\n )}\n </div>\n );\n}\n\nfunction makeRootLabel(componentName: string, componentType: string): React.ReactNode {\n return (\n <div style={{ lineHeight: 1.4, textAlign: 'center' }}>\n <div style={{ fontWeight: 700, fontSize: 13 }}>{componentName}</div>\n <div\n style={{\n fontSize: 10,\n marginTop: 3,\n backgroundColor: 'rgba(255,255,255,0.2)',\n borderRadius: 4,\n padding: '1px 6px',\n display: 'inline-block',\n letterSpacing: '0.05em',\n textTransform: 'uppercase',\n }}\n >\n {componentType}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Graph element builder\n// ---------------------------------------------------------------------------\n\nfunction buildGraphElements(\n componentName: string,\n componentType: string,\n deps: Array<{ name: string; version?: string | null; type?: string | null }>\n): { nodes: Node[]; edges: Edge[] } {\n const visible = deps.slice(0, MAX_GRAPH_DEPS);\n const totalHeight = Math.max(visible.length * 80, 80);\n const rootY = totalHeight / 2 - 24;\n\n const nodes: Node[] = [];\n const edges: Edge[] = [];\n\n // Root node\n nodes.push({\n id: 'root',\n position: { x: 520, y: rootY },\n data: { label: makeRootLabel(componentName, componentType) },\n style: {\n backgroundColor: 'var(--color-action-primary-bg)',\n color: '#fff',\n borderRadius: 10,\n padding: '10px 16px',\n width: 160,\n fontWeight: 700,\n fontSize: 13,\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\n border: 'none',\n textAlign: 'center',\n },\n });\n\n // Dependency nodes and edges\n visible.forEach((dep, i) => {\n const depType = (dep.type ?? null) as DepType;\n const nodeId = `dep-${i}`;\n const isRuntime = !depType || depType === 'runtime';\n const isDev = depType === 'dev';\n\n nodes.push({\n id: nodeId,\n position: { x: 40, y: 20 + i * 80 },\n data: { label: makeDepLabel(dep) },\n style: {\n ...depNodeStyle(depType),\n borderRadius: 8,\n padding: '8px 12px',\n width: 220,\n fontSize: 12,\n },\n });\n\n edges.push({\n id: `edge-${i}`,\n source: nodeId,\n target: 'root',\n animated: isRuntime,\n markerEnd: { type: MarkerType.ArrowClosed },\n style: {\n stroke: 'var(--color-border-strong)',\n strokeWidth: 1.5,\n ...(isDev ? { strokeDasharray: '4 2' } : {}),\n },\n });\n });\n\n return { nodes, edges };\n}\n\n// ---------------------------------------------------------------------------\n// Inner React Flow component (needs its own hook calls — can't be conditional)\n// ---------------------------------------------------------------------------\n\ninterface DependencyFlowProps {\n componentName: string;\n componentType: string;\n deps: Array<{ name: string; version?: string | null; type?: string | null }>;\n canvasHeight: number;\n}\n\nfunction DependencyFlow({ componentName, componentType, deps, canvasHeight }: DependencyFlowProps) {\n const { nodes: initialNodes, edges: initialEdges } = useMemo(\n () => buildGraphElements(componentName, componentType, deps),\n [componentName, componentType, deps]\n );\n\n const [nodes, , onNodesChange] = useNodesState(initialNodes);\n const [edges, , onEdgesChange] = useEdgesState(initialEdges);\n\n return (\n <div\n className=\"w-full rounded-lg border border-border-default overflow-hidden bg-bg-secondary\"\n style={{ height: canvasHeight }}\n >\n <ReactFlow\n nodes={nodes}\n edges={edges}\n onNodesChange={onNodesChange}\n onEdgesChange={onEdgesChange}\n nodesDraggable={false}\n fitView\n fitViewOptions={{ padding: 0.15 }}\n minZoom={0.2}\n maxZoom={2}\n panOnDrag\n proOptions={{ hideAttribution: true }}\n >\n <Background\n variant={BackgroundVariant.Dots}\n gap={20}\n size={1}\n className=\"!fill-text-tertiary/10\"\n />\n <Controls\n showInteractive={false}\n style={{\n background: 'var(--color-bg-primary)',\n border: '1px solid var(--color-border-default)',\n borderRadius: 8,\n boxShadow: '0 1px 4px var(--color-border-default)',\n }}\n className=\"[&_button]:!bg-[var(--color-bg-primary)] [&_button]:!border-[var(--color-border-default)] [&_button]:!fill-[var(--color-text-secondary)] [&_button:hover]:!bg-[var(--color-bg-sunken)]\"\n />\n </ReactFlow>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main export\n// ---------------------------------------------------------------------------\n\nexport function DependencyGraphTab({\n componentName,\n componentType,\n dependencies,\n}: DependencyGraphTabProps) {\n const deps = dependencies ?? [];\n const visibleCount = Math.min(deps.length, MAX_GRAPH_DEPS);\n const hiddenCount = deps.length - visibleCount;\n const canvasHeight = Math.max(400, Math.min(deps.length * 80 + 100, 600));\n\n if (deps.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-center gap-4\">\n <PackageOpen className=\"size-10 text-text-muted\" />\n <p className=\"text-sm text-text-secondary max-w-xs\">\n No dependencies recorded. Add them via Settings.\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Graph canvas */}\n <div>\n {hiddenCount > 0 && (\n <p className=\"text-xs text-text-muted mb-2 text-right\">\n Showing {visibleCount} of {deps.length} dependencies (+{hiddenCount} more in table\n below)\n </p>\n )}\n <DependencyFlow\n componentName={componentName}\n componentType={componentType}\n deps={deps}\n canvasHeight={canvasHeight}\n />\n </div>\n\n {/* All-dependencies table */}\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary mb-3\">\n All Dependencies ({deps.length})\n </h3>\n <div className=\"overflow-x-auto rounded-lg border border-border-default\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left font-medium text-text-secondary\">Name</th>\n <th className=\"px-4 py-2.5 text-left font-medium text-text-secondary\">Version</th>\n <th className=\"px-4 py-2.5 text-left font-medium text-text-secondary\">Type</th>\n </tr>\n </thead>\n <tbody>\n {deps.map((dep, i) => (\n <tr\n key={`${dep.name}-${i}`}\n className=\"border-b border-border-default last:border-0 hover:bg-bg-sunken/50 transition-colors\"\n >\n <td className=\"px-4 py-2.5 font-mono text-xs text-text-primary\">{dep.name}</td>\n <td className=\"px-4 py-2.5 text-text-secondary\">{dep.version ?? '—'}</td>\n <td className=\"px-4 py-2.5\">\n {dep.type ? (\n <span className=\"inline-flex items-center px-2 py-0.5 text-xs font-medium rounded bg-bg-sunken text-text-secondary\">\n {dep.type}\n </span>\n ) : (\n <span className=\"text-text-muted\">runtime</span>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DependencyGraphTab.js","names":[],"sources":["../../../src/components/idp-components/DependencyGraphTab.tsx"],"sourcesContent":["/**\n * DependencyGraphTab — React Flow visualization of a component's dependency graph.\n *\n * Root component node sits on the RIGHT; dependency nodes stack on the LEFT.\n * Edges flow LEFT → RIGHT with type-specific styling.\n * A compact table below the canvas lists all dependencies.\n */\n\nimport { useMemo } from 'react';\nimport { PackageOpen } from 'lucide-react';\nimport '@xyflow/react/dist/style.css';\nimport {\n ReactFlow,\n Background,\n Controls,\n useNodesState,\n useEdgesState,\n type Node,\n type Edge,\n MarkerType,\n BackgroundVariant,\n} from '@xyflow/react';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface DependencyGraphTabProps {\n componentName: string;\n componentType: string;\n dependencies: Array<{ name: string; version?: string | null; type?: string | null }> | null;\n}\n\ntype DepType = 'runtime' | 'dev' | 'peer' | 'optional' | null;\n\nconst MAX_GRAPH_DEPS = 40;\n\n// ---------------------------------------------------------------------------\n// Inline style helpers (React Flow nodes render in a portal — no Tailwind)\n// ---------------------------------------------------------------------------\n\nfunction depNodeStyle(type: DepType): React.CSSProperties {\n switch (type) {\n case 'peer':\n return {\n backgroundColor: 'var(--color-status-info-bg)',\n border: '1px solid var(--color-status-info-border)',\n color: 'var(--color-text-primary)',\n };\n case 'dev':\n return {\n backgroundColor: 'var(--color-bg-sunken)',\n border: '1px dashed var(--color-border-default)',\n color: 'var(--color-text-secondary)',\n };\n case 'optional':\n return {\n backgroundColor: 'var(--color-bg-sunken)',\n border: '1px solid var(--color-border-default)',\n color: 'var(--color-text-primary)',\n opacity: 0.7,\n };\n default:\n // runtime or null\n return {\n backgroundColor: 'var(--color-bg-sunken)',\n border: '1px solid var(--color-border-default)',\n color: 'var(--color-text-primary)',\n };\n }\n}\n\nfunction depTypeBadgeStyle(type: DepType): React.CSSProperties {\n const base: React.CSSProperties = {\n display: 'inline-block',\n fontSize: 10,\n fontWeight: 600,\n borderRadius: 4,\n padding: '1px 5px',\n marginLeft: 4,\n textTransform: 'uppercase',\n letterSpacing: '0.04em',\n };\n switch (type) {\n case 'peer':\n return {\n ...base,\n backgroundColor: 'var(--color-status-info-border)',\n color: 'var(--color-text-inverse)',\n };\n case 'dev':\n return {\n ...base,\n backgroundColor: 'var(--color-border-strong)',\n color: 'var(--color-text-inverse)',\n };\n case 'optional':\n return {\n ...base,\n backgroundColor: 'var(--color-border-default)',\n color: 'var(--color-text-secondary)',\n };\n default:\n return {\n ...base,\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Label renderers (ReactNode — React Flow default node accepts ReactNode label)\n// ---------------------------------------------------------------------------\n\nfunction makeDepLabel(dep: {\n name: string;\n version?: string | null;\n type?: string | null;\n}): React.ReactNode {\n const depType = (dep.type ?? null) as DepType;\n return (\n <div style={{ lineHeight: 1.4 }}>\n <div\n style={{\n fontWeight: 600,\n maxWidth: 180,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {dep.name}\n {depType && <span style={depTypeBadgeStyle(depType)}>{depType}</span>}\n </div>\n {dep.version && (\n <div style={{ fontSize: 10, color: 'var(--color-text-muted)', marginTop: 2 }}>\n {dep.version}\n </div>\n )}\n </div>\n );\n}\n\nfunction makeRootLabel(componentName: string, componentType: string): React.ReactNode {\n return (\n <div style={{ lineHeight: 1.4, textAlign: 'center' }}>\n <div style={{ fontWeight: 700, fontSize: 13 }}>{componentName}</div>\n <div\n style={{\n fontSize: 10,\n marginTop: 3,\n backgroundColor: 'var(--color-accent-soft)',\n borderRadius: 4,\n padding: '1px 6px',\n display: 'inline-block',\n letterSpacing: '0.05em',\n textTransform: 'uppercase',\n }}\n >\n {componentType}\n </div>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Graph element builder\n// ---------------------------------------------------------------------------\n\nfunction buildGraphElements(\n componentName: string,\n componentType: string,\n deps: Array<{ name: string; version?: string | null; type?: string | null }>\n): { nodes: Node[]; edges: Edge[] } {\n const visible = deps.slice(0, MAX_GRAPH_DEPS);\n const totalHeight = Math.max(visible.length * 80, 80);\n const rootY = totalHeight / 2 - 24;\n\n const nodes: Node[] = [];\n const edges: Edge[] = [];\n\n // Root node\n nodes.push({\n id: 'root',\n position: { x: 520, y: rootY },\n data: { label: makeRootLabel(componentName, componentType) },\n style: {\n backgroundColor: 'var(--color-action-primary-bg)',\n color: 'var(--color-action-primary-text)',\n borderRadius: 10,\n padding: '10px 16px',\n width: 160,\n fontWeight: 700,\n fontSize: 13,\n boxShadow: 'var(--shadow-elevation-2)',\n border: 'none',\n textAlign: 'center',\n },\n });\n\n // Dependency nodes and edges\n visible.forEach((dep, i) => {\n const depType = (dep.type ?? null) as DepType;\n const nodeId = `dep-${i}`;\n const isRuntime = !depType || depType === 'runtime';\n const isDev = depType === 'dev';\n\n nodes.push({\n id: nodeId,\n position: { x: 40, y: 20 + i * 80 },\n data: { label: makeDepLabel(dep) },\n style: {\n ...depNodeStyle(depType),\n borderRadius: 8,\n padding: '8px 12px',\n width: 220,\n fontSize: 12,\n },\n });\n\n edges.push({\n id: `edge-${i}`,\n source: nodeId,\n target: 'root',\n animated: isRuntime,\n markerEnd: { type: MarkerType.ArrowClosed },\n style: {\n stroke: 'var(--color-border-strong)',\n strokeWidth: 1.5,\n ...(isDev ? { strokeDasharray: '4 2' } : {}),\n },\n });\n });\n\n return { nodes, edges };\n}\n\n// ---------------------------------------------------------------------------\n// Inner React Flow component (needs its own hook calls — can't be conditional)\n// ---------------------------------------------------------------------------\n\ninterface DependencyFlowProps {\n componentName: string;\n componentType: string;\n deps: Array<{ name: string; version?: string | null; type?: string | null }>;\n canvasHeight: number;\n}\n\nfunction DependencyFlow({ componentName, componentType, deps, canvasHeight }: DependencyFlowProps) {\n const { nodes: initialNodes, edges: initialEdges } = useMemo(\n () => buildGraphElements(componentName, componentType, deps),\n [componentName, componentType, deps]\n );\n\n const [nodes, , onNodesChange] = useNodesState(initialNodes);\n const [edges, , onEdgesChange] = useEdgesState(initialEdges);\n\n return (\n <div\n className=\"w-full rounded-lg border border-border-default overflow-hidden bg-bg-surface\"\n style={{ height: canvasHeight }}\n >\n <ReactFlow\n nodes={nodes}\n edges={edges}\n onNodesChange={onNodesChange}\n onEdgesChange={onEdgesChange}\n nodesDraggable={false}\n fitView\n fitViewOptions={{ padding: 0.15 }}\n minZoom={0.2}\n maxZoom={2}\n panOnDrag\n proOptions={{ hideAttribution: true }}\n >\n <Background\n variant={BackgroundVariant.Dots}\n gap={20}\n size={1}\n className=\"!fill-text-tertiary/10\"\n />\n <Controls\n showInteractive={false}\n style={{\n background: 'var(--color-bg-primary)',\n border: '1px solid var(--color-border-default)',\n borderRadius: 8,\n boxShadow: '0 1px 4px var(--color-border-default)',\n }}\n className=\"[&_button]:!bg-[var(--color-bg-primary)] [&_button]:!border-[var(--color-border-default)] [&_button]:!fill-[var(--color-text-secondary)] [&_button:hover]:!bg-[var(--color-bg-sunken)]\"\n />\n </ReactFlow>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main export\n// ---------------------------------------------------------------------------\n\nexport function DependencyGraphTab({\n componentName,\n componentType,\n dependencies,\n}: DependencyGraphTabProps) {\n const deps = dependencies ?? [];\n const visibleCount = Math.min(deps.length, MAX_GRAPH_DEPS);\n const hiddenCount = deps.length - visibleCount;\n const canvasHeight = Math.max(400, Math.min(deps.length * 80 + 100, 600));\n\n if (deps.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center py-20 text-center gap-4\">\n <PackageOpen className=\"size-10 text-text-muted\" />\n <p className=\"text-sm text-text-secondary max-w-xs\">\n No dependencies recorded. Add them via Settings.\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6\">\n {/* Graph canvas */}\n <div>\n {hiddenCount > 0 && (\n <p className=\"text-xs text-text-muted mb-2 text-right\">\n Showing {visibleCount} of {deps.length} dependencies (+{hiddenCount} more in table\n below)\n </p>\n )}\n <DependencyFlow\n componentName={componentName}\n componentType={componentType}\n deps={deps}\n canvasHeight={canvasHeight}\n />\n </div>\n\n {/* All-dependencies table */}\n <div>\n <h3 className=\"text-sm font-semibold text-text-primary mb-3\">\n All Dependencies ({deps.length})\n </h3>\n <div className=\"overflow-x-auto rounded-lg border border-border-default\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"bg-bg-sunken border-b border-border-default\">\n <th className=\"px-4 py-2.5 text-left font-medium text-text-secondary\">Name</th>\n <th className=\"px-4 py-2.5 text-left font-medium text-text-secondary\">Version</th>\n <th className=\"px-4 py-2.5 text-left font-medium text-text-secondary\">Type</th>\n </tr>\n </thead>\n <tbody>\n {deps.map((dep, i) => (\n <tr\n key={`${dep.name}-${i}`}\n className=\"border-b border-border-default last:border-0 hover:bg-bg-sunken/50 transition-colors\"\n >\n <td className=\"px-4 py-2.5 font-mono text-xs text-text-primary\">{dep.name}</td>\n <td className=\"px-4 py-2.5 text-text-secondary\">{dep.version ?? '—'}</td>\n <td className=\"px-4 py-2.5\">\n {dep.type ? (\n <span className=\"inline-flex items-center px-2 py-0.5 text-xs font-medium rounded bg-bg-sunken text-text-secondary\">\n {dep.type}\n </span>\n ) : (\n <span className=\"text-text-muted\">runtime</span>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -13,10 +13,10 @@ var h = {
|
|
|
13
13
|
warn: "text-status-warning-text",
|
|
14
14
|
error: "text-status-error-text"
|
|
15
15
|
}, g = {
|
|
16
|
-
debug: "bg-bg-
|
|
17
|
-
info: "bg-status-info-bg
|
|
18
|
-
warn: "bg-status-warning-bg
|
|
19
|
-
error: "bg-status-error-bg
|
|
16
|
+
debug: "bg-bg-sunken",
|
|
17
|
+
info: "bg-status-info-bg-subtle",
|
|
18
|
+
warn: "bg-status-warning-bg-subtle",
|
|
19
|
+
error: "bg-status-error-bg-subtle"
|
|
20
20
|
}, _ = ({ agentId: _, profile: v, level: y = "info", source: b, maxEntries: x = 1e3, className: S = "", compact: C = !1 }) => {
|
|
21
21
|
let { t: w } = a(), [T, E] = i([]), [D, O] = i(!1), [k, A] = i(y), [j, M] = i(""), [N, P] = i(null), F = r(null), I = r(!0), { data: L, error: R, loading: z } = e({
|
|
22
22
|
variables: {
|
|
@@ -94,10 +94,10 @@ var h = {
|
|
|
94
94
|
}
|
|
95
95
|
};
|
|
96
96
|
return /* @__PURE__ */ p("div", {
|
|
97
|
-
className: `flex flex-col overflow-hidden rounded-lg border border-border-
|
|
97
|
+
className: `flex flex-col overflow-hidden rounded-lg border border-border-default bg-bg-elevated ${S}`,
|
|
98
98
|
children: [
|
|
99
99
|
/* @__PURE__ */ p("div", {
|
|
100
|
-
className: "flex flex-wrap items-center gap-2 border-b border-border-
|
|
100
|
+
className: "flex flex-wrap items-center gap-2 border-b border-border-default bg-bg-sunken px-3 py-2",
|
|
101
101
|
children: [
|
|
102
102
|
/* @__PURE__ */ p("div", {
|
|
103
103
|
className: "mr-2 flex items-center gap-1.5",
|
|
@@ -109,7 +109,7 @@ var h = {
|
|
|
109
109
|
/* @__PURE__ */ p("select", {
|
|
110
110
|
value: k,
|
|
111
111
|
onChange: (e) => A(e.target.value),
|
|
112
|
-
className: "rounded border border-border-
|
|
112
|
+
className: "rounded border border-border-subtle bg-bg-sunken px-2 py-1 text-xs text-text-primary",
|
|
113
113
|
"aria-label": B("logs.levelFilter", "Log level filter"),
|
|
114
114
|
children: [
|
|
115
115
|
/* @__PURE__ */ f("option", {
|
|
@@ -141,7 +141,7 @@ var h = {
|
|
|
141
141
|
placeholder: B("logs.filterLogs", "Filter logs..."),
|
|
142
142
|
value: j,
|
|
143
143
|
onChange: (e) => M(e.target.value),
|
|
144
|
-
className: "w-full rounded border border-border-
|
|
144
|
+
className: "w-full rounded border border-border-subtle bg-bg-sunken py-1 pl-6 pr-2 text-xs text-text-primary placeholder:text-text-tertiary"
|
|
145
145
|
})]
|
|
146
146
|
}),
|
|
147
147
|
/* @__PURE__ */ p("div", {
|
|
@@ -159,7 +159,7 @@ var h = {
|
|
|
159
159
|
type: "button",
|
|
160
160
|
onClick: () => void W(),
|
|
161
161
|
disabled: U,
|
|
162
|
-
className: "rounded p-1 text-text-tertiary transition-colors hover:bg-bg-
|
|
162
|
+
className: "rounded p-1 text-text-tertiary transition-colors hover:bg-bg-sunken disabled:opacity-50",
|
|
163
163
|
title: B("common.refresh", "Refresh"),
|
|
164
164
|
children: /* @__PURE__ */ f(l, {
|
|
165
165
|
size: 14,
|
|
@@ -169,21 +169,21 @@ var h = {
|
|
|
169
169
|
/* @__PURE__ */ f("button", {
|
|
170
170
|
type: "button",
|
|
171
171
|
onClick: () => O((e) => !e),
|
|
172
|
-
className: `rounded p-1 transition-colors hover:bg-bg-
|
|
172
|
+
className: `rounded p-1 transition-colors hover:bg-bg-sunken ${D ? "text-status-warning-text" : "text-text-tertiary"}`,
|
|
173
173
|
title: D ? B("logs.resume", "Resume") : B("logs.pause", "Pause"),
|
|
174
174
|
children: f(D ? c : s, { size: 14 })
|
|
175
175
|
}),
|
|
176
176
|
/* @__PURE__ */ f("button", {
|
|
177
177
|
type: "button",
|
|
178
178
|
onClick: K,
|
|
179
|
-
className: "rounded p-1 text-text-tertiary transition-colors hover:bg-bg-
|
|
179
|
+
className: "rounded p-1 text-text-tertiary transition-colors hover:bg-bg-sunken",
|
|
180
180
|
title: B("logs.clear", "Clear"),
|
|
181
181
|
children: /* @__PURE__ */ f(d, { size: 14 })
|
|
182
182
|
}),
|
|
183
183
|
/* @__PURE__ */ f("button", {
|
|
184
184
|
type: "button",
|
|
185
185
|
onClick: q,
|
|
186
|
-
className: "rounded p-1 text-text-tertiary transition-colors hover:bg-bg-
|
|
186
|
+
className: "rounded p-1 text-text-tertiary transition-colors hover:bg-bg-sunken",
|
|
187
187
|
title: B("logs.export", "Export"),
|
|
188
188
|
children: /* @__PURE__ */ f(o, { size: 14 })
|
|
189
189
|
})
|
|
@@ -193,7 +193,7 @@ var h = {
|
|
|
193
193
|
}),
|
|
194
194
|
N ? /* @__PURE__ */ f("div", {
|
|
195
195
|
role: "alert",
|
|
196
|
-
className: "border-b border-border-
|
|
196
|
+
className: "border-b border-border-default bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text",
|
|
197
197
|
children: N
|
|
198
198
|
}) : null,
|
|
199
199
|
/* @__PURE__ */ f("div", {
|
|
@@ -205,7 +205,7 @@ var h = {
|
|
|
205
205
|
className: "flex h-full min-h-[200px] items-center justify-center text-text-tertiary",
|
|
206
206
|
children: _ ? N ? `${B("logs.subscriptionError", "Log stream error")}: ${N}` : z ? B("logs.connecting", "Connecting to log stream…") : B("logs.waitingForEntries", "Waiting for log entries…") : B("logs.connectToAgent", "Connect to an agent to view logs")
|
|
207
207
|
}) : G.map((e, t) => /* @__PURE__ */ p("div", {
|
|
208
|
-
className: `flex gap-2 border-b border-border-
|
|
208
|
+
className: `flex gap-2 border-b border-border-default/30 px-3 py-0.5 hover:bg-bg-sunken ${g[e.level] ?? ""}`,
|
|
209
209
|
children: [
|
|
210
210
|
/* @__PURE__ */ f("span", {
|
|
211
211
|
className: "w-[85px] shrink-0 text-text-tertiary",
|