@burdenoff/microfe-adaptercloud 2026.802.1 → 2026.802.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.
@@ -1 +1 @@
1
- {"version":3,"file":"OverviewPage.js","names":[],"sources":["../../../src/adaptercloud/pages/OverviewPage.tsx"],"sourcesContent":["/**\n * Overview / Dashboard Page\n * @module adaptercloud/pages\n *\n * The AdapterCloud landing page: a single-pane view of the estate — fabric\n * counts (adapters, connections, resources), governance posture (open\n * violations, unremediated drift), operations (recent sync runs) and FinOps\n * (workspace cost summary by service). All data is live from the deployed\n * `wspace-adaptercloud-svc` subgraph.\n */\n\nimport { useMemo, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Boxes,\n Cable,\n Server,\n ShieldAlert,\n GitCompareArrows,\n RefreshCw,\n DollarSign,\n ArrowRight,\n Activity,\n AlertCircle,\n Plug,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { SeverityBadge } from '../components/SeverityBadge';\nimport { DataState } from '../components/DataState';\nimport { useAdapterCloud } from '../context/AdapterCloudContext';\nimport {\n useAdapters,\n useConnections,\n useResources,\n useViolations,\n useDriftRecords,\n useSyncRuns,\n useCostSummary,\n} from '../hooks/useAdapterCloudApi';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { formatMoney, severityRank, syncKindLabels } from '../utils/domain';\nimport type { AdaPageInfo, AdaSeverity } from '../types';\n\n/**\n * Estate count for a tile: prefer the estate-wide `pageInfo.totalCount`, fall\n * back to the loaded page length when the field is absent (null/undefined), and\n * render an em dash before the first page has loaded.\n */\nfunction countLabel(page: { items: unknown[]; pageInfo: AdaPageInfo } | undefined): string {\n if (!page) return '—';\n return String(page.pageInfo.totalCount ?? page.items.length);\n}\n\nexport function OverviewPage() {\n const { navigateTo, currentUser } = useAdapterCloud();\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n // Estate count tiles prefer the estate-wide `pageInfo.totalCount` (svc-added)\n // and fall back to the loaded page length when it is absent, so the request\n // limit still bounds the fallback (limit:1 would cap the fallback at 1).\n const adapters = useAdapters({ pagination: { limit: 100 } });\n const connections = useConnections({ pagination: { limit: 100 } });\n const resources = useResources({ pagination: { limit: 100 } });\n const openViolations = useViolations({ status: 'OPEN', pagination: { limit: 50 } });\n const drift = useDriftRecords({ status: 'DETECTED' });\n const syncRuns = useSyncRuns({ pagination: { limit: 5 } });\n const costSummary = useCostSummary();\n\n const firstName = currentUser?.firstName ?? currentUser?.name ?? 'there';\n\n // Connection health breakdown\n const connectionHealth = useMemo(() => {\n const items = connections.data?.items ?? [];\n const counts = { CONNECTED: 0, DEGRADED: 0, ERROR: 0, PENDING: 0, DISABLED: 0 };\n for (const c of items) counts[c.status] += 1;\n return counts;\n }, [connections.data]);\n\n const topViolations = useMemo(() => {\n return [...(openViolations.data?.items ?? [])]\n .sort((a, b) => severityRank[b.severity] - severityRank[a.severity])\n .slice(0, 5);\n }, [openViolations.data]);\n\n const recentRuns = syncRuns.data?.items ?? [];\n\n const topCostLines = useMemo(() => {\n return [...(costSummary.data?.lines ?? [])].sort((a, b) => b.total - a.total).slice(0, 6);\n }, [costSummary.data]);\n\n const isLoading =\n adapters.isLoading ||\n connections.isLoading ||\n resources.isLoading ||\n openViolations.isLoading ||\n drift.isLoading ||\n costSummary.isLoading;\n\n const isError =\n adapters.isError ||\n connections.isError ||\n resources.isError ||\n openViolations.isError ||\n drift.isError ||\n costSummary.isError;\n\n const refetchAll = useCallback(() => {\n void adapters.refetch();\n void connections.refetch();\n void resources.refetch();\n void openViolations.refetch();\n void drift.refetch();\n void syncRuns.refetch();\n void costSummary.refetch();\n }, [adapters, connections, resources, openViolations, drift, syncRuns, costSummary]);\n\n const stats = [\n {\n icon: <Boxes className=\"h-5 w-5\" />,\n value: countLabel(adapters.data),\n label: t('adaptercloud.overview.adapters', 'Adapters'),\n onClick: () => navigateTo('/adapters'),\n },\n {\n icon: <Cable className=\"h-5 w-5\" />,\n value: countLabel(connections.data),\n label: t('adaptercloud.overview.connections', 'Connections'),\n onClick: () => navigateTo('/connections'),\n },\n {\n icon: <Server className=\"h-5 w-5\" />,\n value: countLabel(resources.data),\n label: t('adaptercloud.overview.resources', 'Resources'),\n onClick: () => navigateTo('/resources'),\n },\n {\n icon: <ShieldAlert className=\"h-5 w-5\" />,\n value: countLabel(openViolations.data),\n label: t('adaptercloud.overview.openViolations', 'Open Violations'),\n onClick: () => navigateTo('/violations'),\n },\n ];\n\n return (\n <PageLayout\n title={`${t('adaptercloud.overview.hello', 'Welcome back')}, ${firstName}`}\n description={t(\n 'adaptercloud.overview.subtitle',\n 'Your infrastructure continuum at a glance — fabric, governance, operations and cost.'\n )}\n actions={\n <button\n type=\"button\"\n onClick={refetchAll}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n <RefreshCw className=\"h-4 w-4\" />\n {t('adaptercloud.common.refresh', 'Refresh')}\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n {t(\n 'adaptercloud.overview.purpose',\n 'AdapterCloud connects your fragmented infrastructure — multi-cloud, on-prem, edge and SaaS — into one governable fabric. This overview is your control plane: see what you run, how connected it is, what is out of policy, and what it costs.'\n )}\n </PagePurpose>\n\n <DataState\n isLoading={isLoading}\n isError={isError}\n error={adapters.error}\n onRetry={refetchAll}\n >\n {/* Top metrics — the one emphasis zone */}\n <EmphasisPanel className=\"mb-8\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.estate', 'Estate Summary')}\n </h2>\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n {stats.map((stat) => (\n <button key={stat.label} type=\"button\" onClick={stat.onClick} className=\"text-left\">\n <MetricsCard icon={stat.icon} value={stat.value} label={stat.label} />\n </button>\n ))}\n </div>\n </EmphasisPanel>\n\n {/* Connection health + Cost summary */}\n <div className=\"mb-8 grid grid-cols-1 gap-6 lg:grid-cols-2\">\n {/* Connection health */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.connectionHealth', 'Connection Health')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\n className=\"flex items-center gap-1 text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.common.viewAll', 'View all')}{' '}\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <GlassCard className=\"p-5\">\n {connections.data && connections.data.items.length > 0 ? (\n <ul className=\"space-y-3\">\n {(\n [\n ['CONNECTED', connectionHealth.CONNECTED],\n ['DEGRADED', connectionHealth.DEGRADED],\n ['ERROR', connectionHealth.ERROR],\n ['PENDING', connectionHealth.PENDING],\n ['DISABLED', connectionHealth.DISABLED],\n ] as const\n ).map(([status, count]) => (\n <li key={status} className=\"flex items-center justify-between\">\n <StatusBadge status={status} />\n <span className=\"text-sm font-semibold tabular-nums text-text-primary\">\n {count}\n </span>\n </li>\n ))}\n </ul>\n ) : (\n <div className=\"flex flex-col items-center gap-3 py-6 text-center\">\n <Plug className=\"h-8 w-8 text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'adaptercloud.overview.noConnections',\n 'No connections yet. Connect a target to start discovering resources.'\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n {t('adaptercloud.overview.addConnection', 'Add connection')}\n </button>\n </div>\n )}\n </GlassCard>\n </section>\n\n {/* Cost summary */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.costByService', 'Cost by Service')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/costs')}\n className=\"flex items-center gap-1 text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.overview.finops', 'FinOps')} <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <GlassCard className=\"p-5\">\n <div className=\"mb-4 flex items-baseline gap-2\">\n <DollarSign className=\"h-5 w-5 text-text-secondary\" />\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">\n {costSummary.data\n ? formatMoney(costSummary.data.total, costSummary.data.currency)\n : '—'}\n </span>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.overview.totalSpend', 'total spend')}\n </span>\n </div>\n {topCostLines.length > 0 ? (\n <ul className=\"space-y-2\">\n {topCostLines.map((line) => (\n <li key={line.service} className=\"flex items-center justify-between text-sm\">\n <span className=\"truncate text-text-primary\">{line.service}</span>\n <span className=\"tabular-nums text-text-secondary\">\n {formatMoney(line.total, costSummary.data?.currency ?? 'USD')}\n </span>\n </li>\n ))}\n </ul>\n ) : (\n <p className=\"py-4 text-center text-sm text-text-secondary\">\n {t(\n 'adaptercloud.overview.noCost',\n 'No cost records ingested yet. Run a cost-ingest sync to populate FinOps.'\n )}\n </p>\n )}\n </GlassCard>\n </section>\n </div>\n\n {/* Governance + Operations */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n {/* Top open violations */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.priorityViolations', 'Priority Violations')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/violations')}\n className=\"flex items-center gap-1 text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.overview.queue', 'Queue')} <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {topViolations.length > 0 ? (\n topViolations.map((v) => (\n <button\n key={v.id}\n type=\"button\"\n onClick={() => navigateTo('/violations')}\n className=\"flex w-full items-start gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50\"\n >\n <AlertCircle className=\"mt-0.5 h-4 w-4 shrink-0 text-status-error-text\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{v.message}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {v.policy?.name ?? t('adaptercloud.overview.policy', 'Policy')} ·{' '}\n {formatRelativeTime(v.detectedAt)}\n </p>\n </div>\n <SeverityBadge severity={v.severity as AdaSeverity} />\n </button>\n ))\n ) : (\n <div className=\"flex flex-col items-center gap-2 px-4 py-8 text-center\">\n <ShieldAlert className=\"h-8 w-8 text-status-success-text\" />\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'adaptercloud.overview.noViolations',\n 'No open violations. Estate is clean.'\n )}\n </p>\n </div>\n )}\n </div>\n {drift.data && drift.data.length > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/drift')}\n className=\"mt-3 flex w-full items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-4 py-3 text-left text-sm transition-colors hover:bg-accent/50\"\n >\n <GitCompareArrows className=\"h-4 w-4 text-status-warning-text\" />\n <span className=\"text-text-primary\">\n {drift.data.length}{' '}\n {t('adaptercloud.overview.driftDetected', 'drift records detected')}\n </span>\n <ArrowRight className=\"ml-auto h-3.5 w-3.5 text-text-secondary\" />\n </button>\n )}\n </section>\n\n {/* Recent sync runs */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.recentRuns', 'Recent Sync Runs')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/sync-runs')}\n className=\"flex items-center gap-1 text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.common.viewAll', 'View all')}{' '}\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {recentRuns.length > 0 ? (\n recentRuns.map((run) => (\n <button\n key={run.id}\n type=\"button\"\n onClick={() => navigateTo('/sync-runs')}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50\"\n >\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken\">\n <Activity className=\"h-4 w-4 text-text-secondary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {syncKindLabels[run.kind]}\n </p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {run.discoveredCount} {t('adaptercloud.overview.discovered', 'discovered')}{' '}\n · {formatRelativeTime(run.createdAt)}\n </p>\n </div>\n <StatusBadge status={run.status} />\n </button>\n ))\n ) : (\n <div className=\"flex flex-col items-center gap-2 px-4 py-8 text-center\">\n <RefreshCw className=\"h-8 w-8 text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">\n {t('adaptercloud.overview.noRuns', 'No sync runs yet.')}\n </p>\n </div>\n )}\n </div>\n </section>\n </div>\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OverviewPage.js","names":[],"sources":["../../../src/adaptercloud/pages/OverviewPage.tsx"],"sourcesContent":["/**\n * Overview / Dashboard Page\n * @module adaptercloud/pages\n *\n * The AdapterCloud landing page: a single-pane view of the estate — fabric\n * counts (adapters, connections, resources), governance posture (open\n * violations, unremediated drift), operations (recent sync runs) and FinOps\n * (workspace cost summary by service). All data is live from the deployed\n * `wspace-adaptercloud-svc` subgraph.\n */\n\nimport { useMemo, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Boxes,\n Cable,\n Server,\n ShieldAlert,\n GitCompareArrows,\n RefreshCw,\n DollarSign,\n ArrowRight,\n Activity,\n AlertCircle,\n Plug,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { MetricsCard } from '../components/MetricsCard';\nimport { StatusBadge } from '../components/StatusBadge';\nimport { SeverityBadge } from '../components/SeverityBadge';\nimport { DataState } from '../components/DataState';\nimport { StackedBar, BarChart, type BarDatum, type StackedSegment } from '../components/viz';\nimport { useAdapterCloud } from '../context/AdapterCloudContext';\nimport {\n useAdapters,\n useConnections,\n useResources,\n useViolations,\n useDriftRecords,\n useSyncRuns,\n useCostSummary,\n} from '../hooks/useAdapterCloudApi';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { formatMoney, severityRank, syncKindLabels } from '../utils/domain';\nimport type { AdaPageInfo, AdaSeverity } from '../types';\n\n/**\n * Estate count for a tile: prefer the estate-wide `pageInfo.totalCount`, fall\n * back to the loaded page length when the field is absent (null/undefined), and\n * render an em dash before the first page has loaded.\n */\nfunction countLabel(page: { items: unknown[]; pageInfo: AdaPageInfo } | undefined): string {\n if (!page) return '—';\n return String(page.pageInfo.totalCount ?? page.items.length);\n}\n\nexport function OverviewPage() {\n const { navigateTo, currentUser } = useAdapterCloud();\n const { t: translate } = useI18n();\n const t = useCallback(\n (key: string, fallback: string): string => {\n const value = translate(key);\n return value === key ? fallback : value;\n },\n [translate]\n );\n\n // Estate count tiles prefer the estate-wide `pageInfo.totalCount` (svc-added)\n // and fall back to the loaded page length when it is absent, so the request\n // limit still bounds the fallback (limit:1 would cap the fallback at 1).\n const adapters = useAdapters({ pagination: { limit: 100 } });\n const connections = useConnections({ pagination: { limit: 100 } });\n const resources = useResources({ pagination: { limit: 100 } });\n const openViolations = useViolations({ status: 'OPEN', pagination: { limit: 50 } });\n const drift = useDriftRecords({ status: 'DETECTED' });\n const syncRuns = useSyncRuns({ pagination: { limit: 5 } });\n const costSummary = useCostSummary();\n\n const firstName = currentUser?.firstName ?? currentUser?.name ?? 'there';\n\n // Connection health breakdown\n const connectionHealth = useMemo(() => {\n const items = connections.data?.items ?? [];\n const counts = { CONNECTED: 0, DEGRADED: 0, ERROR: 0, PENDING: 0, DISABLED: 0 };\n for (const c of items) counts[c.status] += 1;\n return counts;\n }, [connections.data]);\n\n const connectionHealthSegments: StackedSegment[] = useMemo(\n () => [\n {\n key: 'CONNECTED',\n label: 'Connected',\n value: connectionHealth.CONNECTED,\n className: 'bg-status-success-text',\n },\n {\n key: 'DEGRADED',\n label: 'Degraded',\n value: connectionHealth.DEGRADED,\n className: 'bg-status-warning-text',\n },\n {\n key: 'ERROR',\n label: 'Error',\n value: connectionHealth.ERROR,\n className: 'bg-status-error-text',\n },\n {\n key: 'PENDING',\n label: 'Pending',\n value: connectionHealth.PENDING,\n className: 'bg-accent-blue',\n },\n {\n key: 'DISABLED',\n label: 'Disabled',\n value: connectionHealth.DISABLED,\n className: 'bg-text-secondary',\n },\n ],\n [connectionHealth]\n );\n\n const topViolations = useMemo(() => {\n return [...(openViolations.data?.items ?? [])]\n .sort((a, b) => severityRank[b.severity] - severityRank[a.severity])\n .slice(0, 5);\n }, [openViolations.data]);\n\n const recentRuns = syncRuns.data?.items ?? [];\n\n const topCostLines = useMemo(() => {\n return [...(costSummary.data?.lines ?? [])].sort((a, b) => b.total - a.total).slice(0, 6);\n }, [costSummary.data]);\n\n const costBarData: BarDatum[] = useMemo(\n () =>\n topCostLines.map((line) => ({\n key: line.service,\n label: line.service,\n value: line.total,\n display: formatMoney(line.total, costSummary.data?.currency ?? 'USD'),\n })),\n [topCostLines, costSummary.data?.currency]\n );\n\n const isLoading =\n adapters.isLoading ||\n connections.isLoading ||\n resources.isLoading ||\n openViolations.isLoading ||\n drift.isLoading ||\n costSummary.isLoading;\n\n const isError =\n adapters.isError ||\n connections.isError ||\n resources.isError ||\n openViolations.isError ||\n drift.isError ||\n costSummary.isError;\n\n const refetchAll = useCallback(() => {\n void adapters.refetch();\n void connections.refetch();\n void resources.refetch();\n void openViolations.refetch();\n void drift.refetch();\n void syncRuns.refetch();\n void costSummary.refetch();\n }, [adapters, connections, resources, openViolations, drift, syncRuns, costSummary]);\n\n const stats = [\n {\n icon: <Boxes className=\"h-5 w-5\" />,\n value: countLabel(adapters.data),\n label: t('adaptercloud.overview.adapters', 'Adapters'),\n onClick: () => navigateTo('/adapters'),\n },\n {\n icon: <Cable className=\"h-5 w-5\" />,\n value: countLabel(connections.data),\n label: t('adaptercloud.overview.connections', 'Connections'),\n onClick: () => navigateTo('/connections'),\n },\n {\n icon: <Server className=\"h-5 w-5\" />,\n value: countLabel(resources.data),\n label: t('adaptercloud.overview.resources', 'Resources'),\n onClick: () => navigateTo('/resources'),\n },\n {\n icon: <ShieldAlert className=\"h-5 w-5\" />,\n value: countLabel(openViolations.data),\n label: t('adaptercloud.overview.openViolations', 'Open Violations'),\n onClick: () => navigateTo('/violations'),\n },\n ];\n\n return (\n <PageLayout\n title={`${t('adaptercloud.overview.hello', 'Welcome back')}, ${firstName}`}\n description={t(\n 'adaptercloud.overview.subtitle',\n 'Your infrastructure continuum at a glance — fabric, governance, operations and cost.'\n )}\n actions={\n <button\n type=\"button\"\n onClick={refetchAll}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n <RefreshCw className=\"h-4 w-4\" />\n {t('adaptercloud.common.refresh', 'Refresh')}\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n {t(\n 'adaptercloud.overview.purpose',\n 'AdapterCloud connects your fragmented infrastructure — multi-cloud, on-prem, edge and SaaS — into one governable fabric. This overview is your control plane: see what you run, how connected it is, what is out of policy, and what it costs.'\n )}\n </PagePurpose>\n\n <DataState\n isLoading={isLoading}\n isError={isError}\n error={adapters.error}\n onRetry={refetchAll}\n >\n {/* Top metrics — the one emphasis zone */}\n <EmphasisPanel className=\"mb-8\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.estate', 'Estate Summary')}\n </h2>\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n {stats.map((stat) => (\n <button key={stat.label} type=\"button\" onClick={stat.onClick} className=\"text-left\">\n <MetricsCard icon={stat.icon} value={stat.value} label={stat.label} />\n </button>\n ))}\n </div>\n </EmphasisPanel>\n\n {/* Connection health + Cost summary */}\n <div className=\"mb-8 grid grid-cols-1 gap-6 lg:grid-cols-2\">\n {/* Connection health */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.connectionHealth', 'Connection Health')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\n className=\"flex items-center gap-1 text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.common.viewAll', 'View all')}{' '}\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <GlassCard className=\"p-5\">\n {connections.data && connections.data.items.length > 0 ? (\n <StackedBar segments={connectionHealthSegments} />\n ) : (\n <div className=\"flex flex-col items-center gap-3 py-6 text-center\">\n <Plug className=\"h-8 w-8 text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'adaptercloud.overview.noConnections',\n 'No connections yet. Connect a target to start discovering resources.'\n )}\n </p>\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n {t('adaptercloud.overview.addConnection', 'Add connection')}\n </button>\n </div>\n )}\n </GlassCard>\n </section>\n\n {/* Cost summary */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.costByService', 'Cost by Service')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/costs')}\n className=\"flex items-center gap-1 text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.overview.finops', 'FinOps')} <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <GlassCard className=\"p-5\">\n <div className=\"mb-4 flex items-baseline gap-2\">\n <DollarSign className=\"h-5 w-5 text-text-secondary\" />\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">\n {costSummary.data\n ? formatMoney(costSummary.data.total, costSummary.data.currency)\n : '—'}\n </span>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.overview.totalSpend', 'total spend')}\n </span>\n </div>\n {costBarData.length > 0 ? (\n <BarChart data={costBarData} labelWidthClassName=\"w-24 sm:w-32\" />\n ) : (\n <p className=\"py-4 text-center text-sm text-text-secondary\">\n {t(\n 'adaptercloud.overview.noCost',\n 'No cost records ingested yet. Run a cost-ingest sync to populate FinOps.'\n )}\n </p>\n )}\n </GlassCard>\n </section>\n </div>\n\n {/* Governance + Operations */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n {/* Top open violations */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.priorityViolations', 'Priority Violations')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/violations')}\n className=\"flex items-center gap-1 text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.overview.queue', 'Queue')} <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {topViolations.length > 0 ? (\n topViolations.map((v) => (\n <button\n key={v.id}\n type=\"button\"\n onClick={() => navigateTo('/violations')}\n className=\"flex w-full items-start gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50\"\n >\n <AlertCircle className=\"mt-0.5 h-4 w-4 shrink-0 text-status-error-text\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{v.message}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {v.policy?.name ?? t('adaptercloud.overview.policy', 'Policy')} ·{' '}\n {formatRelativeTime(v.detectedAt)}\n </p>\n </div>\n <SeverityBadge severity={v.severity as AdaSeverity} />\n </button>\n ))\n ) : (\n <div className=\"flex flex-col items-center gap-2 px-4 py-8 text-center\">\n <ShieldAlert className=\"h-8 w-8 text-status-success-text\" />\n <p className=\"text-sm text-text-secondary\">\n {t(\n 'adaptercloud.overview.noViolations',\n 'No open violations. Estate is clean.'\n )}\n </p>\n </div>\n )}\n </div>\n {drift.data && drift.data.length > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/drift')}\n className=\"mt-3 flex w-full items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-4 py-3 text-left text-sm transition-colors hover:bg-accent/50\"\n >\n <GitCompareArrows className=\"h-4 w-4 text-status-warning-text\" />\n <span className=\"text-text-primary\">\n {drift.data.length}{' '}\n {t('adaptercloud.overview.driftDetected', 'drift records detected')}\n </span>\n <ArrowRight className=\"ml-auto h-3.5 w-3.5 text-text-secondary\" />\n </button>\n )}\n </section>\n\n {/* Recent sync runs */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('adaptercloud.overview.recentRuns', 'Recent Sync Runs')}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/sync-runs')}\n className=\"flex items-center gap-1 text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.common.viewAll', 'View all')}{' '}\n <ArrowRight className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {recentRuns.length > 0 ? (\n recentRuns.map((run) => (\n <button\n key={run.id}\n type=\"button\"\n onClick={() => navigateTo('/sync-runs')}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50\"\n >\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-bg-sunken\">\n <Activity className=\"h-4 w-4 text-text-secondary\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium text-text-primary\">\n {syncKindLabels[run.kind]}\n </p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {run.discoveredCount} {t('adaptercloud.overview.discovered', 'discovered')}{' '}\n · {formatRelativeTime(run.createdAt)}\n </p>\n </div>\n <StatusBadge status={run.status} />\n </button>\n ))\n ) : (\n <div className=\"flex flex-col items-center gap-2 px-4 py-8 text-center\">\n <RefreshCw className=\"h-8 w-8 text-text-secondary\" />\n <p className=\"text-sm text-text-secondary\">\n {t('adaptercloud.overview.noRuns', 'No sync runs yet.')}\n </p>\n </div>\n )}\n </div>\n </section>\n </div>\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/connections/ConnectionDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+BH,wBAAgB,oBAAoB,gCAoSnC"}
1
+ {"version":3,"file":"ConnectionDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/adaptercloud/pages/connections/ConnectionDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgCH,wBAAgB,oBAAoB,gCA+SnC"}
@@ -8,257 +8,254 @@ import { formatDate as p } from "../../utils/formatters.js";
8
8
  import { ConfirmDialog as m } from "../../components/ConfirmDialog.js";
9
9
  import { useCallback as h, useState as g } from "react";
10
10
  import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
11
- import { ArrowLeft as v, Ban as y, Pencil as b, Play as x, RefreshCw as S, Server as C } from "lucide-react";
12
- import { useParams as w } from "react-router";
13
- import { jsx as T, jsxs as E } from "react/jsx-runtime";
14
- import { GlassCard as D } from "@burdenoff/fe-libs/ui";
11
+ import { ArrowLeft as v, Ban as y, Loader2 as b, Pencil as x, Play as S, RefreshCw as C, Server as w } from "lucide-react";
12
+ import { useParams as T } from "react-router";
13
+ import { jsx as E, jsxs as D } from "react/jsx-runtime";
14
+ import { GlassCard as O } from "@burdenoff/fe-libs/ui";
15
15
  //#region src/adaptercloud/pages/connections/ConnectionDetailPage.tsx
16
- var O = [
16
+ var k = [
17
17
  "CONNECTED",
18
18
  "DEGRADED",
19
19
  "ERROR",
20
20
  "PENDING"
21
- ], k = [
21
+ ], A = [
22
22
  "DISCOVERY",
23
23
  "RECONCILE",
24
24
  "COST_INGEST",
25
25
  "FULL"
26
26
  ];
27
- function A() {
28
- let { id: A } = w(), { navigateTo: j } = e(), { t: M } = _(), N = h((e, t) => {
29
- let n = M(e);
27
+ function j() {
28
+ let { id: j } = T(), { navigateTo: M } = e(), { t: N } = _(), P = h((e, t) => {
29
+ let n = N(e);
30
30
  return n === e ? t : n;
31
- }, [M]), P = l(A), F = d(), I = u(), L = f(), R = P.data, [z, B] = g("DISCOVERY"), [V, H] = g(null), [U, W] = g(!1), G = h((e) => H(e instanceof Error ? e.message : "Action failed. Please try again."), []), K = h((e) => {
32
- A && (H(null), F.mutate({
33
- id: A,
31
+ }, [N]), F = l(j), I = d(), L = u(), R = f(), z = F.data, [B, V] = g(null), [H, U] = g(null), [W, G] = g(!1), K = h((e) => U(e instanceof Error ? e.message : "Action failed. Please try again."), []), q = h((e) => {
32
+ j && (U(null), I.mutate({
33
+ id: j,
34
34
  status: e
35
- }, { onError: G }));
35
+ }, { onError: K }));
36
36
  }, [
37
- A,
38
- F,
39
- G
40
- ]), q = h(() => {
41
- A && (H(null), I.mutate(A, {
42
- onSuccess: () => W(!1),
43
- onError: G
44
- }));
45
- }, [
46
- A,
37
+ j,
47
38
  I,
48
- G
39
+ K
49
40
  ]), J = h(() => {
50
- A && (H(null), L.mutate({
51
- connectionId: A,
52
- kind: z
53
- }, {
54
- onSuccess: () => j("/sync-runs"),
55
- onError: G
41
+ j && (U(null), L.mutate(j, {
42
+ onSuccess: () => G(!1),
43
+ onError: K
56
44
  }));
57
45
  }, [
58
- A,
59
- z,
46
+ j,
60
47
  L,
48
+ K
49
+ ]), Y = h((e) => {
50
+ j && (U(null), V(e), R.mutate({
51
+ connectionId: j,
52
+ kind: e
53
+ }, {
54
+ onSuccess: () => {
55
+ V(null), M("/sync-runs");
56
+ },
57
+ onError: (e) => {
58
+ V(null), K(e);
59
+ }
60
+ }));
61
+ }, [
61
62
  j,
62
- G
63
+ R,
64
+ M,
65
+ K
63
66
  ]);
64
- return /* @__PURE__ */ E(t, {
65
- title: R?.name ?? N("adaptercloud.connections.detailTitle", "Connection"),
66
- description: R?.adapter?.name,
67
- actions: /* @__PURE__ */ E("div", {
67
+ return /* @__PURE__ */ D(t, {
68
+ title: z?.name ?? P("adaptercloud.connections.detailTitle", "Connection"),
69
+ description: z?.adapter?.name,
70
+ actions: /* @__PURE__ */ D("div", {
68
71
  className: "flex items-center gap-2",
69
- children: [/* @__PURE__ */ E("button", {
72
+ children: [/* @__PURE__ */ D("button", {
70
73
  type: "button",
71
- onClick: () => j("/connections"),
74
+ onClick: () => M("/connections"),
72
75
  className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent",
73
- children: [/* @__PURE__ */ T(v, { className: "h-4 w-4" }), N("adaptercloud.common.back", "Back")]
74
- }), R && /* @__PURE__ */ E("button", {
76
+ children: [/* @__PURE__ */ E(v, { className: "h-4 w-4" }), P("adaptercloud.common.back", "Back")]
77
+ }), z && /* @__PURE__ */ D("button", {
75
78
  type: "button",
76
- onClick: () => j(`/connections/${R.id}/edit`),
79
+ onClick: () => M(`/connections/${z.id}/edit`),
77
80
  className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent",
78
- children: [/* @__PURE__ */ T(b, { className: "h-4 w-4" }), N("adaptercloud.common.edit", "Edit")]
81
+ children: [/* @__PURE__ */ E(x, { className: "h-4 w-4" }), P("adaptercloud.common.edit", "Edit")]
79
82
  })]
80
83
  }),
81
- children: [/* @__PURE__ */ T(c, {
82
- isLoading: P.isLoading,
83
- isError: P.isError,
84
- isEmpty: !P.isLoading && !R,
85
- error: P.error,
86
- onRetry: () => void P.refetch(),
87
- emptyTitle: N("adaptercloud.connections.notFound", "Connection not found"),
88
- children: R && /* @__PURE__ */ E("div", {
84
+ children: [/* @__PURE__ */ E(c, {
85
+ isLoading: F.isLoading,
86
+ isError: F.isError,
87
+ isEmpty: !F.isLoading && !z,
88
+ error: F.error,
89
+ onRetry: () => void F.refetch(),
90
+ emptyTitle: P("adaptercloud.connections.notFound", "Connection not found"),
91
+ children: z && /* @__PURE__ */ D("div", {
89
92
  className: "space-y-6",
90
93
  children: [
91
- V && /* @__PURE__ */ T("p", {
94
+ H && /* @__PURE__ */ E("p", {
92
95
  role: "alert",
93
96
  "aria-live": "polite",
94
97
  className: "rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
95
- children: V
98
+ children: H
96
99
  }),
97
- /* @__PURE__ */ E(D, {
100
+ /* @__PURE__ */ D(O, {
98
101
  className: "p-6",
99
102
  children: [
100
- /* @__PURE__ */ E("div", {
103
+ /* @__PURE__ */ D("div", {
101
104
  className: "mb-4 flex flex-wrap items-center gap-3",
102
- children: [/* @__PURE__ */ T(s, { status: R.status }), /* @__PURE__ */ T("span", {
105
+ children: [/* @__PURE__ */ E(s, { status: z.status }), /* @__PURE__ */ E("span", {
103
106
  className: "inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary",
104
- children: n[R.authMethod]
107
+ children: n[z.authMethod]
105
108
  })]
106
109
  }),
107
- /* @__PURE__ */ E("dl", {
110
+ /* @__PURE__ */ D("dl", {
108
111
  className: "grid grid-cols-2 gap-4 text-sm sm:grid-cols-4",
109
112
  children: [
110
- /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
113
+ /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("dt", {
111
114
  className: "text-text-secondary",
112
- children: N("adaptercloud.connections.region", "Region")
113
- }), /* @__PURE__ */ T("dd", {
115
+ children: P("adaptercloud.connections.region", "Region")
116
+ }), /* @__PURE__ */ E("dd", {
114
117
  className: "mt-0.5 font-medium text-text-primary",
115
- children: R.region ?? "—"
118
+ children: z.region ?? "—"
116
119
  })] }),
117
- /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
120
+ /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("dt", {
118
121
  className: "text-text-secondary",
119
- children: N("adaptercloud.connections.environment", "Environment")
120
- }), /* @__PURE__ */ T("dd", {
122
+ children: P("adaptercloud.connections.environment", "Environment")
123
+ }), /* @__PURE__ */ E("dd", {
121
124
  className: "mt-0.5 font-medium text-text-primary",
122
- children: R.environment ?? "—"
125
+ children: z.environment ?? "—"
123
126
  })] }),
124
- /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
127
+ /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("dt", {
125
128
  className: "text-text-secondary",
126
- children: N("adaptercloud.connections.resourceCount", "Resources")
127
- }), /* @__PURE__ */ T("dd", {
129
+ children: P("adaptercloud.connections.resourceCount", "Resources")
130
+ }), /* @__PURE__ */ E("dd", {
128
131
  className: "mt-0.5 font-medium tabular-nums text-text-primary",
129
- children: R.resourceCount
132
+ children: z.resourceCount
130
133
  })] }),
131
- /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
134
+ /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("dt", {
132
135
  className: "text-text-secondary",
133
- children: N("adaptercloud.connections.lastSynced", "Last synced")
134
- }), /* @__PURE__ */ T("dd", {
136
+ children: P("adaptercloud.connections.lastSynced", "Last synced")
137
+ }), /* @__PURE__ */ E("dd", {
135
138
  className: "mt-0.5 font-medium text-text-primary",
136
- children: R.lastSyncedAt ? p(R.lastSyncedAt) : "—"
139
+ children: z.lastSyncedAt ? p(z.lastSyncedAt) : "—"
137
140
  })] })
138
141
  ]
139
142
  }),
140
- R.lastError && /* @__PURE__ */ T("p", {
143
+ z.lastError && /* @__PURE__ */ E("p", {
141
144
  className: "mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
142
- children: R.lastError
145
+ children: z.lastError
143
146
  }),
144
- /* @__PURE__ */ E("div", {
147
+ /* @__PURE__ */ D("div", {
145
148
  className: "mt-5 border-t border-border-subtle pt-5",
146
- children: [/* @__PURE__ */ T("h3", {
149
+ children: [/* @__PURE__ */ E("h3", {
147
150
  className: "mb-3 text-sm font-semibold text-text-primary",
148
- children: N("adaptercloud.connections.setHealth", "Set health")
149
- }), /* @__PURE__ */ E("div", {
151
+ children: P("adaptercloud.connections.setHealth", "Set health")
152
+ }), /* @__PURE__ */ D("div", {
150
153
  className: "flex flex-wrap gap-2",
151
- children: [O.map((e) => /* @__PURE__ */ T("button", {
154
+ children: [k.map((e) => /* @__PURE__ */ E("button", {
152
155
  type: "button",
153
- disabled: F.isPending || R.status === e,
154
- onClick: () => K(e),
156
+ disabled: I.isPending || z.status === e,
157
+ onClick: () => q(e),
155
158
  className: "rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40",
156
159
  children: r[e]
157
- }, e)), R.status !== "DISABLED" && /* @__PURE__ */ E("button", {
160
+ }, e)), z.status !== "DISABLED" && /* @__PURE__ */ D("button", {
158
161
  type: "button",
159
- disabled: I.isPending,
160
- onClick: () => W(!0),
162
+ disabled: L.isPending,
163
+ onClick: () => G(!0),
161
164
  className: "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-40",
162
- children: [/* @__PURE__ */ T(y, { className: "h-3.5 w-3.5" }), N("adaptercloud.connections.disable", "Disable")]
165
+ children: [/* @__PURE__ */ E(y, { className: "h-3.5 w-3.5" }), P("adaptercloud.connections.disable", "Disable")]
163
166
  })]
164
167
  })]
165
168
  }),
166
- /* @__PURE__ */ E("div", {
169
+ /* @__PURE__ */ D("div", {
167
170
  className: "mt-5 border-t border-border-subtle pt-5",
168
- children: [/* @__PURE__ */ E("h3", {
171
+ children: [/* @__PURE__ */ D("h3", {
169
172
  className: "mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary",
170
- children: [/* @__PURE__ */ T(S, { className: "h-4 w-4" }), N("adaptercloud.connections.startSync", "Start a sync run")]
173
+ children: [/* @__PURE__ */ E(C, { className: "h-4 w-4" }), P("adaptercloud.connections.startSync", "Start a sync run")]
171
174
  }), /* @__PURE__ */ E("div", {
172
- className: "flex flex-wrap items-center gap-3",
173
- children: [/* @__PURE__ */ T("select", {
174
- value: z,
175
- onChange: (e) => B(e.target.value),
176
- "aria-label": N("adaptercloud.connections.syncKind", "Sync run kind"),
177
- className: "rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
178
- children: k.map((e) => /* @__PURE__ */ T("option", {
179
- value: e,
180
- children: o[e]
181
- }, e))
182
- }), /* @__PURE__ */ E("button", {
183
- type: "button",
184
- disabled: L.isPending,
185
- onClick: J,
186
- className: "inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90 disabled:opacity-50",
187
- children: [/* @__PURE__ */ T(x, { className: "h-4 w-4" }), N("adaptercloud.connections.run", "Run")]
188
- })]
175
+ className: "flex flex-wrap gap-2",
176
+ children: A.map((e) => {
177
+ let t = R.isPending && B === e;
178
+ return /* @__PURE__ */ D("button", {
179
+ type: "button",
180
+ disabled: R.isPending,
181
+ onClick: () => Y(e),
182
+ className: "inline-flex items-center gap-2 rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:opacity-50",
183
+ children: [t ? /* @__PURE__ */ E(b, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ E(S, { className: "h-4 w-4" }), o[e]]
184
+ }, e);
185
+ })
189
186
  })]
190
187
  })
191
188
  ]
192
189
  }),
193
- R.config != null && /* @__PURE__ */ E(D, {
190
+ z.config != null && /* @__PURE__ */ D(O, {
194
191
  className: "p-6",
195
- children: [/* @__PURE__ */ T("h3", {
192
+ children: [/* @__PURE__ */ E("h3", {
196
193
  className: "mb-3 text-sm font-semibold text-text-primary",
197
- children: N("adaptercloud.connections.config", "Configuration")
198
- }), /* @__PURE__ */ T("pre", {
194
+ children: P("adaptercloud.connections.config", "Configuration")
195
+ }), /* @__PURE__ */ E("pre", {
199
196
  className: "overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary",
200
- children: JSON.stringify(R.config, null, 2)
197
+ children: JSON.stringify(z.config, null, 2)
201
198
  })]
202
199
  }),
203
- /* @__PURE__ */ E("section", { children: [/* @__PURE__ */ E("div", {
200
+ /* @__PURE__ */ D("section", { children: [/* @__PURE__ */ D("div", {
204
201
  className: "mb-3 flex items-center justify-between",
205
- children: [/* @__PURE__ */ T("h3", {
202
+ children: [/* @__PURE__ */ E("h3", {
206
203
  className: "text-base font-semibold text-text-primary",
207
- children: N("adaptercloud.connections.discoveredResources", "Discovered Resources")
208
- }), /* @__PURE__ */ T("button", {
204
+ children: P("adaptercloud.connections.discoveredResources", "Discovered Resources")
205
+ }), /* @__PURE__ */ E("button", {
209
206
  type: "button",
210
- onClick: () => j(`/resources?connectionId=${R.id}`),
207
+ onClick: () => M(`/resources?connectionId=${z.id}`),
211
208
  className: "text-sm font-medium text-accent-blue hover:underline",
212
- children: N("adaptercloud.common.viewAll", "View all")
209
+ children: P("adaptercloud.common.viewAll", "View all")
213
210
  })]
214
- }), R.resources && R.resources.length > 0 ? /* @__PURE__ */ T("div", {
211
+ }), z.resources && z.resources.length > 0 ? /* @__PURE__ */ E("div", {
215
212
  className: "divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface",
216
- children: R.resources.slice(0, 10).map((e) => /* @__PURE__ */ E("button", {
213
+ children: z.resources.slice(0, 10).map((e) => /* @__PURE__ */ D("button", {
217
214
  type: "button",
218
- onClick: () => j(`/resources/${e.id}`),
215
+ onClick: () => M(`/resources/${e.id}`),
219
216
  className: "flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50",
220
217
  children: [
221
- /* @__PURE__ */ T(C, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
222
- /* @__PURE__ */ E("div", {
218
+ /* @__PURE__ */ E(w, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
219
+ /* @__PURE__ */ D("div", {
223
220
  className: "min-w-0 flex-1",
224
- children: [/* @__PURE__ */ T("p", {
221
+ children: [/* @__PURE__ */ E("p", {
225
222
  className: "truncate text-sm font-medium text-text-primary",
226
223
  children: e.name
227
- }), /* @__PURE__ */ E("p", {
224
+ }), /* @__PURE__ */ D("p", {
228
225
  className: "mt-0.5 text-xs text-text-secondary",
229
226
  children: [e.resourceType, e.region ? ` · ${e.region}` : ""]
230
227
  })]
231
228
  }),
232
- /* @__PURE__ */ T("span", {
229
+ /* @__PURE__ */ E("span", {
233
230
  className: "hidden text-xs text-text-secondary sm:inline",
234
231
  children: i(e.monthlyCost)
235
232
  }),
236
- /* @__PURE__ */ T(s, {
233
+ /* @__PURE__ */ E(s, {
237
234
  status: e.state,
238
235
  label: a[e.state]
239
236
  })
240
237
  ]
241
238
  }, e.id))
242
- }) : /* @__PURE__ */ T("p", {
239
+ }) : /* @__PURE__ */ E("p", {
243
240
  className: "rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary",
244
- children: N("adaptercloud.connections.noResources", "No resources discovered yet. Start a discovery sync run.")
241
+ children: P("adaptercloud.connections.noResources", "No resources discovered yet. Start a discovery sync run.")
245
242
  })] })
246
243
  ]
247
244
  })
248
- }), /* @__PURE__ */ T(m, {
249
- open: U,
250
- onOpenChange: W,
251
- title: N("adaptercloud.connections.disableTitle", "Disable this connection?"),
252
- description: N("adaptercloud.connections.disablePrompt", "Disabling stops discovery and sync runs against this target. You can re-enable it later by setting its health."),
253
- confirmLabel: N("adaptercloud.connections.disable", "Disable"),
254
- cancelLabel: N("adaptercloud.common.cancel", "Cancel"),
255
- onConfirm: q,
256
- isPending: I.isPending,
245
+ }), /* @__PURE__ */ E(m, {
246
+ open: W,
247
+ onOpenChange: G,
248
+ title: P("adaptercloud.connections.disableTitle", "Disable this connection?"),
249
+ description: P("adaptercloud.connections.disablePrompt", "Disabling stops discovery and sync runs against this target. You can re-enable it later by setting its health."),
250
+ confirmLabel: P("adaptercloud.connections.disable", "Disable"),
251
+ cancelLabel: P("adaptercloud.common.cancel", "Cancel"),
252
+ onConfirm: J,
253
+ isPending: L.isPending,
257
254
  tone: "danger"
258
255
  })]
259
256
  });
260
257
  }
261
258
  //#endregion
262
- export { A as ConnectionDetailPage };
259
+ export { j as ConnectionDetailPage };
263
260
 
264
261
  //# sourceMappingURL=ConnectionDetailPage.js.map