@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.
- package/dist/adaptercloud/components/viz/StackedBar.js +35 -1
- package/dist/adaptercloud/components/viz/StackedBar.js.map +1 -0
- package/dist/adaptercloud/pages/OverviewPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/OverviewPage.js +178 -163
- package/dist/adaptercloud/pages/OverviewPage.js.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js +136 -139
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/costs/CostsPage.js +9 -9
- package/dist/adaptercloud/pages/policies/PolicyFormPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/policies/PolicyFormPage.js +34 -31
- package/dist/adaptercloud/pages/policies/PolicyFormPage.js.map +1 -1
- package/dist/adaptercloud/pages/resources/ResourceDetailPage.d.ts.map +1 -1
- package/dist/adaptercloud/pages/resources/ResourceDetailPage.js +149 -128
- package/dist/adaptercloud/pages/resources/ResourceDetailPage.js.map +1 -1
- package/dist/adaptercloud/pages/topology/TopologyPage.js +4 -4
- package/dist/adaptercloud/pages/topology/TopologyPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -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;
|
|
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,
|
|
12
|
-
import { useParams as
|
|
13
|
-
import { jsx as
|
|
14
|
-
import { GlassCard as
|
|
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
|
|
16
|
+
var k = [
|
|
17
17
|
"CONNECTED",
|
|
18
18
|
"DEGRADED",
|
|
19
19
|
"ERROR",
|
|
20
20
|
"PENDING"
|
|
21
|
-
],
|
|
21
|
+
], A = [
|
|
22
22
|
"DISCOVERY",
|
|
23
23
|
"RECONCILE",
|
|
24
24
|
"COST_INGEST",
|
|
25
25
|
"FULL"
|
|
26
26
|
];
|
|
27
|
-
function
|
|
28
|
-
let { id:
|
|
29
|
-
let n =
|
|
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
|
-
}, [
|
|
32
|
-
|
|
33
|
-
id:
|
|
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:
|
|
35
|
+
}, { onError: K }));
|
|
36
36
|
}, [
|
|
37
|
-
|
|
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
|
-
|
|
39
|
+
K
|
|
49
40
|
]), J = h(() => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
63
|
+
R,
|
|
64
|
+
M,
|
|
65
|
+
K
|
|
63
66
|
]);
|
|
64
|
-
return /* @__PURE__ */
|
|
65
|
-
title:
|
|
66
|
-
description:
|
|
67
|
-
actions: /* @__PURE__ */
|
|
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__ */
|
|
72
|
+
children: [/* @__PURE__ */ D("button", {
|
|
70
73
|
type: "button",
|
|
71
|
-
onClick: () =>
|
|
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__ */
|
|
74
|
-
}),
|
|
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: () =>
|
|
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__ */
|
|
81
|
+
children: [/* @__PURE__ */ E(x, { className: "h-4 w-4" }), P("adaptercloud.common.edit", "Edit")]
|
|
79
82
|
})]
|
|
80
83
|
}),
|
|
81
|
-
children: [/* @__PURE__ */
|
|
82
|
-
isLoading:
|
|
83
|
-
isError:
|
|
84
|
-
isEmpty: !
|
|
85
|
-
error:
|
|
86
|
-
onRetry: () => void
|
|
87
|
-
emptyTitle:
|
|
88
|
-
children:
|
|
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
|
-
|
|
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:
|
|
98
|
+
children: H
|
|
96
99
|
}),
|
|
97
|
-
/* @__PURE__ */
|
|
100
|
+
/* @__PURE__ */ D(O, {
|
|
98
101
|
className: "p-6",
|
|
99
102
|
children: [
|
|
100
|
-
/* @__PURE__ */
|
|
103
|
+
/* @__PURE__ */ D("div", {
|
|
101
104
|
className: "mb-4 flex flex-wrap items-center gap-3",
|
|
102
|
-
children: [/* @__PURE__ */
|
|
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[
|
|
107
|
+
children: n[z.authMethod]
|
|
105
108
|
})]
|
|
106
109
|
}),
|
|
107
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ D("dl", {
|
|
108
111
|
className: "grid grid-cols-2 gap-4 text-sm sm:grid-cols-4",
|
|
109
112
|
children: [
|
|
110
|
-
/* @__PURE__ */
|
|
113
|
+
/* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("dt", {
|
|
111
114
|
className: "text-text-secondary",
|
|
112
|
-
children:
|
|
113
|
-
}), /* @__PURE__ */
|
|
115
|
+
children: P("adaptercloud.connections.region", "Region")
|
|
116
|
+
}), /* @__PURE__ */ E("dd", {
|
|
114
117
|
className: "mt-0.5 font-medium text-text-primary",
|
|
115
|
-
children:
|
|
118
|
+
children: z.region ?? "—"
|
|
116
119
|
})] }),
|
|
117
|
-
/* @__PURE__ */
|
|
120
|
+
/* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("dt", {
|
|
118
121
|
className: "text-text-secondary",
|
|
119
|
-
children:
|
|
120
|
-
}), /* @__PURE__ */
|
|
122
|
+
children: P("adaptercloud.connections.environment", "Environment")
|
|
123
|
+
}), /* @__PURE__ */ E("dd", {
|
|
121
124
|
className: "mt-0.5 font-medium text-text-primary",
|
|
122
|
-
children:
|
|
125
|
+
children: z.environment ?? "—"
|
|
123
126
|
})] }),
|
|
124
|
-
/* @__PURE__ */
|
|
127
|
+
/* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("dt", {
|
|
125
128
|
className: "text-text-secondary",
|
|
126
|
-
children:
|
|
127
|
-
}), /* @__PURE__ */
|
|
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:
|
|
132
|
+
children: z.resourceCount
|
|
130
133
|
})] }),
|
|
131
|
-
/* @__PURE__ */
|
|
134
|
+
/* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("dt", {
|
|
132
135
|
className: "text-text-secondary",
|
|
133
|
-
children:
|
|
134
|
-
}), /* @__PURE__ */
|
|
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:
|
|
139
|
+
children: z.lastSyncedAt ? p(z.lastSyncedAt) : "—"
|
|
137
140
|
})] })
|
|
138
141
|
]
|
|
139
142
|
}),
|
|
140
|
-
|
|
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:
|
|
145
|
+
children: z.lastError
|
|
143
146
|
}),
|
|
144
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ D("div", {
|
|
145
148
|
className: "mt-5 border-t border-border-subtle pt-5",
|
|
146
|
-
children: [/* @__PURE__ */
|
|
149
|
+
children: [/* @__PURE__ */ E("h3", {
|
|
147
150
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
148
|
-
children:
|
|
149
|
-
}), /* @__PURE__ */
|
|
151
|
+
children: P("adaptercloud.connections.setHealth", "Set health")
|
|
152
|
+
}), /* @__PURE__ */ D("div", {
|
|
150
153
|
className: "flex flex-wrap gap-2",
|
|
151
|
-
children: [
|
|
154
|
+
children: [k.map((e) => /* @__PURE__ */ E("button", {
|
|
152
155
|
type: "button",
|
|
153
|
-
disabled:
|
|
154
|
-
onClick: () =>
|
|
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)),
|
|
160
|
+
}, e)), z.status !== "DISABLED" && /* @__PURE__ */ D("button", {
|
|
158
161
|
type: "button",
|
|
159
|
-
disabled:
|
|
160
|
-
onClick: () =>
|
|
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__ */
|
|
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__ */
|
|
169
|
+
/* @__PURE__ */ D("div", {
|
|
167
170
|
className: "mt-5 border-t border-border-subtle pt-5",
|
|
168
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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
|
|
173
|
-
children:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
children: o[e]
|
|
181
|
-
}, e)
|
|
182
|
-
})
|
|
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
|
-
|
|
190
|
+
z.config != null && /* @__PURE__ */ D(O, {
|
|
194
191
|
className: "p-6",
|
|
195
|
-
children: [/* @__PURE__ */
|
|
192
|
+
children: [/* @__PURE__ */ E("h3", {
|
|
196
193
|
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
197
|
-
children:
|
|
198
|
-
}), /* @__PURE__ */
|
|
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(
|
|
197
|
+
children: JSON.stringify(z.config, null, 2)
|
|
201
198
|
})]
|
|
202
199
|
}),
|
|
203
|
-
/* @__PURE__ */
|
|
200
|
+
/* @__PURE__ */ D("section", { children: [/* @__PURE__ */ D("div", {
|
|
204
201
|
className: "mb-3 flex items-center justify-between",
|
|
205
|
-
children: [/* @__PURE__ */
|
|
202
|
+
children: [/* @__PURE__ */ E("h3", {
|
|
206
203
|
className: "text-base font-semibold text-text-primary",
|
|
207
|
-
children:
|
|
208
|
-
}), /* @__PURE__ */
|
|
204
|
+
children: P("adaptercloud.connections.discoveredResources", "Discovered Resources")
|
|
205
|
+
}), /* @__PURE__ */ E("button", {
|
|
209
206
|
type: "button",
|
|
210
|
-
onClick: () =>
|
|
207
|
+
onClick: () => M(`/resources?connectionId=${z.id}`),
|
|
211
208
|
className: "text-sm font-medium text-accent-blue hover:underline",
|
|
212
|
-
children:
|
|
209
|
+
children: P("adaptercloud.common.viewAll", "View all")
|
|
213
210
|
})]
|
|
214
|
-
}),
|
|
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:
|
|
213
|
+
children: z.resources.slice(0, 10).map((e) => /* @__PURE__ */ D("button", {
|
|
217
214
|
type: "button",
|
|
218
|
-
onClick: () =>
|
|
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__ */
|
|
222
|
-
/* @__PURE__ */
|
|
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__ */
|
|
221
|
+
children: [/* @__PURE__ */ E("p", {
|
|
225
222
|
className: "truncate text-sm font-medium text-text-primary",
|
|
226
223
|
children: e.name
|
|
227
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
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:
|
|
241
|
+
children: P("adaptercloud.connections.noResources", "No resources discovered yet. Start a discovery sync run.")
|
|
245
242
|
})] })
|
|
246
243
|
]
|
|
247
244
|
})
|
|
248
|
-
}), /* @__PURE__ */
|
|
249
|
-
open:
|
|
250
|
-
onOpenChange:
|
|
251
|
-
title:
|
|
252
|
-
description:
|
|
253
|
-
confirmLabel:
|
|
254
|
-
cancelLabel:
|
|
255
|
-
onConfirm:
|
|
256
|
-
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 {
|
|
259
|
+
export { j as ConnectionDetailPage };
|
|
263
260
|
|
|
264
261
|
//# sourceMappingURL=ConnectionDetailPage.js.map
|