@burdenoff/microfe-adaptercloud 2026.706.1 → 2026.706.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/adaptercloud/AdapterCloudRoot.js +52 -44
  2. package/dist/adaptercloud/AdapterCloudRoot.js.map +1 -1
  3. package/dist/adaptercloud/AdapterCloudRoutes.js +22 -14
  4. package/dist/adaptercloud/AdapterCloudRoutes.js.map +1 -1
  5. package/dist/adaptercloud/components/ConfirmDialog.js +27 -0
  6. package/dist/adaptercloud/components/ConfirmDialog.js.map +1 -0
  7. package/dist/adaptercloud/components/DataState.js +1 -1
  8. package/dist/adaptercloud/components/DataState.js.map +1 -1
  9. package/dist/adaptercloud/components/viz/BarChart.js +32 -0
  10. package/dist/adaptercloud/components/viz/BarChart.js.map +1 -0
  11. package/dist/adaptercloud/components/viz/Sparkline.js +50 -0
  12. package/dist/adaptercloud/components/viz/Sparkline.js.map +1 -0
  13. package/dist/adaptercloud/components/viz/StackedBar.js +1 -0
  14. package/dist/adaptercloud/components/viz/TopologyGraph.js +96 -0
  15. package/dist/adaptercloud/components/viz/TopologyGraph.js.map +1 -0
  16. package/dist/adaptercloud/components/viz/index.js +4 -0
  17. package/dist/adaptercloud/hooks/useAdapterCloudApi.js +71 -34
  18. package/dist/adaptercloud/hooks/useAdapterCloudApi.js.map +1 -1
  19. package/dist/adaptercloud/pages/OverviewPage.js +159 -156
  20. package/dist/adaptercloud/pages/OverviewPage.js.map +1 -1
  21. package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js +179 -113
  22. package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js.map +1 -1
  23. package/dist/adaptercloud/pages/adapters/AdapterFormPage.js +263 -179
  24. package/dist/adaptercloud/pages/adapters/AdapterFormPage.js.map +1 -1
  25. package/dist/adaptercloud/pages/adapters/AdaptersListPage.js +2 -0
  26. package/dist/adaptercloud/pages/adapters/AdaptersListPage.js.map +1 -1
  27. package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js +141 -124
  28. package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js.map +1 -1
  29. package/dist/adaptercloud/pages/connections/ConnectionFormPage.js +2 -0
  30. package/dist/adaptercloud/pages/connections/ConnectionFormPage.js.map +1 -1
  31. package/dist/adaptercloud/pages/connections/ConnectionsListPage.js +158 -93
  32. package/dist/adaptercloud/pages/connections/ConnectionsListPage.js.map +1 -1
  33. package/dist/adaptercloud/pages/costs/CostsPage.js +183 -109
  34. package/dist/adaptercloud/pages/costs/CostsPage.js.map +1 -1
  35. package/dist/adaptercloud/pages/drift/DriftListPage.js +172 -71
  36. package/dist/adaptercloud/pages/drift/DriftListPage.js.map +1 -1
  37. package/dist/adaptercloud/pages/policies/PoliciesListPage.js +179 -96
  38. package/dist/adaptercloud/pages/policies/PoliciesListPage.js.map +1 -1
  39. package/dist/adaptercloud/pages/policies/PolicyDetailPage.js +109 -91
  40. package/dist/adaptercloud/pages/policies/PolicyDetailPage.js.map +1 -1
  41. package/dist/adaptercloud/pages/policies/PolicyFormPage.js +211 -184
  42. package/dist/adaptercloud/pages/policies/PolicyFormPage.js.map +1 -1
  43. package/dist/adaptercloud/pages/resources/ResourceDetailPage.js +183 -127
  44. package/dist/adaptercloud/pages/resources/ResourceDetailPage.js.map +1 -1
  45. package/dist/adaptercloud/pages/resources/ResourcesListPage.js +121 -84
  46. package/dist/adaptercloud/pages/resources/ResourcesListPage.js.map +1 -1
  47. package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js +236 -153
  48. package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js.map +1 -1
  49. package/dist/adaptercloud/pages/topology/TopologyPage.js +397 -0
  50. package/dist/adaptercloud/pages/topology/TopologyPage.js.map +1 -0
  51. package/dist/adaptercloud/pages/violations/ViolationsListPage.js +192 -131
  52. package/dist/adaptercloud/pages/violations/ViolationsListPage.js.map +1 -1
  53. package/package.json +1 -1
@@ -4,11 +4,11 @@ import { AdapterCloudRoutes as n } from "./AdapterCloudRoutes.js";
4
4
  import { useCallback as r, useEffect as i } from "react";
5
5
  import { MutationCache as a, QueryClient as o, QueryClientProvider as s } from "@tanstack/react-query";
6
6
  import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
- import { Activity as l, Boxes as u, Cable as d, DollarSign as f, GitCompareArrows as p, LayoutDashboard as m, ScrollText as h, Server as g, ShieldAlert as _ } from "lucide-react";
8
- import { jsx as v } from "react/jsx-runtime";
9
- import { FeatureFlagProvider as y } from "@burdenoff/fe-libs/shared/feature-flags";
7
+ import { Activity as l, Boxes as u, Cable as d, DollarSign as f, GitCompareArrows as p, LayoutDashboard as m, ScrollText as h, Server as g, ShieldAlert as _, Waypoints as v } from "lucide-react";
8
+ import { jsx as y } from "react/jsx-runtime";
9
+ import { FeatureFlagProvider as b } from "@burdenoff/fe-libs/shared/feature-flags";
10
10
  //#region src/adaptercloud/AdapterCloudRoot.tsx
11
- var b = new o({
11
+ var x = new o({
12
12
  mutationCache: new a({ onError: (e) => {
13
13
  t.error("Something went wrong", e instanceof Error ? e.message : "Please try again.");
14
14
  } }),
@@ -16,112 +16,120 @@ var b = new o({
16
16
  staleTime: 300 * 1e3,
17
17
  retry: 1
18
18
  } }
19
- }), x = (t) => {
20
- let { registerNavItems: a, registerFooterItems: o, basePath: x = "/" } = t, { t: S } = c(), C = r((e, t) => {
21
- let n = S(e);
19
+ }), S = (t) => {
20
+ let { registerNavItems: a, registerFooterItems: o, basePath: S = "/" } = t, { t: C } = c(), w = r((e, t) => {
21
+ let n = C(e);
22
22
  return n === e ? t : n;
23
- }, [S]), w = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
23
+ }, [C]), T = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
24
24
  return i(() => {
25
25
  if (a) return a([
26
26
  {
27
27
  id: "adaptercloud-overview",
28
- label: C("adaptercloud.nav.overview", "Overview"),
29
- path: w(x, ""),
30
- icon: /* @__PURE__ */ v(m, { size: 20 }),
28
+ label: w("adaptercloud.nav.overview", "Overview"),
29
+ path: T(S, ""),
30
+ icon: /* @__PURE__ */ y(m, { size: 20 }),
31
31
  order: 1,
32
32
  group: "main"
33
33
  },
34
34
  {
35
35
  id: "adaptercloud-adapters",
36
- label: C("adaptercloud.nav.adapters", "Adapters"),
37
- path: w(x, "adapters"),
38
- icon: /* @__PURE__ */ v(u, { size: 20 }),
36
+ label: w("adaptercloud.nav.adapters", "Adapters"),
37
+ path: T(S, "adapters"),
38
+ icon: /* @__PURE__ */ y(u, { size: 20 }),
39
39
  order: 10,
40
40
  group: "fabric"
41
41
  },
42
42
  {
43
43
  id: "adaptercloud-connections",
44
- label: C("adaptercloud.nav.connections", "Connections"),
45
- path: w(x, "connections"),
46
- icon: /* @__PURE__ */ v(d, { size: 20 }),
44
+ label: w("adaptercloud.nav.connections", "Connections"),
45
+ path: T(S, "connections"),
46
+ icon: /* @__PURE__ */ y(d, { size: 20 }),
47
47
  order: 11,
48
48
  group: "fabric"
49
49
  },
50
50
  {
51
51
  id: "adaptercloud-resources",
52
- label: C("adaptercloud.nav.resources", "Resources"),
53
- path: w(x, "resources"),
54
- icon: /* @__PURE__ */ v(g, { size: 20 }),
52
+ label: w("adaptercloud.nav.resources", "Resources"),
53
+ path: T(S, "resources"),
54
+ icon: /* @__PURE__ */ y(g, { size: 20 }),
55
55
  order: 12,
56
56
  group: "fabric"
57
57
  },
58
+ {
59
+ id: "adaptercloud-topology",
60
+ label: w("adaptercloud.nav.topology", "Topology"),
61
+ path: T(S, "topology"),
62
+ icon: /* @__PURE__ */ y(v, { size: 20 }),
63
+ order: 13,
64
+ group: "fabric"
65
+ },
58
66
  {
59
67
  id: "adaptercloud-policies",
60
- label: C("adaptercloud.nav.policies", "Policies"),
61
- path: w(x, "policies"),
62
- icon: /* @__PURE__ */ v(h, { size: 20 }),
68
+ label: w("adaptercloud.nav.policies", "Policies"),
69
+ path: T(S, "policies"),
70
+ icon: /* @__PURE__ */ y(h, { size: 20 }),
63
71
  order: 20,
64
72
  group: "governance"
65
73
  },
66
74
  {
67
75
  id: "adaptercloud-violations",
68
- label: C("adaptercloud.nav.violations", "Violations"),
69
- path: w(x, "violations"),
70
- icon: /* @__PURE__ */ v(_, { size: 20 }),
76
+ label: w("adaptercloud.nav.violations", "Violations"),
77
+ path: T(S, "violations"),
78
+ icon: /* @__PURE__ */ y(_, { size: 20 }),
71
79
  order: 21,
72
80
  group: "governance"
73
81
  },
74
82
  {
75
83
  id: "adaptercloud-drift",
76
- label: C("adaptercloud.nav.drift", "Drift"),
77
- path: w(x, "drift"),
78
- icon: /* @__PURE__ */ v(p, { size: 20 }),
84
+ label: w("adaptercloud.nav.drift", "Drift"),
85
+ path: T(S, "drift"),
86
+ icon: /* @__PURE__ */ y(p, { size: 20 }),
79
87
  order: 22,
80
88
  group: "governance"
81
89
  },
82
90
  {
83
91
  id: "adaptercloud-sync-runs",
84
- label: C("adaptercloud.nav.syncRuns", "Sync Runs"),
85
- path: w(x, "sync-runs"),
86
- icon: /* @__PURE__ */ v(l, { size: 20 }),
92
+ label: w("adaptercloud.nav.syncRuns", "Sync Runs"),
93
+ path: T(S, "sync-runs"),
94
+ icon: /* @__PURE__ */ y(l, { size: 20 }),
87
95
  order: 30,
88
96
  group: "operations"
89
97
  },
90
98
  {
91
99
  id: "adaptercloud-costs",
92
- label: C("adaptercloud.nav.finops", "FinOps"),
93
- path: w(x, "costs"),
94
- icon: /* @__PURE__ */ v(f, { size: 20 }),
100
+ label: w("adaptercloud.nav.finops", "FinOps"),
101
+ path: T(S, "costs"),
102
+ icon: /* @__PURE__ */ y(f, { size: 20 }),
95
103
  order: 31,
96
104
  group: "operations"
97
105
  }
98
106
  ]);
99
107
  }, [
100
108
  a,
101
- x,
102
- C
109
+ S,
110
+ w
103
111
  ]), i(() => {
104
112
  if (o) return o([{
105
113
  id: "adaptercloud-status",
106
- label: C("adaptercloud.footer.ready", "AdapterCloud Ready"),
114
+ label: w("adaptercloud.footer.ready", "AdapterCloud Ready"),
107
115
  type: "status",
108
116
  order: 10,
109
117
  section: "left"
110
118
  }]);
111
- }, [o, C]), /* @__PURE__ */ v(s, {
112
- client: b,
113
- children: /* @__PURE__ */ v(y, {
119
+ }, [o, w]), /* @__PURE__ */ y(s, {
120
+ client: x,
121
+ children: /* @__PURE__ */ y(b, {
114
122
  workspaceId: null,
115
123
  gateway: "global",
116
124
  defaultEnabled: !0,
117
- children: /* @__PURE__ */ v(e, {
125
+ children: /* @__PURE__ */ y(e, {
118
126
  ...t,
119
- children: /* @__PURE__ */ v(n, {})
127
+ children: /* @__PURE__ */ y(n, {})
120
128
  })
121
129
  })
122
130
  });
123
131
  };
124
132
  //#endregion
125
- export { x as AdapterCloudRoot };
133
+ export { S as AdapterCloudRoot };
126
134
 
127
135
  //# sourceMappingURL=AdapterCloudRoot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdapterCloudRoot.js","names":[],"sources":["../../src/adaptercloud/AdapterCloudRoot.tsx"],"sourcesContent":["/**\n * AdapterCloud Root Component\n * @module adaptercloud\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useEffect } from 'react';\nimport { MutationCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n LayoutDashboard,\n Boxes,\n Cable,\n Server,\n ScrollText,\n ShieldAlert,\n GitCompareArrows,\n Activity,\n DollarSign,\n} from 'lucide-react';\nimport { AdapterCloudProvider } from './context/AdapterCloudContext';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { AdapterCloudRoutes } from './AdapterCloudRoutes';\nimport { notify } from './lib/toast';\nimport type { AdapterCloudRootProps, NavItem } from './types';\n\n// Create a query client for this microfrontend. A shared MutationCache surfaces\n// every failed write as a toast, so no mutation can fail silently with only\n// inline error state (the <Toaster> is owned by the host app shell).\nconst queryClient = new QueryClient({\n mutationCache: new MutationCache({\n onError: (error) => {\n notify.error(\n 'Something went wrong',\n error instanceof Error ? error.message : 'Please try again.'\n );\n },\n }),\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n },\n },\n});\n\nexport const AdapterCloudRoot: FC<AdapterCloudRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\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 // Helper to join paths correctly\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with shell on mount\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n // Overview\n {\n id: 'adaptercloud-overview',\n label: t('adaptercloud.nav.overview', 'Overview'),\n path: joinPath(basePath, ''),\n icon: <LayoutDashboard size={20} />,\n order: 1,\n group: 'main',\n },\n\n // Fabric\n {\n id: 'adaptercloud-adapters',\n label: t('adaptercloud.nav.adapters', 'Adapters'),\n path: joinPath(basePath, 'adapters'),\n icon: <Boxes size={20} />,\n order: 10,\n group: 'fabric',\n },\n {\n id: 'adaptercloud-connections',\n label: t('adaptercloud.nav.connections', 'Connections'),\n path: joinPath(basePath, 'connections'),\n icon: <Cable size={20} />,\n order: 11,\n group: 'fabric',\n },\n {\n id: 'adaptercloud-resources',\n label: t('adaptercloud.nav.resources', 'Resources'),\n path: joinPath(basePath, 'resources'),\n icon: <Server size={20} />,\n order: 12,\n group: 'fabric',\n },\n\n // Governance\n {\n id: 'adaptercloud-policies',\n label: t('adaptercloud.nav.policies', 'Policies'),\n path: joinPath(basePath, 'policies'),\n icon: <ScrollText size={20} />,\n order: 20,\n group: 'governance',\n },\n {\n id: 'adaptercloud-violations',\n label: t('adaptercloud.nav.violations', 'Violations'),\n path: joinPath(basePath, 'violations'),\n icon: <ShieldAlert size={20} />,\n order: 21,\n group: 'governance',\n },\n {\n id: 'adaptercloud-drift',\n label: t('adaptercloud.nav.drift', 'Drift'),\n path: joinPath(basePath, 'drift'),\n icon: <GitCompareArrows size={20} />,\n order: 22,\n group: 'governance',\n },\n\n // Operations\n {\n id: 'adaptercloud-sync-runs',\n label: t('adaptercloud.nav.syncRuns', 'Sync Runs'),\n path: joinPath(basePath, 'sync-runs'),\n icon: <Activity size={20} />,\n order: 30,\n group: 'operations',\n },\n {\n id: 'adaptercloud-costs',\n label: t('adaptercloud.nav.finops', 'FinOps'),\n path: joinPath(basePath, 'costs'),\n icon: <DollarSign size={20} />,\n order: 31,\n group: 'operations',\n },\n ];\n\n const cleanup = registerNavItems(navItems);\n return cleanup;\n }, [registerNavItems, basePath, t]);\n\n // Register footer items\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'adaptercloud-status',\n label: t('adaptercloud.footer.ready', 'AdapterCloud Ready'),\n type: 'status' as const,\n order: 10,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, t]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <AdapterCloudProvider {...props}>\n <AdapterCloudRoutes />\n </AdapterCloudProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AdapterCloudRoot.js","names":[],"sources":["../../src/adaptercloud/AdapterCloudRoot.tsx"],"sourcesContent":["/**\n * AdapterCloud Root Component\n * @module adaptercloud\n */\n\nimport type { FC } from 'react';\nimport { useCallback, useEffect } from 'react';\nimport { MutationCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n LayoutDashboard,\n Boxes,\n Cable,\n Server,\n Waypoints,\n ScrollText,\n ShieldAlert,\n GitCompareArrows,\n Activity,\n DollarSign,\n} from 'lucide-react';\nimport { AdapterCloudProvider } from './context/AdapterCloudContext';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { AdapterCloudRoutes } from './AdapterCloudRoutes';\nimport { notify } from './lib/toast';\nimport type { AdapterCloudRootProps, NavItem } from './types';\n\n// Create a query client for this microfrontend. A shared MutationCache surfaces\n// every failed write as a toast, so no mutation can fail silently with only\n// inline error state (the <Toaster> is owned by the host app shell).\nconst queryClient = new QueryClient({\n mutationCache: new MutationCache({\n onError: (error) => {\n notify.error(\n 'Something went wrong',\n error instanceof Error ? error.message : 'Please try again.'\n );\n },\n }),\n defaultOptions: {\n queries: {\n staleTime: 5 * 60 * 1000,\n retry: 1,\n },\n },\n});\n\nexport const AdapterCloudRoot: FC<AdapterCloudRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/' } = props;\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 // Helper to join paths correctly\n const joinPath = (base: string, path: string): string => {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n };\n\n // Register navigation items with shell on mount\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n // Overview\n {\n id: 'adaptercloud-overview',\n label: t('adaptercloud.nav.overview', 'Overview'),\n path: joinPath(basePath, ''),\n icon: <LayoutDashboard size={20} />,\n order: 1,\n group: 'main',\n },\n\n // Fabric\n {\n id: 'adaptercloud-adapters',\n label: t('adaptercloud.nav.adapters', 'Adapters'),\n path: joinPath(basePath, 'adapters'),\n icon: <Boxes size={20} />,\n order: 10,\n group: 'fabric',\n },\n {\n id: 'adaptercloud-connections',\n label: t('adaptercloud.nav.connections', 'Connections'),\n path: joinPath(basePath, 'connections'),\n icon: <Cable size={20} />,\n order: 11,\n group: 'fabric',\n },\n {\n id: 'adaptercloud-resources',\n label: t('adaptercloud.nav.resources', 'Resources'),\n path: joinPath(basePath, 'resources'),\n icon: <Server size={20} />,\n order: 12,\n group: 'fabric',\n },\n {\n id: 'adaptercloud-topology',\n label: t('adaptercloud.nav.topology', 'Topology'),\n path: joinPath(basePath, 'topology'),\n icon: <Waypoints size={20} />,\n order: 13,\n group: 'fabric',\n },\n\n // Governance\n {\n id: 'adaptercloud-policies',\n label: t('adaptercloud.nav.policies', 'Policies'),\n path: joinPath(basePath, 'policies'),\n icon: <ScrollText size={20} />,\n order: 20,\n group: 'governance',\n },\n {\n id: 'adaptercloud-violations',\n label: t('adaptercloud.nav.violations', 'Violations'),\n path: joinPath(basePath, 'violations'),\n icon: <ShieldAlert size={20} />,\n order: 21,\n group: 'governance',\n },\n {\n id: 'adaptercloud-drift',\n label: t('adaptercloud.nav.drift', 'Drift'),\n path: joinPath(basePath, 'drift'),\n icon: <GitCompareArrows size={20} />,\n order: 22,\n group: 'governance',\n },\n\n // Operations\n {\n id: 'adaptercloud-sync-runs',\n label: t('adaptercloud.nav.syncRuns', 'Sync Runs'),\n path: joinPath(basePath, 'sync-runs'),\n icon: <Activity size={20} />,\n order: 30,\n group: 'operations',\n },\n {\n id: 'adaptercloud-costs',\n label: t('adaptercloud.nav.finops', 'FinOps'),\n path: joinPath(basePath, 'costs'),\n icon: <DollarSign size={20} />,\n order: 31,\n group: 'operations',\n },\n ];\n\n const cleanup = registerNavItems(navItems);\n return cleanup;\n }, [registerNavItems, basePath, t]);\n\n // Register footer items\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'adaptercloud-status',\n label: t('adaptercloud.footer.ready', 'AdapterCloud Ready'),\n type: 'status' as const,\n order: 10,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems, t]);\n\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <AdapterCloudProvider {...props}>\n <AdapterCloudRoutes />\n </AdapterCloudProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n"],"mappings":"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"}
@@ -4,15 +4,15 @@ import { Suspense as n, lazy as r } from "react";
4
4
  import { Navigate as i, Route as a, Routes as o, useLocation as s } from "react-router-dom";
5
5
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
6
6
  //#region src/adaptercloud/AdapterCloudRoutes.tsx
7
- var u = r(() => import("./pages/adapters/AdaptersListPage.js").then((e) => ({ default: e.AdaptersListPage }))), d = r(() => import("./pages/adapters/AdapterDetailPage.js").then((e) => ({ default: e.AdapterDetailPage }))), f = r(() => import("./pages/adapters/AdapterFormPage.js").then((e) => ({ default: e.AdapterFormPage }))), p = r(() => import("./pages/connections/ConnectionsListPage.js").then((e) => ({ default: e.ConnectionsListPage }))), m = r(() => import("./pages/connections/ConnectionDetailPage.js").then((e) => ({ default: e.ConnectionDetailPage }))), h = r(() => import("./pages/connections/ConnectionFormPage.js").then((e) => ({ default: e.ConnectionFormPage }))), g = r(() => import("./pages/resources/ResourcesListPage.js").then((e) => ({ default: e.ResourcesListPage }))), _ = r(() => import("./pages/resources/ResourceDetailPage.js").then((e) => ({ default: e.ResourceDetailPage }))), v = r(() => import("./pages/policies/PoliciesListPage.js").then((e) => ({ default: e.PoliciesListPage }))), y = r(() => import("./pages/policies/PolicyDetailPage.js").then((e) => ({ default: e.PolicyDetailPage }))), b = r(() => import("./pages/policies/PolicyFormPage.js").then((e) => ({ default: e.PolicyFormPage }))), x = r(() => import("./pages/violations/ViolationsListPage.js").then((e) => ({ default: e.ViolationsListPage }))), S = r(() => import("./pages/drift/DriftListPage.js").then((e) => ({ default: e.DriftListPage }))), C = r(() => import("./pages/sync-runs/SyncRunsListPage.js").then((e) => ({ default: e.SyncRunsListPage }))), w = r(() => import("./pages/costs/CostsPage.js").then((e) => ({ default: e.CostsPage }))), T = () => /* @__PURE__ */ c("div", {
7
+ var u = r(() => import("./pages/adapters/AdaptersListPage.js").then((e) => ({ default: e.AdaptersListPage }))), d = r(() => import("./pages/adapters/AdapterDetailPage.js").then((e) => ({ default: e.AdapterDetailPage }))), f = r(() => import("./pages/adapters/AdapterFormPage.js").then((e) => ({ default: e.AdapterFormPage }))), p = r(() => import("./pages/connections/ConnectionsListPage.js").then((e) => ({ default: e.ConnectionsListPage }))), m = r(() => import("./pages/connections/ConnectionDetailPage.js").then((e) => ({ default: e.ConnectionDetailPage }))), h = r(() => import("./pages/connections/ConnectionFormPage.js").then((e) => ({ default: e.ConnectionFormPage }))), g = r(() => import("./pages/resources/ResourcesListPage.js").then((e) => ({ default: e.ResourcesListPage }))), _ = r(() => import("./pages/resources/ResourceDetailPage.js").then((e) => ({ default: e.ResourceDetailPage }))), v = r(() => import("./pages/topology/TopologyPage.js").then((e) => ({ default: e.TopologyPage }))), y = r(() => import("./pages/policies/PoliciesListPage.js").then((e) => ({ default: e.PoliciesListPage }))), b = r(() => import("./pages/policies/PolicyDetailPage.js").then((e) => ({ default: e.PolicyDetailPage }))), x = r(() => import("./pages/policies/PolicyFormPage.js").then((e) => ({ default: e.PolicyFormPage }))), S = r(() => import("./pages/violations/ViolationsListPage.js").then((e) => ({ default: e.ViolationsListPage }))), C = r(() => import("./pages/drift/DriftListPage.js").then((e) => ({ default: e.DriftListPage }))), w = r(() => import("./pages/sync-runs/SyncRunsListPage.js").then((e) => ({ default: e.SyncRunsListPage }))), T = r(() => import("./pages/costs/CostsPage.js").then((e) => ({ default: e.CostsPage }))), E = () => /* @__PURE__ */ c("div", {
8
8
  className: "flex min-h-[400px] items-center justify-center",
9
- children: /* @__PURE__ */ c("div", { className: "h-8 w-8 animate-spin rounded-full border-b-2 border-primary" })
10
- }), E = () => {
11
- let { basePath: r, isStandalone: E } = e(), D = s(), O = r === "/" ? "" : (r ?? "").replace(/\/$/, "");
12
- return O && !E && !(D.pathname === O || D.pathname.startsWith(O + "/")) ? null : /* @__PURE__ */ c("div", {
9
+ children: /* @__PURE__ */ c("div", { className: "h-8 w-8 animate-spin rounded-full border-b-2 border-accent-blue" })
10
+ }), D = () => {
11
+ let { basePath: r, isStandalone: D } = e(), O = s(), k = r === "/" ? "" : (r ?? "").replace(/\/$/, "");
12
+ return k && !D && !(O.pathname === k || O.pathname.startsWith(k + "/")) ? null : /* @__PURE__ */ c("div", {
13
13
  className: "flex min-h-full flex-col",
14
14
  children: /* @__PURE__ */ c(n, {
15
- fallback: /* @__PURE__ */ c(T, {}),
15
+ fallback: /* @__PURE__ */ c(E, {}),
16
16
  children: /* @__PURE__ */ l(o, { children: [
17
17
  /* @__PURE__ */ c(a, {
18
18
  index: !0,
@@ -59,33 +59,41 @@ var u = r(() => import("./pages/adapters/AdaptersListPage.js").then((e) => ({ de
59
59
  element: /* @__PURE__ */ c(_, {})
60
60
  }),
61
61
  /* @__PURE__ */ c(a, {
62
- path: "policies",
62
+ path: "topology",
63
63
  element: /* @__PURE__ */ c(v, {})
64
64
  }),
65
+ /* @__PURE__ */ c(a, {
66
+ path: "policies",
67
+ element: /* @__PURE__ */ c(y, {})
68
+ }),
65
69
  /* @__PURE__ */ c(a, {
66
70
  path: "policies/new",
67
- element: /* @__PURE__ */ c(b, {})
71
+ element: /* @__PURE__ */ c(x, {})
68
72
  }),
69
73
  /* @__PURE__ */ c(a, {
70
74
  path: "policies/:id",
71
- element: /* @__PURE__ */ c(y, {})
75
+ element: /* @__PURE__ */ c(b, {})
72
76
  }),
73
77
  /* @__PURE__ */ c(a, {
74
- path: "violations",
78
+ path: "policies/:id/edit",
75
79
  element: /* @__PURE__ */ c(x, {})
76
80
  }),
77
81
  /* @__PURE__ */ c(a, {
78
- path: "drift",
82
+ path: "violations",
79
83
  element: /* @__PURE__ */ c(S, {})
80
84
  }),
81
85
  /* @__PURE__ */ c(a, {
82
- path: "sync-runs",
86
+ path: "drift",
83
87
  element: /* @__PURE__ */ c(C, {})
84
88
  }),
85
89
  /* @__PURE__ */ c(a, {
86
- path: "costs",
90
+ path: "sync-runs",
87
91
  element: /* @__PURE__ */ c(w, {})
88
92
  }),
93
+ /* @__PURE__ */ c(a, {
94
+ path: "costs",
95
+ element: /* @__PURE__ */ c(T, {})
96
+ }),
89
97
  /* @__PURE__ */ c(a, {
90
98
  path: "*",
91
99
  element: /* @__PURE__ */ c(i, {
@@ -98,6 +106,6 @@ var u = r(() => import("./pages/adapters/AdaptersListPage.js").then((e) => ({ de
98
106
  });
99
107
  };
100
108
  //#endregion
101
- export { E as AdapterCloudRoutes };
109
+ export { D as AdapterCloudRoutes };
102
110
 
103
111
  //# sourceMappingURL=AdapterCloudRoutes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdapterCloudRoutes.js","names":[],"sources":["../../src/adaptercloud/AdapterCloudRoutes.tsx"],"sourcesContent":["/**\n * AdapterCloud Routes\n * @module adaptercloud\n *\n * Domain routing for the AdapterCloud (InfraVerse) control plane: an overview\n * landing page plus fabric (adapters / connections / resources), governance\n * (policies / violations / drift) and operations (sync runs / FinOps).\n */\n\nimport { type FC, lazy, Suspense } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router-dom';\nimport { useAdapterCloud } from './context/AdapterCloudContext';\n\n// Eager — overview landing page\nimport { OverviewPage } from './pages/OverviewPage';\n\n// Fabric — adapters\nconst AdaptersListPage = lazy(() =>\n import('./pages/adapters/AdaptersListPage').then((m) => ({ default: m.AdaptersListPage }))\n);\nconst AdapterDetailPage = lazy(() =>\n import('./pages/adapters/AdapterDetailPage').then((m) => ({ default: m.AdapterDetailPage }))\n);\nconst AdapterFormPage = lazy(() =>\n import('./pages/adapters/AdapterFormPage').then((m) => ({ default: m.AdapterFormPage }))\n);\n\n// Fabric — connections\nconst ConnectionsListPage = lazy(() =>\n import('./pages/connections/ConnectionsListPage').then((m) => ({\n default: m.ConnectionsListPage,\n }))\n);\nconst ConnectionDetailPage = lazy(() =>\n import('./pages/connections/ConnectionDetailPage').then((m) => ({\n default: m.ConnectionDetailPage,\n }))\n);\nconst ConnectionFormPage = lazy(() =>\n import('./pages/connections/ConnectionFormPage').then((m) => ({\n default: m.ConnectionFormPage,\n }))\n);\n\n// Fabric — resources\nconst ResourcesListPage = lazy(() =>\n import('./pages/resources/ResourcesListPage').then((m) => ({ default: m.ResourcesListPage }))\n);\nconst ResourceDetailPage = lazy(() =>\n import('./pages/resources/ResourceDetailPage').then((m) => ({ default: m.ResourceDetailPage }))\n);\n\n// Governance — policies\nconst PoliciesListPage = lazy(() =>\n import('./pages/policies/PoliciesListPage').then((m) => ({ default: m.PoliciesListPage }))\n);\nconst PolicyDetailPage = lazy(() =>\n import('./pages/policies/PolicyDetailPage').then((m) => ({ default: m.PolicyDetailPage }))\n);\nconst PolicyFormPage = lazy(() =>\n import('./pages/policies/PolicyFormPage').then((m) => ({ default: m.PolicyFormPage }))\n);\n\n// Governance — violations & drift\nconst ViolationsListPage = lazy(() =>\n import('./pages/violations/ViolationsListPage').then((m) => ({ default: m.ViolationsListPage }))\n);\nconst DriftListPage = lazy(() =>\n import('./pages/drift/DriftListPage').then((m) => ({ default: m.DriftListPage }))\n);\n\n// Operations — sync runs & costs\nconst SyncRunsListPage = lazy(() =>\n import('./pages/sync-runs/SyncRunsListPage').then((m) => ({ default: m.SyncRunsListPage }))\n);\nconst CostsPage = lazy(() =>\n import('./pages/costs/CostsPage').then((m) => ({ default: m.CostsPage }))\n);\n\n// Loading fallback component\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-b-2 border-primary\" />\n </div>\n);\n\nexport const AdapterCloudRoutes: FC = () => {\n const { basePath, isStandalone } = useAdapterCloud();\n const location = useLocation();\n\n // Normalize base path\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n // Guard: Only render if path matches basePath (when integrated)\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n {/* Overview — eager loaded */}\n <Route index element={<OverviewPage />} />\n\n {/* Adapters */}\n <Route path=\"adapters\" element={<AdaptersListPage />} />\n <Route path=\"adapters/new\" element={<AdapterFormPage />} />\n <Route path=\"adapters/:id\" element={<AdapterDetailPage />} />\n <Route path=\"adapters/:id/edit\" element={<AdapterFormPage />} />\n\n {/* Connections */}\n <Route path=\"connections\" element={<ConnectionsListPage />} />\n <Route path=\"connections/new\" element={<ConnectionFormPage />} />\n <Route path=\"connections/:id\" element={<ConnectionDetailPage />} />\n <Route path=\"connections/:id/edit\" element={<ConnectionFormPage />} />\n\n {/* Resources */}\n <Route path=\"resources\" element={<ResourcesListPage />} />\n <Route path=\"resources/:id\" element={<ResourceDetailPage />} />\n\n {/* Policies */}\n <Route path=\"policies\" element={<PoliciesListPage />} />\n <Route path=\"policies/new\" element={<PolicyFormPage />} />\n <Route path=\"policies/:id\" element={<PolicyDetailPage />} />\n\n {/* Governance */}\n <Route path=\"violations\" element={<ViolationsListPage />} />\n <Route path=\"drift\" element={<DriftListPage />} />\n\n {/* Operations */}\n <Route path=\"sync-runs\" element={<SyncRunsListPage />} />\n <Route path=\"costs\" element={<CostsPage />} />\n\n {/* Fallback */}\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":";;;;;;AAiBA,IAAM,IAAmB,QACvB,OAAO,wCAAqC,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAC3F,EACK,IAAoB,QACxB,OAAO,yCAAsC,MAAM,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAC7F,EACK,IAAkB,QACtB,OAAO,uCAAoC,MAAM,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,CACzF,EAGK,IAAsB,QAC1B,OAAO,8CAA2C,MAAM,OAAO,EAC7D,SAAS,EAAE,qBACZ,EAAE,CACJ,EACK,IAAuB,QAC3B,OAAO,+CAA4C,MAAM,OAAO,EAC9D,SAAS,EAAE,sBACZ,EAAE,CACJ,EACK,IAAqB,QACzB,OAAO,6CAA0C,MAAM,OAAO,EAC5D,SAAS,EAAE,oBACZ,EAAE,CACJ,EAGK,IAAoB,QACxB,OAAO,0CAAuC,MAAM,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAC9F,EACK,IAAqB,QACzB,OAAO,2CAAwC,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAChG,EAGK,IAAmB,QACvB,OAAO,wCAAqC,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAC3F,EACK,IAAmB,QACvB,OAAO,wCAAqC,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAC3F,EACK,IAAiB,QACrB,OAAO,sCAAmC,MAAM,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,CACvF,EAGK,IAAqB,QACzB,OAAO,4CAAyC,MAAM,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,CACjG,EACK,IAAgB,QACpB,OAAO,kCAA+B,MAAM,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,CAClF,EAGK,IAAmB,QACvB,OAAO,yCAAsC,MAAM,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAC5F,EACK,IAAY,QAChB,OAAO,8BAA2B,MAAM,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAC1E,EAGK,UACJ,kBAAC,OAAD;CAAK,WAAU;WACb,kBAAC,OAAD,EAAK,WAAU,+DAAgE,CAAA;CAC3E,CAAA,EAGK,UAA+B;CAC1C,IAAM,EAAE,aAAU,oBAAiB,GAAiB,EAC9C,IAAW,GAAa,EAGxB,IAAqB,MAAa,MAAM,MAAM,KAAY,IAAI,QAAQ,OAAO,GAAG;AAatF,QAVI,KAAsB,CAAC,KAKrB,EAHF,EAAS,aAAa,KACtB,EAAS,SAAS,WAAW,IAAqB,IAAI,IAG/C,OAKT,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAU,UAAU,kBAAC,GAAD,EAAc,CAAA;aAChC,kBAAC,GAAD,EAAA,UAAA;IAEE,kBAAC,GAAD;KAAO,OAAA;KAAM,SAAS,kBAAC,GAAD,EAAgB,CAAA;KAAI,CAAA;IAG1C,kBAAC,GAAD;KAAO,MAAK;KAAW,SAAS,kBAAC,GAAD,EAAoB,CAAA;KAAI,CAAA;IACxD,kBAAC,GAAD;KAAO,MAAK;KAAe,SAAS,kBAAC,GAAD,EAAmB,CAAA;KAAI,CAAA;IAC3D,kBAAC,GAAD;KAAO,MAAK;KAAe,SAAS,kBAAC,GAAD,EAAqB,CAAA;KAAI,CAAA;IAC7D,kBAAC,GAAD;KAAO,MAAK;KAAoB,SAAS,kBAAC,GAAD,EAAmB,CAAA;KAAI,CAAA;IAGhE,kBAAC,GAAD;KAAO,MAAK;KAAc,SAAS,kBAAC,GAAD,EAAuB,CAAA;KAAI,CAAA;IAC9D,kBAAC,GAAD;KAAO,MAAK;KAAkB,SAAS,kBAAC,GAAD,EAAsB,CAAA;KAAI,CAAA;IACjE,kBAAC,GAAD;KAAO,MAAK;KAAkB,SAAS,kBAAC,GAAD,EAAwB,CAAA;KAAI,CAAA;IACnE,kBAAC,GAAD;KAAO,MAAK;KAAuB,SAAS,kBAAC,GAAD,EAAsB,CAAA;KAAI,CAAA;IAGtE,kBAAC,GAAD;KAAO,MAAK;KAAY,SAAS,kBAAC,GAAD,EAAqB,CAAA;KAAI,CAAA;IAC1D,kBAAC,GAAD;KAAO,MAAK;KAAgB,SAAS,kBAAC,GAAD,EAAsB,CAAA;KAAI,CAAA;IAG/D,kBAAC,GAAD;KAAO,MAAK;KAAW,SAAS,kBAAC,GAAD,EAAoB,CAAA;KAAI,CAAA;IACxD,kBAAC,GAAD;KAAO,MAAK;KAAe,SAAS,kBAAC,GAAD,EAAkB,CAAA;KAAI,CAAA;IAC1D,kBAAC,GAAD;KAAO,MAAK;KAAe,SAAS,kBAAC,GAAD,EAAoB,CAAA;KAAI,CAAA;IAG5D,kBAAC,GAAD;KAAO,MAAK;KAAa,SAAS,kBAAC,GAAD,EAAsB,CAAA;KAAI,CAAA;IAC5D,kBAAC,GAAD;KAAO,MAAK;KAAQ,SAAS,kBAAC,GAAD,EAAiB,CAAA;KAAI,CAAA;IAGlD,kBAAC,GAAD;KAAO,MAAK;KAAY,SAAS,kBAAC,GAAD,EAAoB,CAAA;KAAI,CAAA;IACzD,kBAAC,GAAD;KAAO,MAAK;KAAQ,SAAS,kBAAC,GAAD,EAAa,CAAA;KAAI,CAAA;IAG9C,kBAAC,GAAD;KAAO,MAAK;KAAI,SAAS,kBAAC,GAAD;MAAU,IAAG;MAAG,SAAA;MAAU,CAAA;KAAI,CAAA;IAChD,EAAA,CAAA;GACA,CAAA;EACP,CAAA"}
1
+ {"version":3,"file":"AdapterCloudRoutes.js","names":[],"sources":["../../src/adaptercloud/AdapterCloudRoutes.tsx"],"sourcesContent":["/**\n * AdapterCloud Routes\n * @module adaptercloud\n *\n * Domain routing for the AdapterCloud (InfraVerse) control plane: an overview\n * landing page plus fabric (adapters / connections / resources), governance\n * (policies / violations / drift) and operations (sync runs / FinOps).\n */\n\nimport { type FC, lazy, Suspense } from 'react';\nimport { Routes, Route, Navigate, useLocation } from 'react-router-dom';\nimport { useAdapterCloud } from './context/AdapterCloudContext';\n\n// Eager — overview landing page\nimport { OverviewPage } from './pages/OverviewPage';\n\n// Fabric — adapters\nconst AdaptersListPage = lazy(() =>\n import('./pages/adapters/AdaptersListPage').then((m) => ({ default: m.AdaptersListPage }))\n);\nconst AdapterDetailPage = lazy(() =>\n import('./pages/adapters/AdapterDetailPage').then((m) => ({ default: m.AdapterDetailPage }))\n);\nconst AdapterFormPage = lazy(() =>\n import('./pages/adapters/AdapterFormPage').then((m) => ({ default: m.AdapterFormPage }))\n);\n\n// Fabric — connections\nconst ConnectionsListPage = lazy(() =>\n import('./pages/connections/ConnectionsListPage').then((m) => ({\n default: m.ConnectionsListPage,\n }))\n);\nconst ConnectionDetailPage = lazy(() =>\n import('./pages/connections/ConnectionDetailPage').then((m) => ({\n default: m.ConnectionDetailPage,\n }))\n);\nconst ConnectionFormPage = lazy(() =>\n import('./pages/connections/ConnectionFormPage').then((m) => ({\n default: m.ConnectionFormPage,\n }))\n);\n\n// Fabric — resources\nconst ResourcesListPage = lazy(() =>\n import('./pages/resources/ResourcesListPage').then((m) => ({ default: m.ResourcesListPage }))\n);\nconst ResourceDetailPage = lazy(() =>\n import('./pages/resources/ResourceDetailPage').then((m) => ({ default: m.ResourceDetailPage }))\n);\n\n// Fabric — estate topology (dependency graph)\nconst TopologyPage = lazy(() =>\n import('./pages/topology/TopologyPage').then((m) => ({ default: m.TopologyPage }))\n);\n\n// Governance — policies\nconst PoliciesListPage = lazy(() =>\n import('./pages/policies/PoliciesListPage').then((m) => ({ default: m.PoliciesListPage }))\n);\nconst PolicyDetailPage = lazy(() =>\n import('./pages/policies/PolicyDetailPage').then((m) => ({ default: m.PolicyDetailPage }))\n);\nconst PolicyFormPage = lazy(() =>\n import('./pages/policies/PolicyFormPage').then((m) => ({ default: m.PolicyFormPage }))\n);\n\n// Governance — violations & drift\nconst ViolationsListPage = lazy(() =>\n import('./pages/violations/ViolationsListPage').then((m) => ({ default: m.ViolationsListPage }))\n);\nconst DriftListPage = lazy(() =>\n import('./pages/drift/DriftListPage').then((m) => ({ default: m.DriftListPage }))\n);\n\n// Operations — sync runs & costs\nconst SyncRunsListPage = lazy(() =>\n import('./pages/sync-runs/SyncRunsListPage').then((m) => ({ default: m.SyncRunsListPage }))\n);\nconst CostsPage = lazy(() =>\n import('./pages/costs/CostsPage').then((m) => ({ default: m.CostsPage }))\n);\n\n// Loading fallback component\nconst PageLoader: FC = () => (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-b-2 border-accent-blue\" />\n </div>\n);\n\nexport const AdapterCloudRoutes: FC = () => {\n const { basePath, isStandalone } = useAdapterCloud();\n const location = useLocation();\n\n // Normalize base path\n const normalizedBasePath = basePath === '/' ? '' : (basePath ?? '').replace(/\\/$/, '');\n\n // Guard: Only render if path matches basePath (when integrated)\n if (normalizedBasePath && !isStandalone) {\n const pathMatches =\n location.pathname === normalizedBasePath ||\n location.pathname.startsWith(normalizedBasePath + '/');\n\n if (!pathMatches) {\n return null;\n }\n }\n\n return (\n <div className=\"flex min-h-full flex-col\">\n <Suspense fallback={<PageLoader />}>\n <Routes>\n {/* Overview — eager loaded */}\n <Route index element={<OverviewPage />} />\n\n {/* Adapters */}\n <Route path=\"adapters\" element={<AdaptersListPage />} />\n <Route path=\"adapters/new\" element={<AdapterFormPage />} />\n <Route path=\"adapters/:id\" element={<AdapterDetailPage />} />\n <Route path=\"adapters/:id/edit\" element={<AdapterFormPage />} />\n\n {/* Connections */}\n <Route path=\"connections\" element={<ConnectionsListPage />} />\n <Route path=\"connections/new\" element={<ConnectionFormPage />} />\n <Route path=\"connections/:id\" element={<ConnectionDetailPage />} />\n <Route path=\"connections/:id/edit\" element={<ConnectionFormPage />} />\n\n {/* Resources */}\n <Route path=\"resources\" element={<ResourcesListPage />} />\n <Route path=\"resources/:id\" element={<ResourceDetailPage />} />\n\n {/* Fabric — estate topology graph */}\n <Route path=\"topology\" element={<TopologyPage />} />\n\n {/* Policies */}\n <Route path=\"policies\" element={<PoliciesListPage />} />\n <Route path=\"policies/new\" element={<PolicyFormPage />} />\n <Route path=\"policies/:id\" element={<PolicyDetailPage />} />\n <Route path=\"policies/:id/edit\" element={<PolicyFormPage />} />\n\n {/* Governance */}\n <Route path=\"violations\" element={<ViolationsListPage />} />\n <Route path=\"drift\" element={<DriftListPage />} />\n\n {/* Operations */}\n <Route path=\"sync-runs\" element={<SyncRunsListPage />} />\n <Route path=\"costs\" element={<CostsPage />} />\n\n {/* Fallback */}\n <Route path=\"*\" element={<Navigate to=\"\" replace />} />\n </Routes>\n </Suspense>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Loader2 as e } from "lucide-react";
2
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
+ import { ResponsiveDialog as r, ResponsiveDialogContent as i, ResponsiveDialogDescription as a, ResponsiveDialogFooter as o, ResponsiveDialogHeader as s, ResponsiveDialogTitle as c } from "@burdenoff/fe-libs/ui";
4
+ //#region src/adaptercloud/components/ConfirmDialog.tsx
5
+ var l = ({ open: l, onOpenChange: u, title: d, description: f, confirmLabel: p, cancelLabel: m, onConfirm: h, isPending: g = !1, tone: _ = "danger" }) => /* @__PURE__ */ t(r, {
6
+ open: l,
7
+ onOpenChange: (e) => {
8
+ e || u(!1);
9
+ },
10
+ children: /* @__PURE__ */ n(i, { children: [/* @__PURE__ */ n(s, { children: [/* @__PURE__ */ t(c, { children: d }), f && /* @__PURE__ */ t(a, { children: f })] }), /* @__PURE__ */ n(o, { children: [/* @__PURE__ */ t("button", {
11
+ type: "button",
12
+ disabled: g,
13
+ onClick: () => u(!1),
14
+ className: "rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:opacity-50",
15
+ children: m
16
+ }), /* @__PURE__ */ n("button", {
17
+ type: "button",
18
+ disabled: g,
19
+ onClick: h,
20
+ className: _ === "danger" ? "inline-flex items-center justify-center gap-2 rounded-lg bg-action-danger-bg px-4 py-2 text-sm font-medium text-action-danger-text transition-colors hover:bg-action-danger-bg-hover disabled:opacity-50" : "inline-flex items-center justify-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",
21
+ children: [g && /* @__PURE__ */ t(e, { className: "h-4 w-4 animate-spin" }), p]
22
+ })] })] })
23
+ });
24
+ //#endregion
25
+ export { l as ConfirmDialog };
26
+
27
+ //# sourceMappingURL=ConfirmDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmDialog.js","names":[],"sources":["../../../src/adaptercloud/components/ConfirmDialog.tsx"],"sourcesContent":["/**\n * ConfirmDialog Component\n * @module adaptercloud/components\n *\n * A consistent \"Are you sure?\" confirmation gate for destructive or\n * consequential actions (archive, disable, remediate, cancel). Built on the\n * shared fe-libs `ResponsiveDialog` primitive so it adapts to mobile as a sheet\n * and desktop as a modal. Cancel dismisses; Confirm invokes `onConfirm` and can\n * show a pending spinner while the mutation is in flight.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { Loader2 } from 'lucide-react';\nimport {\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\n\ninterface ConfirmDialogProps {\n /** Controls visibility. */\n open: boolean;\n /** Called with `false` when the dialog should close (Cancel / overlay / esc). */\n onOpenChange: (open: boolean) => void;\n /** Dialog heading, e.g. \"Archive adapter?\". */\n title: string;\n /** Supporting body copy explaining the consequence. */\n description?: ReactNode;\n /** Confirm button label. Defaults to \"Confirm\". */\n confirmLabel: string;\n /** Cancel button label. Defaults to \"Cancel\". */\n cancelLabel: string;\n /** Invoked when the user confirms. */\n onConfirm: () => void;\n /** When true the confirm button spins and both buttons disable. */\n isPending?: boolean;\n /**\n * Visual tone of the confirm button. `danger` for destructive actions\n * (archive/disable/cancel), `primary` for neutral consequential ones.\n */\n tone?: 'danger' | 'primary';\n}\n\nexport const ConfirmDialog: FC<ConfirmDialogProps> = ({\n open,\n onOpenChange,\n title,\n description,\n confirmLabel,\n cancelLabel,\n onConfirm,\n isPending = false,\n tone = 'danger',\n}) => {\n const confirmClass =\n tone === 'danger'\n ? 'inline-flex items-center justify-center gap-2 rounded-lg bg-action-danger-bg px-4 py-2 text-sm font-medium text-action-danger-text transition-colors hover:bg-action-danger-bg-hover disabled:opacity-50'\n : 'inline-flex items-center justify-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 return (\n <ResponsiveDialog\n open={open}\n onOpenChange={(next) => {\n if (!next) onOpenChange(false);\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{title}</ResponsiveDialogTitle>\n {description && <ResponsiveDialogDescription>{description}</ResponsiveDialogDescription>}\n </ResponsiveDialogHeader>\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n disabled={isPending}\n onClick={() => onOpenChange(false)}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent disabled:opacity-50\"\n >\n {cancelLabel}\n </button>\n <button type=\"button\" disabled={isPending} onClick={onConfirm} className={confirmClass}>\n {isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {confirmLabel}\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n};\n"],"mappings":";;;;AA8CA,IAAa,KAAyC,EACpD,SACA,iBACA,UACA,gBACA,iBACA,gBACA,cACA,eAAY,IACZ,UAAO,eAQL,kBAAC,GAAD;CACQ;CACN,eAAe,MAAS;AACtB,EAAK,KAAM,EAAa,GAAM;;WAGhC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAwB,GAA8B,CAAA,EACrD,KAAe,kBAAC,GAAD,EAAA,UAA8B,GAA0C,CAAA,CACjE,EAAA,CAAA,EACzB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,UAAD;EACE,MAAK;EACL,UAAU;EACV,eAAe,EAAa,GAAM;EAClC,WAAU;YAET;EACM,CAAA,EACT,kBAAC,UAAD;EAAQ,MAAK;EAAS,UAAU;EAAW,SAAS;EAAW,WAzBrE,MAAS,WACL,6MACA;YAuBE,CACG,KAAa,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,EACzD,EACM;IACc,EAAA,CAAA,CACD,EAAA,CAAA;CACT,CAAA"}
@@ -8,7 +8,7 @@ function s(e) {
8
8
  }
9
9
  var c = ({ isLoading: c, isError: l, isEmpty: u = !1, error: d, onRetry: f, emptyTitle: p = "Nothing here yet", emptyDescription: m, emptyIcon: h, emptyAction: g, emptyIllustration: _, className: v, children: y }) => c ? /* @__PURE__ */ a("div", {
10
10
  className: e("flex min-h-[240px] items-center justify-center", v),
11
- children: /* @__PURE__ */ a(r, { className: "h-8 w-8 animate-spin text-primary" })
11
+ children: /* @__PURE__ */ a(r, { className: "h-8 w-8 animate-spin text-accent-blue" })
12
12
  }) : l ? /* @__PURE__ */ o("div", {
13
13
  className: e("flex min-h-[240px] flex-col items-center justify-center gap-3 rounded-xl border border-border-subtle bg-bg-surface p-8 text-center", v),
14
14
  children: [
@@ -1 +1 @@
1
- {"version":3,"file":"DataState.js","names":[],"sources":["../../../src/adaptercloud/components/DataState.tsx"],"sourcesContent":["/**\n * DataState Component\n * @module adaptercloud/components\n *\n * Standard loading / error / empty wrapper for query-backed sections. Renders\n * `children` only when there is data; otherwise shows a spinner, an error panel,\n * or an illustrated empty state. Keeps every page's async UX consistent.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { AlertCircle, Loader2 } from 'lucide-react';\nimport { EmptyState } from './EmptyState';\nimport { cn } from '../utils/cn';\n\ninterface DataStateProps {\n isLoading: boolean;\n isError: boolean;\n /** True when the underlying list/record is empty (only checked once loaded). */\n isEmpty?: boolean;\n error?: unknown;\n onRetry?: () => void;\n emptyTitle?: string;\n emptyDescription?: string;\n emptyIcon?: ReactNode;\n emptyAction?: ReactNode;\n emptyIllustration?: string;\n className?: string;\n children: ReactNode;\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === 'string') return error;\n return 'Something went wrong while loading data.';\n}\n\nexport const DataState: FC<DataStateProps> = ({\n isLoading,\n isError,\n isEmpty = false,\n error,\n onRetry,\n emptyTitle = 'Nothing here yet',\n emptyDescription,\n emptyIcon,\n emptyAction,\n emptyIllustration,\n className,\n children,\n}) => {\n if (isLoading) {\n return (\n <div className={cn('flex min-h-[240px] items-center justify-center', className)}>\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n );\n }\n\n if (isError) {\n return (\n <div\n className={cn(\n 'flex min-h-[240px] flex-col items-center justify-center gap-3 rounded-xl border border-border-subtle bg-bg-surface p-8 text-center',\n className\n )}\n >\n <AlertCircle className=\"h-10 w-10 text-status-error-text\" />\n <h3 className=\"text-base font-semibold text-text-primary\">Failed to load</h3>\n <p className=\"max-w-md text-sm text-text-secondary\">{errorMessage(error)}</p>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"mt-1 rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n Try again\n </button>\n )}\n </div>\n );\n }\n\n if (isEmpty) {\n return (\n <EmptyState\n title={emptyTitle}\n description={emptyDescription}\n icon={emptyIcon}\n action={emptyAction}\n illustration={emptyIllustration}\n className={className}\n />\n );\n }\n\n return <>{children}</>;\n};\n"],"mappings":";;;;;AA8BA,SAAS,EAAa,GAAwB;AAG5C,QAFI,aAAiB,QAAc,EAAM,UACrC,OAAO,KAAU,WAAiB,IAC/B;;AAGT,IAAa,KAAiC,EAC5C,cACA,YACA,aAAU,IACV,UACA,YACA,gBAAa,oBACb,qBACA,cACA,gBACA,sBACA,cACA,kBAEI,IAEA,kBAAC,OAAD;CAAK,WAAW,EAAG,kDAAkD,EAAU;WAC7E,kBAAC,GAAD,EAAS,WAAU,qCAAsC,CAAA;CACrD,CAAA,GAIN,IAEA,kBAAC,OAAD;CACE,WAAW,EACT,sIACA,EACD;WAJH;EAME,kBAAC,GAAD,EAAa,WAAU,oCAAqC,CAAA;EAC5D,kBAAC,MAAD;GAAI,WAAU;aAA4C;GAAmB,CAAA;EAC7E,kBAAC,KAAD;GAAG,WAAU;aAAwC,EAAa,EAAM;GAAK,CAAA;EAC5E,KACC,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;aACX;GAEQ,CAAA;EAEP;KAIN,IAEA,kBAAC,GAAD;CACE,OAAO;CACP,aAAa;CACb,MAAM;CACN,QAAQ;CACR,cAAc;CACH;CACX,CAAA,GAIC,kBAAA,GAAA,EAAG,aAAY,CAAA"}
1
+ {"version":3,"file":"DataState.js","names":[],"sources":["../../../src/adaptercloud/components/DataState.tsx"],"sourcesContent":["/**\n * DataState Component\n * @module adaptercloud/components\n *\n * Standard loading / error / empty wrapper for query-backed sections. Renders\n * `children` only when there is data; otherwise shows a spinner, an error panel,\n * or an illustrated empty state. Keeps every page's async UX consistent.\n */\n\nimport type { FC, ReactNode } from 'react';\nimport { AlertCircle, Loader2 } from 'lucide-react';\nimport { EmptyState } from './EmptyState';\nimport { cn } from '../utils/cn';\n\ninterface DataStateProps {\n isLoading: boolean;\n isError: boolean;\n /** True when the underlying list/record is empty (only checked once loaded). */\n isEmpty?: boolean;\n error?: unknown;\n onRetry?: () => void;\n emptyTitle?: string;\n emptyDescription?: string;\n emptyIcon?: ReactNode;\n emptyAction?: ReactNode;\n emptyIllustration?: string;\n className?: string;\n children: ReactNode;\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n if (typeof error === 'string') return error;\n return 'Something went wrong while loading data.';\n}\n\nexport const DataState: FC<DataStateProps> = ({\n isLoading,\n isError,\n isEmpty = false,\n error,\n onRetry,\n emptyTitle = 'Nothing here yet',\n emptyDescription,\n emptyIcon,\n emptyAction,\n emptyIllustration,\n className,\n children,\n}) => {\n if (isLoading) {\n return (\n <div className={cn('flex min-h-[240px] items-center justify-center', className)}>\n <Loader2 className=\"h-8 w-8 animate-spin text-accent-blue\" />\n </div>\n );\n }\n\n if (isError) {\n return (\n <div\n className={cn(\n 'flex min-h-[240px] flex-col items-center justify-center gap-3 rounded-xl border border-border-subtle bg-bg-surface p-8 text-center',\n className\n )}\n >\n <AlertCircle className=\"h-10 w-10 text-status-error-text\" />\n <h3 className=\"text-base font-semibold text-text-primary\">Failed to load</h3>\n <p className=\"max-w-md text-sm text-text-secondary\">{errorMessage(error)}</p>\n {onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className=\"mt-1 rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n Try again\n </button>\n )}\n </div>\n );\n }\n\n if (isEmpty) {\n return (\n <EmptyState\n title={emptyTitle}\n description={emptyDescription}\n icon={emptyIcon}\n action={emptyAction}\n illustration={emptyIllustration}\n className={className}\n />\n );\n }\n\n return <>{children}</>;\n};\n"],"mappings":";;;;;AA8BA,SAAS,EAAa,GAAwB;AAG5C,QAFI,aAAiB,QAAc,EAAM,UACrC,OAAO,KAAU,WAAiB,IAC/B;;AAGT,IAAa,KAAiC,EAC5C,cACA,YACA,aAAU,IACV,UACA,YACA,gBAAa,oBACb,qBACA,cACA,gBACA,sBACA,cACA,kBAEI,IAEA,kBAAC,OAAD;CAAK,WAAW,EAAG,kDAAkD,EAAU;WAC7E,kBAAC,GAAD,EAAS,WAAU,yCAA0C,CAAA;CACzD,CAAA,GAIN,IAEA,kBAAC,OAAD;CACE,WAAW,EACT,sIACA,EACD;WAJH;EAME,kBAAC,GAAD,EAAa,WAAU,oCAAqC,CAAA;EAC5D,kBAAC,MAAD;GAAI,WAAU;aAA4C;GAAmB,CAAA;EAC7E,kBAAC,KAAD;GAAG,WAAU;aAAwC,EAAa,EAAM;GAAK,CAAA;EAC5E,KACC,kBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;aACX;GAEQ,CAAA;EAEP;KAIN,IAEA,kBAAC,GAAD;CACE,OAAO;CACP,aAAa;CACb,MAAM;CACN,QAAQ;CACR,cAAc;CACH;CACX,CAAA,GAIC,kBAAA,GAAA,EAAG,aAAY,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { jsx as e, jsxs as t } from "react/jsx-runtime";
2
+ //#region src/adaptercloud/components/viz/BarChart.tsx
3
+ var n = ({ data: n, barClassName: r = "bg-accent-blue", labelWidthClassName: i = "w-20 sm:w-24" }) => {
4
+ let a = Math.max(...n.map((e) => e.value), 1);
5
+ return /* @__PURE__ */ e("ul", {
6
+ className: "space-y-2.5",
7
+ children: n.map((n) => /* @__PURE__ */ t("li", {
8
+ className: "flex items-center gap-3",
9
+ children: [
10
+ /* @__PURE__ */ e("span", {
11
+ className: `${i} shrink-0 truncate text-xs text-text-secondary`,
12
+ children: n.label
13
+ }),
14
+ /* @__PURE__ */ e("div", {
15
+ className: "h-2.5 flex-1 overflow-hidden rounded-full bg-bg-sunken",
16
+ children: /* @__PURE__ */ e("div", {
17
+ className: `h-full rounded-full ${r} transition-[width] duration-500`,
18
+ style: { width: `${Math.max(2, n.value / a * 100)}%` }
19
+ })
20
+ }),
21
+ /* @__PURE__ */ e("span", {
22
+ className: "shrink-0 text-xs font-semibold tabular-nums text-text-primary",
23
+ children: n.display
24
+ })
25
+ ]
26
+ }, n.key))
27
+ });
28
+ };
29
+ //#endregion
30
+ export { n as BarChart };
31
+
32
+ //# sourceMappingURL=BarChart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BarChart.js","names":[],"sources":["../../../../src/adaptercloud/components/viz/BarChart.tsx"],"sourcesContent":["/**\n * BarChart — a compact horizontal bar list (label · bar · value). Tokenized,\n * responsive, no raw colors. Used for breakdowns like cost-by-service.\n */\nimport type { FC } from 'react';\n\nexport interface BarDatum {\n key: string;\n label: string;\n value: number;\n /** Preformatted value shown on the right (e.g. \"$22,400\"). */\n display: string;\n}\n\ninterface BarChartProps {\n data: BarDatum[];\n /** Semantic-token fill class for the bar (default accent-blue). */\n barClassName?: string;\n labelWidthClassName?: string;\n}\n\nexport const BarChart: FC<BarChartProps> = ({\n data,\n barClassName = 'bg-accent-blue',\n labelWidthClassName = 'w-20 sm:w-24',\n}) => {\n const max = Math.max(...data.map((d) => d.value), 1);\n\n return (\n <ul className=\"space-y-2.5\">\n {data.map((d) => (\n <li key={d.key} className=\"flex items-center gap-3\">\n <span className={`${labelWidthClassName} shrink-0 truncate text-xs text-text-secondary`}>\n {d.label}\n </span>\n <div className=\"h-2.5 flex-1 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className={`h-full rounded-full ${barClassName} transition-[width] duration-500`}\n style={{ width: `${Math.max(2, (d.value / max) * 100)}%` }}\n />\n </div>\n <span className=\"shrink-0 text-xs font-semibold tabular-nums text-text-primary\">\n {d.display}\n </span>\n </li>\n ))}\n </ul>\n );\n};\n"],"mappings":";;AAqBA,IAAa,KAA+B,EAC1C,SACA,kBAAe,kBACf,yBAAsB,qBAClB;CACJ,IAAM,IAAM,KAAK,IAAI,GAAG,EAAK,KAAK,MAAM,EAAE,MAAM,EAAE,EAAE;AAEpD,QACE,kBAAC,MAAD;EAAI,WAAU;YACX,EAAK,KAAK,MACT,kBAAC,MAAD;GAAgB,WAAU;aAA1B;IACE,kBAAC,QAAD;KAAM,WAAW,GAAG,EAAoB;eACrC,EAAE;KACE,CAAA;IACP,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MACE,WAAW,uBAAuB,EAAa;MAC/C,OAAO,EAAE,OAAO,GAAG,KAAK,IAAI,GAAI,EAAE,QAAQ,IAAO,IAAI,CAAC,IAAI;MAC1D,CAAA;KACE,CAAA;IACN,kBAAC,QAAD;KAAM,WAAU;eACb,EAAE;KACE,CAAA;IACJ;KAbI,EAAE,IAaN,CACL;EACC,CAAA"}
@@ -0,0 +1,50 @@
1
+ import { useId as e } from "react";
2
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
+ //#region src/adaptercloud/components/viz/Sparkline.tsx
4
+ var r = ({ points: r, className: i = "text-accent-blue h-10 w-full", ariaLabel: a }) => {
5
+ let o = e();
6
+ if (r.length < 2) return null;
7
+ let s = Math.max(...r), c = Math.min(...r), l = s - c || 1, u = 120 / (r.length - 1), d = r.map((e, t) => [t * u, 40 - (e - c) / l * 36 - 2]).map(([e, t], n) => `${n === 0 ? "M" : "L"}${e.toFixed(1)},${t.toFixed(1)}`).join(" "), f = `${d} L120,40 L0,40 Z`;
8
+ return /* @__PURE__ */ n("svg", {
9
+ viewBox: "0 0 120 40",
10
+ className: i,
11
+ preserveAspectRatio: "none",
12
+ role: "img",
13
+ "aria-label": a ?? "trend",
14
+ children: [
15
+ /* @__PURE__ */ t("defs", { children: /* @__PURE__ */ n("linearGradient", {
16
+ id: o,
17
+ x1: "0",
18
+ y1: "0",
19
+ x2: "0",
20
+ y2: "1",
21
+ children: [/* @__PURE__ */ t("stop", {
22
+ offset: "0%",
23
+ stopColor: "currentColor",
24
+ stopOpacity: "0.3"
25
+ }), /* @__PURE__ */ t("stop", {
26
+ offset: "100%",
27
+ stopColor: "currentColor",
28
+ stopOpacity: "0"
29
+ })]
30
+ }) }),
31
+ /* @__PURE__ */ t("path", {
32
+ d: f,
33
+ fill: `url(#${o})`
34
+ }),
35
+ /* @__PURE__ */ t("path", {
36
+ d,
37
+ fill: "none",
38
+ stroke: "currentColor",
39
+ strokeWidth: "1.75",
40
+ strokeLinecap: "round",
41
+ strokeLinejoin: "round",
42
+ vectorEffect: "non-scaling-stroke"
43
+ })
44
+ ]
45
+ });
46
+ };
47
+ //#endregion
48
+ export { r as Sparkline };
49
+
50
+ //# sourceMappingURL=Sparkline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sparkline.js","names":[],"sources":["../../../../src/adaptercloud/components/viz/Sparkline.tsx"],"sourcesContent":["/**\n * Sparkline — a tiny tokenized SVG area/line trend (e.g. monthly cost trend).\n * Uses currentColor + a unique gradient id so multiple sparklines coexist.\n */\nimport { useId, type FC } from 'react';\n\ninterface SparklineProps {\n points: number[];\n /** Wrapper class controls size + color (via text-*). Default accent-blue, full width, 40px tall. */\n className?: string;\n ariaLabel?: string;\n}\n\nexport const Sparkline: FC<SparklineProps> = ({\n points,\n className = 'text-accent-blue h-10 w-full',\n ariaLabel,\n}) => {\n const gradientId = useId();\n if (points.length < 2) return null;\n\n const w = 120;\n const h = 40;\n const max = Math.max(...points);\n const min = Math.min(...points);\n const range = max - min || 1;\n const step = w / (points.length - 1);\n const coords = points.map((p, i) => [i * step, h - ((p - min) / range) * (h - 4) - 2]);\n const line = coords\n .map(([x, y], i) => `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`)\n .join(' ');\n const area = `${line} L${w},${h} L0,${h} Z`;\n\n return (\n <svg\n viewBox={`0 0 ${w} ${h}`}\n className={className}\n preserveAspectRatio=\"none\"\n role=\"img\"\n aria-label={ariaLabel ?? 'trend'}\n >\n <defs>\n <linearGradient id={gradientId} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"currentColor\" stopOpacity=\"0.3\" />\n <stop offset=\"100%\" stopColor=\"currentColor\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={area} fill={`url(#${gradientId})`} />\n <path\n d={line}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n vectorEffect=\"non-scaling-stroke\"\n />\n </svg>\n );\n};\n"],"mappings":";;;AAaA,IAAa,KAAiC,EAC5C,WACA,eAAY,gCACZ,mBACI;CACJ,IAAM,IAAa,GAAO;AAC1B,KAAI,EAAO,SAAS,EAAG,QAAO;CAE9B,IAEM,IAAM,KAAK,IAAI,GAAG,EAAO,EACzB,IAAM,KAAK,IAAI,GAAG,EAAO,EACzB,IAAQ,IAAM,KAAO,GACrB,IAAO,OAAK,EAAO,SAAS,IAE5B,IADS,EAAO,KAAK,GAAG,MAAM,CAAC,IAAI,GAAM,MAAM,IAAI,KAAO,IAAU,KAAS,EAAE,CAAC,CAEnF,KAAK,CAAC,GAAG,IAAI,MAAM,GAAG,MAAM,IAAI,MAAM,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,CAC3E,KAAK,IAAI,EACN,IAAO,GAAG,EAAK;AAErB,QACE,kBAAC,OAAD;EACE,SAAS;EACE;EACX,qBAAoB;EACpB,MAAK;EACL,cAAY,KAAa;YAL3B;GAOE,kBAAC,QAAD,EAAA,UACE,kBAAC,kBAAD;IAAgB,IAAI;IAAY,IAAG;IAAI,IAAG;IAAI,IAAG;IAAI,IAAG;cAAxD,CACE,kBAAC,QAAD;KAAM,QAAO;KAAK,WAAU;KAAe,aAAY;KAAQ,CAAA,EAC/D,kBAAC,QAAD;KAAM,QAAO;KAAO,WAAU;KAAe,aAAY;KAAM,CAAA,CAChD;OACZ,CAAA;GACP,kBAAC,QAAD;IAAM,GAAG;IAAM,MAAM,QAAQ,EAAW;IAAM,CAAA;GAC9C,kBAAC,QAAD;IACK;IACH,MAAK;IACL,QAAO;IACP,aAAY;IACZ,eAAc;IACd,gBAAe;IACf,cAAa;IACb,CAAA;GACE"}
@@ -0,0 +1 @@
1
+ import "react/jsx-runtime";
@@ -0,0 +1,96 @@
1
+ import { useMemo as e } from "react";
2
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
+ //#region src/adaptercloud/components/viz/TopologyGraph.tsx
4
+ var r = 168, i = 44, a = 120, o = 26, s = 28, c = ({ nodes: c, edges: l, selectedId: u, onSelect: d }) => {
5
+ let { positioned: f, width: p, height: m, edgePaths: h } = e(() => {
6
+ let e = /* @__PURE__ */ new Map();
7
+ for (let t of c) {
8
+ let n = e.get(t.group) ?? [];
9
+ n.push(t), e.set(t.group, n);
10
+ }
11
+ let t = [...e.keys()], n = Math.max(1, ...[...e.values()].map((e) => e.length)), u = /* @__PURE__ */ new Map();
12
+ t.forEach((t, c) => {
13
+ let l = e.get(t), d = l.length * i + (l.length - 1) * o, f = s + (n * i + (n - 1) * o - d) / 2;
14
+ l.forEach((e, t) => {
15
+ u.set(e.id, {
16
+ x: s + c * (r + a),
17
+ y: f + t * (i + o),
18
+ node: e
19
+ });
20
+ });
21
+ });
22
+ let d = s * 2 + t.length * r + Math.max(0, t.length - 1) * a, f = s * 2 + n * i + Math.max(0, n - 1) * o, p = l.map((e) => {
23
+ let t = u.get(e.from), n = u.get(e.to);
24
+ if (!t || !n) return null;
25
+ let a = t.x + r, o = t.y + i / 2, s = n.x, c = n.y + i / 2, l = (a + s) / 2, d = `M${a},${o} C${l},${o} ${l},${c} ${s},${c}`;
26
+ return {
27
+ ...e,
28
+ d
29
+ };
30
+ }).filter(Boolean);
31
+ return {
32
+ positioned: [...u.values()],
33
+ width: d,
34
+ height: f,
35
+ edgePaths: p
36
+ };
37
+ }, [c, l]), g = e(() => u ? new Set(h.filter((e) => e.from === u || e.to === u).map((e) => e.id)) : /* @__PURE__ */ new Set(), [u, h]), _ = (e) => e === "DRIFTED" ? "border-status-warning-text/60" : e === "ORPHANED" || e === "DELETED" ? "border-status-error-text/60" : "border-border-strong";
38
+ return /* @__PURE__ */ t("div", {
39
+ className: "relative w-full overflow-auto rounded-xl border border-border-subtle bg-bg-sunken/40",
40
+ children: /* @__PURE__ */ n("div", {
41
+ className: "relative",
42
+ style: {
43
+ width: p,
44
+ height: m,
45
+ minWidth: "100%"
46
+ },
47
+ children: [/* @__PURE__ */ t("svg", {
48
+ className: "absolute inset-0 h-full w-full",
49
+ width: p,
50
+ height: m,
51
+ "aria-hidden": !0,
52
+ children: h.map((e) => {
53
+ let n = g.has(e.id), r = e.drifted ? "stroke-status-warning-text" : n ? "stroke-accent-blue" : "stroke-border-strong";
54
+ return /* @__PURE__ */ t("path", {
55
+ d: e.d,
56
+ fill: "none",
57
+ className: r,
58
+ strokeWidth: n ? 2 : 1.25,
59
+ strokeOpacity: u && !n && !e.drifted ? .35 : .9
60
+ }, e.id);
61
+ })
62
+ }), f.map(({ x: e, y: a, node: o }) => {
63
+ let s = o.id === u;
64
+ return /* @__PURE__ */ n("button", {
65
+ type: "button",
66
+ onClick: () => d?.(o.id),
67
+ style: {
68
+ left: e,
69
+ top: a,
70
+ width: r,
71
+ height: i
72
+ },
73
+ className: `absolute flex items-center gap-2 rounded-lg border bg-bg-surface/90 px-3 text-left backdrop-blur transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] ${s ? "border-accent-blue ring-2 ring-accent-blue/40" : _(o.state)}`,
74
+ title: o.type ? `${o.label} · ${o.type}` : o.label,
75
+ children: [/* @__PURE__ */ t("span", {
76
+ className: `h-2 w-2 shrink-0 rounded-full ${o.state === "DRIFTED" ? "bg-status-warning-text" : o.state === "ORPHANED" || o.state === "DELETED" ? "bg-status-error-text" : "bg-status-success-text"}`,
77
+ "aria-hidden": !0
78
+ }), /* @__PURE__ */ n("span", {
79
+ className: "min-w-0 flex-1",
80
+ children: [/* @__PURE__ */ t("span", {
81
+ className: "block truncate text-sm font-medium text-text-primary",
82
+ children: o.label
83
+ }), o.type && /* @__PURE__ */ t("span", {
84
+ className: "block truncate font-mono text-[10px] text-text-secondary",
85
+ children: o.type
86
+ })]
87
+ })]
88
+ }, o.id);
89
+ })]
90
+ })
91
+ });
92
+ };
93
+ //#endregion
94
+ export { c as TopologyGraph };
95
+
96
+ //# sourceMappingURL=TopologyGraph.js.map