@burdenoff/microfe-adaptercloud 2026.706.1 → 2026.706.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.
Files changed (41) hide show
  1. package/dist/adaptercloud/AdapterCloudRoutes.js +5 -1
  2. package/dist/adaptercloud/AdapterCloudRoutes.js.map +1 -1
  3. package/dist/adaptercloud/components/ConfirmDialog.js +27 -0
  4. package/dist/adaptercloud/components/ConfirmDialog.js.map +1 -0
  5. package/dist/adaptercloud/components/DataState.js +1 -1
  6. package/dist/adaptercloud/components/DataState.js.map +1 -1
  7. package/dist/adaptercloud/hooks/useAdapterCloudApi.js +50 -31
  8. package/dist/adaptercloud/hooks/useAdapterCloudApi.js.map +1 -1
  9. package/dist/adaptercloud/pages/OverviewPage.js +159 -156
  10. package/dist/adaptercloud/pages/OverviewPage.js.map +1 -1
  11. package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js +102 -89
  12. package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js.map +1 -1
  13. package/dist/adaptercloud/pages/adapters/AdapterFormPage.js +2 -0
  14. package/dist/adaptercloud/pages/adapters/AdapterFormPage.js.map +1 -1
  15. package/dist/adaptercloud/pages/adapters/AdaptersListPage.js +2 -0
  16. package/dist/adaptercloud/pages/adapters/AdaptersListPage.js.map +1 -1
  17. package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js +141 -124
  18. package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js.map +1 -1
  19. package/dist/adaptercloud/pages/connections/ConnectionFormPage.js +2 -0
  20. package/dist/adaptercloud/pages/connections/ConnectionFormPage.js.map +1 -1
  21. package/dist/adaptercloud/pages/connections/ConnectionsListPage.js +1 -0
  22. package/dist/adaptercloud/pages/connections/ConnectionsListPage.js.map +1 -1
  23. package/dist/adaptercloud/pages/costs/CostsPage.js +112 -87
  24. package/dist/adaptercloud/pages/costs/CostsPage.js.map +1 -1
  25. package/dist/adaptercloud/pages/drift/DriftListPage.js +81 -59
  26. package/dist/adaptercloud/pages/drift/DriftListPage.js.map +1 -1
  27. package/dist/adaptercloud/pages/policies/PoliciesListPage.js +2 -0
  28. package/dist/adaptercloud/pages/policies/PoliciesListPage.js.map +1 -1
  29. package/dist/adaptercloud/pages/policies/PolicyDetailPage.js +109 -91
  30. package/dist/adaptercloud/pages/policies/PolicyDetailPage.js.map +1 -1
  31. package/dist/adaptercloud/pages/policies/PolicyFormPage.js +211 -184
  32. package/dist/adaptercloud/pages/policies/PolicyFormPage.js.map +1 -1
  33. package/dist/adaptercloud/pages/resources/ResourceDetailPage.js +153 -111
  34. package/dist/adaptercloud/pages/resources/ResourceDetailPage.js.map +1 -1
  35. package/dist/adaptercloud/pages/resources/ResourcesListPage.js +111 -83
  36. package/dist/adaptercloud/pages/resources/ResourcesListPage.js.map +1 -1
  37. package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js +108 -86
  38. package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js.map +1 -1
  39. package/dist/adaptercloud/pages/violations/ViolationsListPage.js +11 -3
  40. package/dist/adaptercloud/pages/violations/ViolationsListPage.js.map +1 -1
  41. package/package.json +1 -1
@@ -40,6 +40,7 @@ function y() {
40
40
  children: [/* @__PURE__ */ g("select", {
41
41
  value: S,
42
42
  onChange: (e) => j(C)(e.target.value),
43
+ "aria-label": x("adaptercloud.adapters.filterByKind", "Filter by kind"),
43
44
  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)]",
44
45
  children: [/* @__PURE__ */ h("option", {
45
46
  value: "",
@@ -51,6 +52,7 @@ function y() {
51
52
  }), /* @__PURE__ */ g("select", {
52
53
  value: w,
53
54
  onChange: (e) => j(T)(e.target.value),
55
+ "aria-label": x("adaptercloud.adapters.filterByStatus", "Filter by status"),
54
56
  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)]",
55
57
  children: [/* @__PURE__ */ h("option", {
56
58
  value: "",
@@ -1 +1 @@
1
- {"version":3,"file":"AdaptersListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/adapters/AdaptersListPage.tsx"],"sourcesContent":["/**\n * Adapters List Page\n * @module adaptercloud/pages/adapters\n *\n * The adapter catalog — every reusable connector definition in the workspace.\n * Lists from `adaListAdapters` with kind/status filters and offset pagination\n * (driven by `AdaPageInfo.hasMore`).\n */\n\nimport { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Boxes, Plus, ChevronLeft, ChevronRight } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useAdapters } from '../../hooks/useAdapterCloudApi';\nimport { adapterKindLabels, adapterStatusLabels } from '../../utils/domain';\nimport { formatRelativeTime } from '../../utils/formatters';\nimport type { AdaAdapterKind, AdaAdapterStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nexport function AdaptersListPage() {\n const { navigateTo } = 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 const [kind, setKind] = useState<AdaAdapterKind | ''>('');\n const [status, setStatus] = useState<AdaAdapterStatus | ''>('');\n const [offset, setOffset] = useState(0);\n\n const query = useAdapters({\n kind: kind || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n const resetTo = useCallback(<T,>(setter: (v: T) => void) => {\n return (v: T) => {\n setter(v);\n setOffset(0);\n };\n }, []);\n\n return (\n <PageLayout\n title={t('adaptercloud.adapters.title', 'Adapters')}\n description={t(\n 'adaptercloud.adapters.subtitle',\n 'The catalog of connectors that bridge each class of system into the fabric.'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/adapters/new')}\n 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\"\n >\n <Plus className=\"h-4 w-4\" />\n {t('adaptercloud.adapters.new', 'New adapter')}\n </button>\n }\n >\n {/* Filters */}\n <div className=\"mb-6 flex flex-wrap gap-3\">\n <select\n value={kind}\n onChange={(e) => resetTo(setKind)(e.target.value as AdaAdapterKind | '')}\n 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)]\"\n >\n <option value=\"\">{t('adaptercloud.adapters.allKinds', 'All kinds')}</option>\n {(Object.keys(adapterKindLabels) as AdaAdapterKind[]).map((k) => (\n <option key={k} value={k}>\n {adapterKindLabels[k]}\n </option>\n ))}\n </select>\n <select\n value={status}\n onChange={(e) => resetTo(setStatus)(e.target.value as AdaAdapterStatus | '')}\n 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)]\"\n >\n <option value=\"\">{t('adaptercloud.adapters.allStatuses', 'All statuses')}</option>\n {(Object.keys(adapterStatusLabels) as AdaAdapterStatus[]).map((s) => (\n <option key={s} value={s}>\n {adapterStatusLabels[s]}\n </option>\n ))}\n </select>\n </div>\n\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={items.length === 0}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.adapters.emptyTitle', 'No adapters yet')}\n emptyDescription={t(\n 'adaptercloud.adapters.emptyDescription',\n 'Define your first adapter to start bridging a class of system into the fabric.'\n )}\n emptyIcon={<Boxes className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/adapters/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.adapters.new', 'New adapter')}\n </button>\n }\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {items.map((adapter) => (\n <GlassCard\n key={adapter.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => navigateTo(`/adapters/${adapter.id}`)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateTo(`/adapters/${adapter.id}`);\n }\n }}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">\n {adapter.name}\n </h3>\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{adapter.slug}</p>\n </div>\n <StatusBadge status={adapter.status} />\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-2 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5\">\n {adapterKindLabels[adapter.kind]}\n </span>\n <span>v{adapter.version}</span>\n {adapter.vendor && <span>· {adapter.vendor}</span>}\n </div>\n\n {adapter.description && (\n <p className=\"mt-3 line-clamp-2 text-sm text-text-secondary\">\n {adapter.description}\n </p>\n )}\n\n {adapter.capabilities.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {adapter.capabilities.slice(0, 4).map((cap) => (\n <span\n key={cap}\n className=\"inline-flex items-center rounded-full bg-accent-blue-subtle px-2 py-0.5 text-xs text-accent-blue\"\n >\n {cap}\n </span>\n ))}\n {adapter.capabilities.length > 4 && (\n <span className=\"text-xs text-text-secondary\">\n +{adapter.capabilities.length - 4}\n </span>\n )}\n </div>\n )}\n\n <p className=\"mt-4 text-xs text-text-secondary\">\n {t('adaptercloud.common.updated', 'Updated')}{' '}\n {formatRelativeTime(adapter.updatedAt)}\n </p>\n </GlassCard>\n ))}\n </div>\n\n {/* Pagination */}\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-between\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.prev', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.common.showing', 'Showing')} {offset + 1}–{offset + items.length}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {t('adaptercloud.common.next', 'Next')}\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdaptersListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/adapters/AdaptersListPage.tsx"],"sourcesContent":["/**\n * Adapters List Page\n * @module adaptercloud/pages/adapters\n *\n * The adapter catalog — every reusable connector definition in the workspace.\n * Lists from `adaListAdapters` with kind/status filters and offset pagination\n * (driven by `AdaPageInfo.hasMore`).\n */\n\nimport { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Boxes, Plus, ChevronLeft, ChevronRight } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useAdapters } from '../../hooks/useAdapterCloudApi';\nimport { adapterKindLabels, adapterStatusLabels } from '../../utils/domain';\nimport { formatRelativeTime } from '../../utils/formatters';\nimport type { AdaAdapterKind, AdaAdapterStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nexport function AdaptersListPage() {\n const { navigateTo } = 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 const [kind, setKind] = useState<AdaAdapterKind | ''>('');\n const [status, setStatus] = useState<AdaAdapterStatus | ''>('');\n const [offset, setOffset] = useState(0);\n\n const query = useAdapters({\n kind: kind || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n const resetTo = useCallback(<T,>(setter: (v: T) => void) => {\n return (v: T) => {\n setter(v);\n setOffset(0);\n };\n }, []);\n\n return (\n <PageLayout\n title={t('adaptercloud.adapters.title', 'Adapters')}\n description={t(\n 'adaptercloud.adapters.subtitle',\n 'The catalog of connectors that bridge each class of system into the fabric.'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/adapters/new')}\n 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\"\n >\n <Plus className=\"h-4 w-4\" />\n {t('adaptercloud.adapters.new', 'New adapter')}\n </button>\n }\n >\n {/* Filters */}\n <div className=\"mb-6 flex flex-wrap gap-3\">\n <select\n value={kind}\n onChange={(e) => resetTo(setKind)(e.target.value as AdaAdapterKind | '')}\n aria-label={t('adaptercloud.adapters.filterByKind', 'Filter by kind')}\n 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)]\"\n >\n <option value=\"\">{t('adaptercloud.adapters.allKinds', 'All kinds')}</option>\n {(Object.keys(adapterKindLabels) as AdaAdapterKind[]).map((k) => (\n <option key={k} value={k}>\n {adapterKindLabels[k]}\n </option>\n ))}\n </select>\n <select\n value={status}\n onChange={(e) => resetTo(setStatus)(e.target.value as AdaAdapterStatus | '')}\n aria-label={t('adaptercloud.adapters.filterByStatus', 'Filter by status')}\n 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)]\"\n >\n <option value=\"\">{t('adaptercloud.adapters.allStatuses', 'All statuses')}</option>\n {(Object.keys(adapterStatusLabels) as AdaAdapterStatus[]).map((s) => (\n <option key={s} value={s}>\n {adapterStatusLabels[s]}\n </option>\n ))}\n </select>\n </div>\n\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={items.length === 0}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.adapters.emptyTitle', 'No adapters yet')}\n emptyDescription={t(\n 'adaptercloud.adapters.emptyDescription',\n 'Define your first adapter to start bridging a class of system into the fabric.'\n )}\n emptyIcon={<Boxes className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/adapters/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.adapters.new', 'New adapter')}\n </button>\n }\n >\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {items.map((adapter) => (\n <GlassCard\n key={adapter.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => navigateTo(`/adapters/${adapter.id}`)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateTo(`/adapters/${adapter.id}`);\n }\n }}\n className=\"cursor-pointer p-5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-base font-semibold text-text-primary\">\n {adapter.name}\n </h3>\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">{adapter.slug}</p>\n </div>\n <StatusBadge status={adapter.status} />\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-2 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5\">\n {adapterKindLabels[adapter.kind]}\n </span>\n <span>v{adapter.version}</span>\n {adapter.vendor && <span>· {adapter.vendor}</span>}\n </div>\n\n {adapter.description && (\n <p className=\"mt-3 line-clamp-2 text-sm text-text-secondary\">\n {adapter.description}\n </p>\n )}\n\n {adapter.capabilities.length > 0 && (\n <div className=\"mt-3 flex flex-wrap gap-1.5\">\n {adapter.capabilities.slice(0, 4).map((cap) => (\n <span\n key={cap}\n className=\"inline-flex items-center rounded-full bg-accent-blue-subtle px-2 py-0.5 text-xs text-accent-blue\"\n >\n {cap}\n </span>\n ))}\n {adapter.capabilities.length > 4 && (\n <span className=\"text-xs text-text-secondary\">\n +{adapter.capabilities.length - 4}\n </span>\n )}\n </div>\n )}\n\n <p className=\"mt-4 text-xs text-text-secondary\">\n {t('adaptercloud.common.updated', 'Updated')}{' '}\n {formatRelativeTime(adapter.updatedAt)}\n </p>\n </GlassCard>\n ))}\n </div>\n\n {/* Pagination */}\n {(offset > 0 || hasMore) && (\n <div className=\"mt-6 flex items-center justify-between\">\n <button\n type=\"button\"\n disabled={offset === 0}\n onClick={() => setOffset((o) => Math.max(0, o - PAGE_SIZE))}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.prev', 'Previous')}\n </button>\n <span className=\"text-sm text-text-secondary\">\n {t('adaptercloud.common.showing', 'Showing')} {offset + 1}–{offset + items.length}\n </span>\n <button\n type=\"button\"\n disabled={!hasMore}\n onClick={() => setOffset((o) => o + PAGE_SIZE)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {t('adaptercloud.common.next', 'Next')}\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n )}\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -5,243 +5,260 @@ import { StatusBadge as s } from "../../components/StatusBadge.js";
5
5
  import { DataState as c } from "../../components/DataState.js";
6
6
  import { useConnection as l, useDisableConnection as u, useSetConnectionStatus as d, useStartSyncRun as f } from "../../hooks/useAdapterCloudApi.js";
7
7
  import { formatDate as p } from "../../utils/formatters.js";
8
- import { useCallback as m, useState as h } from "react";
9
- import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
- import { ArrowLeft as _, Ban as v, Pencil as y, Play as b, RefreshCw as x, Server as S } from "lucide-react";
11
- import { useParams as C } from "react-router-dom";
12
- import { jsx as w, jsxs as T } from "react/jsx-runtime";
13
- import { GlassCard as E } from "@burdenoff/fe-libs/ui";
8
+ import { ConfirmDialog as m } from "../../components/ConfirmDialog.js";
9
+ import { useCallback as h, useState as g } from "react";
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-dom";
13
+ import { jsx as T, jsxs as E } from "react/jsx-runtime";
14
+ import { GlassCard as D } from "@burdenoff/fe-libs/ui";
14
15
  //#region src/adaptercloud/pages/connections/ConnectionDetailPage.tsx
15
- var D = [
16
+ var O = [
16
17
  "CONNECTED",
17
18
  "DEGRADED",
18
19
  "ERROR",
19
20
  "PENDING"
20
- ], O = [
21
+ ], k = [
21
22
  "DISCOVERY",
22
23
  "RECONCILE",
23
24
  "COST_INGEST",
24
25
  "FULL"
25
26
  ];
26
- function k() {
27
- let { id: k } = C(), { navigateTo: A } = e(), { t: j } = g(), M = m((e, t) => {
28
- let n = j(e);
27
+ function A() {
28
+ let { id: A } = w(), { navigateTo: j } = e(), { t: M } = _(), N = h((e, t) => {
29
+ let n = M(e);
29
30
  return n === e ? t : n;
30
- }, [j]), N = l(k), P = d(), F = u(), I = f(), L = N.data, [R, z] = h("DISCOVERY"), [B, V] = h(null), H = m((e) => V(e instanceof Error ? e.message : "Action failed. Please try again."), []), U = m((e) => {
31
- k && (V(null), P.mutate({
32
- id: k,
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,
33
34
  status: e
34
- }, { onError: H }));
35
+ }, { onError: G }));
35
36
  }, [
36
- k,
37
- P,
38
- H
39
- ]), W = m(() => {
40
- k && (V(null), F.mutate(k, { onError: H }));
41
- }, [
42
- k,
37
+ A,
43
38
  F,
44
- H
45
- ]), G = m(() => {
46
- k && (V(null), I.mutate({
47
- connectionId: k,
48
- kind: R
49
- }, {
50
- onSuccess: () => A("/sync-runs"),
51
- onError: H
39
+ G
40
+ ]), q = h(() => {
41
+ A && (H(null), I.mutate(A, {
42
+ onSuccess: () => W(!1),
43
+ onError: G
52
44
  }));
53
45
  }, [
54
- k,
55
- R,
46
+ A,
56
47
  I,
48
+ G
49
+ ]), J = h(() => {
50
+ A && (H(null), L.mutate({
51
+ connectionId: A,
52
+ kind: z
53
+ }, {
54
+ onSuccess: () => j("/sync-runs"),
55
+ onError: G
56
+ }));
57
+ }, [
57
58
  A,
58
- H
59
+ z,
60
+ L,
61
+ j,
62
+ G
59
63
  ]);
60
- return /* @__PURE__ */ w(t, {
61
- title: L?.name ?? M("adaptercloud.connections.detailTitle", "Connection"),
62
- description: L?.adapter?.name,
63
- actions: /* @__PURE__ */ T("div", {
64
+ return /* @__PURE__ */ E(t, {
65
+ title: R?.name ?? N("adaptercloud.connections.detailTitle", "Connection"),
66
+ description: R?.adapter?.name,
67
+ actions: /* @__PURE__ */ E("div", {
64
68
  className: "flex items-center gap-2",
65
- children: [/* @__PURE__ */ T("button", {
69
+ children: [/* @__PURE__ */ E("button", {
66
70
  type: "button",
67
- onClick: () => A("/connections"),
71
+ onClick: () => j("/connections"),
68
72
  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",
69
- children: [/* @__PURE__ */ w(_, { className: "h-4 w-4" }), M("adaptercloud.common.back", "Back")]
70
- }), L && /* @__PURE__ */ T("button", {
73
+ children: [/* @__PURE__ */ T(v, { className: "h-4 w-4" }), N("adaptercloud.common.back", "Back")]
74
+ }), R && /* @__PURE__ */ E("button", {
71
75
  type: "button",
72
- onClick: () => A(`/connections/${L.id}/edit`),
76
+ onClick: () => j(`/connections/${R.id}/edit`),
73
77
  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",
74
- children: [/* @__PURE__ */ w(y, { className: "h-4 w-4" }), M("adaptercloud.common.edit", "Edit")]
78
+ children: [/* @__PURE__ */ T(b, { className: "h-4 w-4" }), N("adaptercloud.common.edit", "Edit")]
75
79
  })]
76
80
  }),
77
- children: /* @__PURE__ */ w(c, {
78
- isLoading: N.isLoading,
79
- isError: N.isError,
80
- isEmpty: !N.isLoading && !L,
81
- error: N.error,
82
- onRetry: () => void N.refetch(),
83
- emptyTitle: M("adaptercloud.connections.notFound", "Connection not found"),
84
- children: L && /* @__PURE__ */ T("div", {
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", {
85
89
  className: "space-y-6",
86
90
  children: [
87
- B && /* @__PURE__ */ w("p", {
91
+ V && /* @__PURE__ */ T("p", {
92
+ role: "alert",
93
+ "aria-live": "polite",
88
94
  className: "rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
89
- children: B
95
+ children: V
90
96
  }),
91
- /* @__PURE__ */ T(E, {
97
+ /* @__PURE__ */ E(D, {
92
98
  className: "p-6",
93
99
  children: [
94
- /* @__PURE__ */ T("div", {
100
+ /* @__PURE__ */ E("div", {
95
101
  className: "mb-4 flex flex-wrap items-center gap-3",
96
- children: [/* @__PURE__ */ w(s, { status: L.status }), /* @__PURE__ */ w("span", {
102
+ children: [/* @__PURE__ */ T(s, { status: R.status }), /* @__PURE__ */ T("span", {
97
103
  className: "inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary",
98
- children: n[L.authMethod]
104
+ children: n[R.authMethod]
99
105
  })]
100
106
  }),
101
- /* @__PURE__ */ T("dl", {
107
+ /* @__PURE__ */ E("dl", {
102
108
  className: "grid grid-cols-2 gap-4 text-sm sm:grid-cols-4",
103
109
  children: [
104
- /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("dt", {
110
+ /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
105
111
  className: "text-text-secondary",
106
- children: M("adaptercloud.connections.region", "Region")
107
- }), /* @__PURE__ */ w("dd", {
112
+ children: N("adaptercloud.connections.region", "Region")
113
+ }), /* @__PURE__ */ T("dd", {
108
114
  className: "mt-0.5 font-medium text-text-primary",
109
- children: L.region ?? "—"
115
+ children: R.region ?? "—"
110
116
  })] }),
111
- /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("dt", {
117
+ /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
112
118
  className: "text-text-secondary",
113
- children: M("adaptercloud.connections.environment", "Environment")
114
- }), /* @__PURE__ */ w("dd", {
119
+ children: N("adaptercloud.connections.environment", "Environment")
120
+ }), /* @__PURE__ */ T("dd", {
115
121
  className: "mt-0.5 font-medium text-text-primary",
116
- children: L.environment ?? "—"
122
+ children: R.environment ?? "—"
117
123
  })] }),
118
- /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("dt", {
124
+ /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
119
125
  className: "text-text-secondary",
120
- children: M("adaptercloud.connections.resourceCount", "Resources")
121
- }), /* @__PURE__ */ w("dd", {
126
+ children: N("adaptercloud.connections.resourceCount", "Resources")
127
+ }), /* @__PURE__ */ T("dd", {
122
128
  className: "mt-0.5 font-medium tabular-nums text-text-primary",
123
- children: L.resourceCount
129
+ children: R.resourceCount
124
130
  })] }),
125
- /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("dt", {
131
+ /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
126
132
  className: "text-text-secondary",
127
- children: M("adaptercloud.connections.lastSynced", "Last synced")
128
- }), /* @__PURE__ */ w("dd", {
133
+ children: N("adaptercloud.connections.lastSynced", "Last synced")
134
+ }), /* @__PURE__ */ T("dd", {
129
135
  className: "mt-0.5 font-medium text-text-primary",
130
- children: L.lastSyncedAt ? p(L.lastSyncedAt) : "—"
136
+ children: R.lastSyncedAt ? p(R.lastSyncedAt) : "—"
131
137
  })] })
132
138
  ]
133
139
  }),
134
- L.lastError && /* @__PURE__ */ w("p", {
140
+ R.lastError && /* @__PURE__ */ T("p", {
135
141
  className: "mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
136
- children: L.lastError
142
+ children: R.lastError
137
143
  }),
138
- /* @__PURE__ */ T("div", {
144
+ /* @__PURE__ */ E("div", {
139
145
  className: "mt-5 border-t border-border-subtle pt-5",
140
- children: [/* @__PURE__ */ w("h3", {
146
+ children: [/* @__PURE__ */ T("h3", {
141
147
  className: "mb-3 text-sm font-semibold text-text-primary",
142
- children: M("adaptercloud.connections.setHealth", "Set health")
143
- }), /* @__PURE__ */ T("div", {
148
+ children: N("adaptercloud.connections.setHealth", "Set health")
149
+ }), /* @__PURE__ */ E("div", {
144
150
  className: "flex flex-wrap gap-2",
145
- children: [D.map((e) => /* @__PURE__ */ w("button", {
151
+ children: [O.map((e) => /* @__PURE__ */ T("button", {
146
152
  type: "button",
147
- disabled: P.isPending || L.status === e,
148
- onClick: () => U(e),
153
+ disabled: F.isPending || R.status === e,
154
+ onClick: () => K(e),
149
155
  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",
150
156
  children: r[e]
151
- }, e)), L.status !== "DISABLED" && /* @__PURE__ */ T("button", {
157
+ }, e)), R.status !== "DISABLED" && /* @__PURE__ */ E("button", {
152
158
  type: "button",
153
- disabled: F.isPending,
154
- onClick: W,
159
+ disabled: I.isPending,
160
+ onClick: () => W(!0),
155
161
  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",
156
- children: [/* @__PURE__ */ w(v, { className: "h-3.5 w-3.5" }), M("adaptercloud.connections.disable", "Disable")]
162
+ children: [/* @__PURE__ */ T(y, { className: "h-3.5 w-3.5" }), N("adaptercloud.connections.disable", "Disable")]
157
163
  })]
158
164
  })]
159
165
  }),
160
- /* @__PURE__ */ T("div", {
166
+ /* @__PURE__ */ E("div", {
161
167
  className: "mt-5 border-t border-border-subtle pt-5",
162
- children: [/* @__PURE__ */ T("h3", {
168
+ children: [/* @__PURE__ */ E("h3", {
163
169
  className: "mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary",
164
- children: [/* @__PURE__ */ w(x, { className: "h-4 w-4" }), M("adaptercloud.connections.startSync", "Start a sync run")]
165
- }), /* @__PURE__ */ T("div", {
170
+ children: [/* @__PURE__ */ T(S, { className: "h-4 w-4" }), N("adaptercloud.connections.startSync", "Start a sync run")]
171
+ }), /* @__PURE__ */ E("div", {
166
172
  className: "flex flex-wrap items-center gap-3",
167
- children: [/* @__PURE__ */ w("select", {
168
- value: R,
169
- onChange: (e) => z(e.target.value),
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"),
170
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)]",
171
- children: O.map((e) => /* @__PURE__ */ w("option", {
178
+ children: k.map((e) => /* @__PURE__ */ T("option", {
172
179
  value: e,
173
180
  children: o[e]
174
181
  }, e))
175
- }), /* @__PURE__ */ T("button", {
182
+ }), /* @__PURE__ */ E("button", {
176
183
  type: "button",
177
- disabled: I.isPending,
178
- onClick: G,
184
+ disabled: L.isPending,
185
+ onClick: J,
179
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",
180
- children: [/* @__PURE__ */ w(b, { className: "h-4 w-4" }), M("adaptercloud.connections.run", "Run")]
187
+ children: [/* @__PURE__ */ T(x, { className: "h-4 w-4" }), N("adaptercloud.connections.run", "Run")]
181
188
  })]
182
189
  })]
183
190
  })
184
191
  ]
185
192
  }),
186
- L.config != null && /* @__PURE__ */ T(E, {
193
+ R.config != null && /* @__PURE__ */ E(D, {
187
194
  className: "p-6",
188
- children: [/* @__PURE__ */ w("h3", {
195
+ children: [/* @__PURE__ */ T("h3", {
189
196
  className: "mb-3 text-sm font-semibold text-text-primary",
190
- children: M("adaptercloud.connections.config", "Configuration")
191
- }), /* @__PURE__ */ w("pre", {
197
+ children: N("adaptercloud.connections.config", "Configuration")
198
+ }), /* @__PURE__ */ T("pre", {
192
199
  className: "overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary",
193
- children: JSON.stringify(L.config, null, 2)
200
+ children: JSON.stringify(R.config, null, 2)
194
201
  })]
195
202
  }),
196
- /* @__PURE__ */ T("section", { children: [/* @__PURE__ */ T("div", {
203
+ /* @__PURE__ */ E("section", { children: [/* @__PURE__ */ E("div", {
197
204
  className: "mb-3 flex items-center justify-between",
198
- children: [/* @__PURE__ */ w("h3", {
205
+ children: [/* @__PURE__ */ T("h3", {
199
206
  className: "text-base font-semibold text-text-primary",
200
- children: M("adaptercloud.connections.discoveredResources", "Discovered Resources")
201
- }), /* @__PURE__ */ w("button", {
207
+ children: N("adaptercloud.connections.discoveredResources", "Discovered Resources")
208
+ }), /* @__PURE__ */ T("button", {
202
209
  type: "button",
203
- onClick: () => A(`/resources?connectionId=${L.id}`),
204
- className: "text-sm font-medium text-primary hover:underline",
205
- children: M("adaptercloud.common.viewAll", "View all")
210
+ onClick: () => j(`/resources?connectionId=${R.id}`),
211
+ className: "text-sm font-medium text-accent-blue hover:underline",
212
+ children: N("adaptercloud.common.viewAll", "View all")
206
213
  })]
207
- }), L.resources && L.resources.length > 0 ? /* @__PURE__ */ w("div", {
214
+ }), R.resources && R.resources.length > 0 ? /* @__PURE__ */ T("div", {
208
215
  className: "divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface",
209
- children: L.resources.slice(0, 10).map((e) => /* @__PURE__ */ T("button", {
216
+ children: R.resources.slice(0, 10).map((e) => /* @__PURE__ */ E("button", {
210
217
  type: "button",
211
- onClick: () => A(`/resources/${e.id}`),
218
+ onClick: () => j(`/resources/${e.id}`),
212
219
  className: "flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50",
213
220
  children: [
214
- /* @__PURE__ */ w(S, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
215
- /* @__PURE__ */ T("div", {
221
+ /* @__PURE__ */ T(C, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
222
+ /* @__PURE__ */ E("div", {
216
223
  className: "min-w-0 flex-1",
217
- children: [/* @__PURE__ */ w("p", {
224
+ children: [/* @__PURE__ */ T("p", {
218
225
  className: "truncate text-sm font-medium text-text-primary",
219
226
  children: e.name
220
- }), /* @__PURE__ */ T("p", {
227
+ }), /* @__PURE__ */ E("p", {
221
228
  className: "mt-0.5 text-xs text-text-secondary",
222
229
  children: [e.resourceType, e.region ? ` · ${e.region}` : ""]
223
230
  })]
224
231
  }),
225
- /* @__PURE__ */ w("span", {
232
+ /* @__PURE__ */ T("span", {
226
233
  className: "hidden text-xs text-text-secondary sm:inline",
227
234
  children: i(e.monthlyCost)
228
235
  }),
229
- /* @__PURE__ */ w(s, {
236
+ /* @__PURE__ */ T(s, {
230
237
  status: e.state,
231
238
  label: a[e.state]
232
239
  })
233
240
  ]
234
241
  }, e.id))
235
- }) : /* @__PURE__ */ w("p", {
242
+ }) : /* @__PURE__ */ T("p", {
236
243
  className: "rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary",
237
- children: M("adaptercloud.connections.noResources", "No resources discovered yet. Start a discovery sync run.")
244
+ children: N("adaptercloud.connections.noResources", "No resources discovered yet. Start a discovery sync run.")
238
245
  })] })
239
246
  ]
240
247
  })
241
- })
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,
257
+ tone: "danger"
258
+ })]
242
259
  });
243
260
  }
244
261
  //#endregion
245
- export { k as ConnectionDetailPage };
262
+ export { A as ConnectionDetailPage };
246
263
 
247
264
  //# sourceMappingURL=ConnectionDetailPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConnectionDetailPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/ConnectionDetailPage.tsx"],"sourcesContent":["/**\n * Connection Detail Page\n * @module adaptercloud/pages/connections\n *\n * One connection (`adaConnection`) — its adapter, health, config, and the\n * resources it has discovered. Supports the validated health transition\n * (`adaSetConnectionStatus`), disable (`adaDisableConnection`), and starting a\n * sync run (`adaStartSyncRun`) against it.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ArrowLeft, Ban, Pencil, Play, RefreshCw, Server } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport {\n useConnection,\n useDisableConnection,\n useSetConnectionStatus,\n useStartSyncRun,\n} from '../../hooks/useAdapterCloudApi';\nimport {\n authMethodLabels,\n connectionStatusLabels,\n resourceStateLabels,\n syncKindLabels,\n} from '../../utils/domain';\nimport { formatDate } from '../../utils/formatters';\nimport { formatMoney } from '../../utils/domain';\nimport type { AdaConnectionStatus, AdaSyncKind } from '../../types';\n\nconst TRANSITIONABLE: AdaConnectionStatus[] = ['CONNECTED', 'DEGRADED', 'ERROR', 'PENDING'];\nconst SYNC_KINDS: AdaSyncKind[] = ['DISCOVERY', 'RECONCILE', 'COST_INGEST', 'FULL'];\n\nexport function ConnectionDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = 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 const query = useConnection(id);\n const setStatus = useSetConnectionStatus();\n const disable = useDisableConnection();\n const startRun = useStartSyncRun();\n const conn = query.data;\n\n const [syncKind, setSyncKind] = useState<AdaSyncKind>('DISCOVERY');\n const [actionError, setActionError] = useState<string | null>(null);\n\n const onError = useCallback(\n (err: unknown) =>\n setActionError(err instanceof Error ? err.message : 'Action failed. Please try again.'),\n []\n );\n\n const handleSetStatus = useCallback(\n (newStatus: AdaConnectionStatus) => {\n if (!id) return;\n setActionError(null);\n setStatus.mutate({ id, status: newStatus }, { onError });\n },\n [id, setStatus, onError]\n );\n\n const handleDisable = useCallback(() => {\n if (!id) return;\n setActionError(null);\n disable.mutate(id, { onError });\n }, [id, disable, onError]);\n\n const handleStartRun = useCallback(() => {\n if (!id) return;\n setActionError(null);\n startRun.mutate(\n { connectionId: id, kind: syncKind },\n { onSuccess: () => navigateTo('/sync-runs'), onError }\n );\n }, [id, syncKind, startRun, navigateTo, onError]);\n\n return (\n <PageLayout\n title={conn?.name ?? t('adaptercloud.connections.detailTitle', 'Connection')}\n description={conn?.adapter?.name}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\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 <ArrowLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.back', 'Back')}\n </button>\n {conn && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/connections/${conn.id}/edit`)}\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 <Pencil className=\"h-4 w-4\" />\n {t('adaptercloud.common.edit', 'Edit')}\n </button>\n )}\n </div>\n }\n >\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={!query.isLoading && !conn}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.connections.notFound', 'Connection not found')}\n >\n {conn && (\n <div className=\"space-y-6\">\n {actionError && (\n <p className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {actionError}\n </p>\n )}\n\n {/* Health + actions */}\n <GlassCard className=\"p-6\">\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <StatusBadge status={conn.status} />\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary\">\n {authMethodLabels[conn.authMethod]}\n </span>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-4 text-sm sm:grid-cols-4\">\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.region', 'Region')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">{conn.region ?? '—'}</dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.environment', 'Environment')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.environment ?? '—'}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.resourceCount', 'Resources')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n {conn.resourceCount}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.lastSynced', 'Last synced')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.lastSyncedAt ? formatDate(conn.lastSyncedAt) : '—'}\n </dd>\n </div>\n </dl>\n\n {conn.lastError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {conn.lastError}\n </p>\n )}\n\n {/* Health transitions */}\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.connections.setHealth', 'Set health')}\n </h3>\n <div className=\"flex flex-wrap gap-2\">\n {TRANSITIONABLE.map((s) => (\n <button\n key={s}\n type=\"button\"\n disabled={setStatus.isPending || conn.status === s}\n onClick={() => handleSetStatus(s)}\n 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\"\n >\n {connectionStatusLabels[s]}\n </button>\n ))}\n {conn.status !== 'DISABLED' && (\n <button\n type=\"button\"\n disabled={disable.isPending}\n onClick={handleDisable}\n 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\"\n >\n <Ban className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.connections.disable', 'Disable')}\n </button>\n )}\n </div>\n </div>\n\n {/* Start sync run */}\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <RefreshCw className=\"h-4 w-4\" />\n {t('adaptercloud.connections.startSync', 'Start a sync run')}\n </h3>\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n value={syncKind}\n onChange={(e) => setSyncKind(e.target.value as AdaSyncKind)}\n 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)]\"\n >\n {SYNC_KINDS.map((k) => (\n <option key={k} value={k}>\n {syncKindLabels[k]}\n </option>\n ))}\n </select>\n <button\n type=\"button\"\n disabled={startRun.isPending}\n onClick={handleStartRun}\n 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\"\n >\n <Play className=\"h-4 w-4\" />\n {t('adaptercloud.connections.run', 'Run')}\n </button>\n </div>\n </div>\n </GlassCard>\n\n {/* Config */}\n {conn.config != null && (\n <GlassCard className=\"p-6\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.connections.config', 'Configuration')}\n </h3>\n <pre className=\"overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary\">\n {JSON.stringify(conn.config, null, 2)}\n </pre>\n </GlassCard>\n )}\n\n {/* Resources */}\n <section>\n <div className=\"mb-3 flex items-center justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {t('adaptercloud.connections.discoveredResources', 'Discovered Resources')}\n </h3>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources?connectionId=${conn.id}`)}\n className=\"text-sm font-medium text-primary hover:underline\"\n >\n {t('adaptercloud.common.viewAll', 'View all')}\n </button>\n </div>\n {conn.resources && conn.resources.length > 0 ? (\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {conn.resources.slice(0, 10).map((r) => (\n <button\n key={r.id}\n type=\"button\"\n onClick={() => navigateTo(`/resources/${r.id}`)}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50\"\n >\n <Server className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{r.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {r.resourceType}\n {r.region ? ` · ${r.region}` : ''}\n </p>\n </div>\n <span className=\"hidden text-xs text-text-secondary sm:inline\">\n {formatMoney(r.monthlyCost)}\n </span>\n <StatusBadge status={r.state} label={resourceStateLabels[r.state]} />\n </button>\n ))}\n </div>\n ) : (\n <p className=\"rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary\">\n {t(\n 'adaptercloud.connections.noResources',\n 'No resources discovered yet. Start a discovery sync run.'\n )}\n </p>\n )}\n </section>\n </div>\n )}\n </DataState>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ConnectionDetailPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/ConnectionDetailPage.tsx"],"sourcesContent":["/**\n * Connection Detail Page\n * @module adaptercloud/pages/connections\n *\n * One connection (`adaConnection`) — its adapter, health, config, and the\n * resources it has discovered. Supports the validated health transition\n * (`adaSetConnectionStatus`), disable (`adaDisableConnection`), and starting a\n * sync run (`adaStartSyncRun`) against it.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ArrowLeft, Ban, Pencil, Play, RefreshCw, Server } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { DataState } from '../../components/DataState';\nimport { ConfirmDialog } from '../../components/ConfirmDialog';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport {\n useConnection,\n useDisableConnection,\n useSetConnectionStatus,\n useStartSyncRun,\n} from '../../hooks/useAdapterCloudApi';\nimport {\n authMethodLabels,\n connectionStatusLabels,\n resourceStateLabels,\n syncKindLabels,\n} from '../../utils/domain';\nimport { formatDate } from '../../utils/formatters';\nimport { formatMoney } from '../../utils/domain';\nimport type { AdaConnectionStatus, AdaSyncKind } from '../../types';\n\nconst TRANSITIONABLE: AdaConnectionStatus[] = ['CONNECTED', 'DEGRADED', 'ERROR', 'PENDING'];\nconst SYNC_KINDS: AdaSyncKind[] = ['DISCOVERY', 'RECONCILE', 'COST_INGEST', 'FULL'];\n\nexport function ConnectionDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = 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 const query = useConnection(id);\n const setStatus = useSetConnectionStatus();\n const disable = useDisableConnection();\n const startRun = useStartSyncRun();\n const conn = query.data;\n\n const [syncKind, setSyncKind] = useState<AdaSyncKind>('DISCOVERY');\n const [actionError, setActionError] = useState<string | null>(null);\n const [confirmDisableOpen, setConfirmDisableOpen] = useState(false);\n\n const onError = useCallback(\n (err: unknown) =>\n setActionError(err instanceof Error ? err.message : 'Action failed. Please try again.'),\n []\n );\n\n const handleSetStatus = useCallback(\n (newStatus: AdaConnectionStatus) => {\n if (!id) return;\n setActionError(null);\n setStatus.mutate({ id, status: newStatus }, { onError });\n },\n [id, setStatus, onError]\n );\n\n const handleDisable = useCallback(() => {\n if (!id) return;\n setActionError(null);\n disable.mutate(id, {\n onSuccess: () => setConfirmDisableOpen(false),\n onError,\n });\n }, [id, disable, onError]);\n\n const handleStartRun = useCallback(() => {\n if (!id) return;\n setActionError(null);\n startRun.mutate(\n { connectionId: id, kind: syncKind },\n { onSuccess: () => navigateTo('/sync-runs'), onError }\n );\n }, [id, syncKind, startRun, navigateTo, onError]);\n\n return (\n <PageLayout\n title={conn?.name ?? t('adaptercloud.connections.detailTitle', 'Connection')}\n description={conn?.adapter?.name}\n actions={\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\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 <ArrowLeft className=\"h-4 w-4\" />\n {t('adaptercloud.common.back', 'Back')}\n </button>\n {conn && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/connections/${conn.id}/edit`)}\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 <Pencil className=\"h-4 w-4\" />\n {t('adaptercloud.common.edit', 'Edit')}\n </button>\n )}\n </div>\n }\n >\n <DataState\n isLoading={query.isLoading}\n isError={query.isError}\n isEmpty={!query.isLoading && !conn}\n error={query.error}\n onRetry={() => void query.refetch()}\n emptyTitle={t('adaptercloud.connections.notFound', 'Connection not found')}\n >\n {conn && (\n <div className=\"space-y-6\">\n {actionError && (\n <p\n role=\"alert\"\n aria-live=\"polite\"\n className=\"rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\"\n >\n {actionError}\n </p>\n )}\n\n {/* Health + actions */}\n <GlassCard className=\"p-6\">\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <StatusBadge status={conn.status} />\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary\">\n {authMethodLabels[conn.authMethod]}\n </span>\n </div>\n\n <dl className=\"grid grid-cols-2 gap-4 text-sm sm:grid-cols-4\">\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.region', 'Region')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">{conn.region ?? '—'}</dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.environment', 'Environment')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.environment ?? '—'}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.resourceCount', 'Resources')}\n </dt>\n <dd className=\"mt-0.5 font-medium tabular-nums text-text-primary\">\n {conn.resourceCount}\n </dd>\n </div>\n <div>\n <dt className=\"text-text-secondary\">\n {t('adaptercloud.connections.lastSynced', 'Last synced')}\n </dt>\n <dd className=\"mt-0.5 font-medium text-text-primary\">\n {conn.lastSyncedAt ? formatDate(conn.lastSyncedAt) : '—'}\n </dd>\n </div>\n </dl>\n\n {conn.lastError && (\n <p className=\"mt-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {conn.lastError}\n </p>\n )}\n\n {/* Health transitions */}\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.connections.setHealth', 'Set health')}\n </h3>\n <div className=\"flex flex-wrap gap-2\">\n {TRANSITIONABLE.map((s) => (\n <button\n key={s}\n type=\"button\"\n disabled={setStatus.isPending || conn.status === s}\n onClick={() => handleSetStatus(s)}\n 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\"\n >\n {connectionStatusLabels[s]}\n </button>\n ))}\n {conn.status !== 'DISABLED' && (\n <button\n type=\"button\"\n disabled={disable.isPending}\n onClick={() => setConfirmDisableOpen(true)}\n 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\"\n >\n <Ban className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.connections.disable', 'Disable')}\n </button>\n )}\n </div>\n </div>\n\n {/* Start sync run */}\n <div className=\"mt-5 border-t border-border-subtle pt-5\">\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <RefreshCw className=\"h-4 w-4\" />\n {t('adaptercloud.connections.startSync', 'Start a sync run')}\n </h3>\n <div className=\"flex flex-wrap items-center gap-3\">\n <select\n value={syncKind}\n onChange={(e) => setSyncKind(e.target.value as AdaSyncKind)}\n aria-label={t('adaptercloud.connections.syncKind', 'Sync run kind')}\n 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)]\"\n >\n {SYNC_KINDS.map((k) => (\n <option key={k} value={k}>\n {syncKindLabels[k]}\n </option>\n ))}\n </select>\n <button\n type=\"button\"\n disabled={startRun.isPending}\n onClick={handleStartRun}\n 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\"\n >\n <Play className=\"h-4 w-4\" />\n {t('adaptercloud.connections.run', 'Run')}\n </button>\n </div>\n </div>\n </GlassCard>\n\n {/* Config */}\n {conn.config != null && (\n <GlassCard className=\"p-6\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">\n {t('adaptercloud.connections.config', 'Configuration')}\n </h3>\n <pre className=\"overflow-auto rounded-lg bg-bg-sunken p-4 text-xs text-text-secondary\">\n {JSON.stringify(conn.config, null, 2)}\n </pre>\n </GlassCard>\n )}\n\n {/* Resources */}\n <section>\n <div className=\"mb-3 flex items-center justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {t('adaptercloud.connections.discoveredResources', 'Discovered Resources')}\n </h3>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources?connectionId=${conn.id}`)}\n className=\"text-sm font-medium text-accent-blue hover:underline\"\n >\n {t('adaptercloud.common.viewAll', 'View all')}\n </button>\n </div>\n {conn.resources && conn.resources.length > 0 ? (\n <div className=\"divide-y divide-border rounded-xl border border-border-subtle bg-bg-surface\">\n {conn.resources.slice(0, 10).map((r) => (\n <button\n key={r.id}\n type=\"button\"\n onClick={() => navigateTo(`/resources/${r.id}`)}\n className=\"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-accent/50\"\n >\n <Server className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">{r.name}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">\n {r.resourceType}\n {r.region ? ` · ${r.region}` : ''}\n </p>\n </div>\n <span className=\"hidden text-xs text-text-secondary sm:inline\">\n {formatMoney(r.monthlyCost)}\n </span>\n <StatusBadge status={r.state} label={resourceStateLabels[r.state]} />\n </button>\n ))}\n </div>\n ) : (\n <p className=\"rounded-xl border border-border-subtle bg-bg-surface px-4 py-6 text-center text-sm text-text-secondary\">\n {t(\n 'adaptercloud.connections.noResources',\n 'No resources discovered yet. Start a discovery sync run.'\n )}\n </p>\n )}\n </section>\n </div>\n )}\n </DataState>\n\n <ConfirmDialog\n open={confirmDisableOpen}\n onOpenChange={setConfirmDisableOpen}\n title={t('adaptercloud.connections.disableTitle', 'Disable this connection?')}\n description={t(\n 'adaptercloud.connections.disablePrompt',\n 'Disabling stops discovery and sync runs against this target. You can re-enable it later by setting its health.'\n )}\n confirmLabel={t('adaptercloud.connections.disable', 'Disable')}\n cancelLabel={t('adaptercloud.common.cancel', 'Cancel')}\n onConfirm={handleDisable}\n isPending={disable.isPending}\n tone=\"danger\"\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -247,6 +247,8 @@ function x() {
247
247
  })
248
248
  ] }),
249
249
  M && /* @__PURE__ */ g("p", {
250
+ role: "alert",
251
+ "aria-live": "polite",
250
252
  className: "rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
251
253
  children: M
252
254
  }),