@burdenoff/microfe-adaptercloud 2026.825.3 → 2026.825.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js +1 -1
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js.map +1 -1
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +24 -7
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +8 -5
|
@@ -37,7 +37,7 @@ function N() {
|
|
|
37
37
|
}), L = o({
|
|
38
38
|
status: "PUBLISHED",
|
|
39
39
|
pagination: { limit: 100 }
|
|
40
|
-
}).data?.items ?? [], R = I.data?.items ?? [], z = I.data?.pageInfo.hasMore ?? !1, B = u(() => {
|
|
40
|
+
}).data?.items ?? [], R = u(() => I.data?.items ?? [], [I.data?.items]), z = I.data?.pageInfo.hasMore ?? !1, B = u(() => {
|
|
41
41
|
let e = T.trim().toLowerCase();
|
|
42
42
|
return e ? R.filter((t) => t.name.toLowerCase().includes(e) || (t.region?.toLowerCase().includes(e) ?? !1) || (t.environment?.toLowerCase().includes(e) ?? !1)) : R;
|
|
43
43
|
}, [R, T]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConnectionsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/ConnectionsListPage.tsx"],"sourcesContent":["/**\n * Connections List Page\n * @module adaptercloud/pages/connections\n *\n * Every configured, authenticated target in the workspace. Lists from\n * `adaListConnections` with an adapter + status filter, a client-side search,\n * and offset pagination. Each card carries a per-adapter-kind glyph tile so the\n * fabric's reach reads at a glance (mirrors the aws/azure/gke/snowflake logos in\n * the mock).\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Cable,\n Plus,\n ChevronLeft,\n ChevronRight,\n MapPin,\n Server,\n Search,\n Cloud,\n Radio,\n Cpu,\n Boxes,\n Network,\n Database,\n HardDrive,\n Puzzle,\n type LucideIcon,\n} 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 { useConnections, useAdapters } from '../../hooks/useAdapterCloudApi';\nimport { authMethodLabels, connectionStatusLabels } from '../../utils/domain';\nimport { formatRelativeTime } from '../../utils/formatters';\nimport type { AdaAdapterKind, AdaConnectionStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\n/**\n * Per-adapter-kind glyph — stands in for the vendor logos (aws / azure / gke /\n * snowflake) in the mock. Keyed off the connection's bound adapter kind; every\n * `AdaAdapterKind` maps to one of the eight allowed lucide marks.\n */\nconst adapterKindIcon: Record<AdaAdapterKind, LucideIcon> = {\n PUBLIC_CLOUD: Cloud,\n PRIVATE_CLOUD: Cloud,\n SAAS: Cloud,\n ON_PREM: HardDrive,\n EDGE: Radio,\n IOT: Cpu,\n KUBERNETES: Boxes,\n NETWORK: Network,\n DATA_SYSTEM: Database,\n CUSTOM: Puzzle,\n};\n\nexport function ConnectionsListPage() {\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 [status, setStatus] = useState<AdaConnectionStatus | ''>('');\n const [adapterId, setAdapterId] = useState('');\n const [search, setSearch] = useState('');\n const [offset, setOffset] = useState(0);\n\n const query = useConnections({\n adapterId: adapterId || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n // Published adapters power the adapter filter dropdown (mock's \"Adapter filter\").\n const adaptersQuery = useAdapters({ status: 'PUBLISHED', pagination: { limit: 100 } });\n const adapterOptions = adaptersQuery.data?.items ?? [];\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n // Client-side search over the loaded page (name / region / environment).\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return items;\n return items.filter(\n (c) =>\n c.name.toLowerCase().includes(q) ||\n (c.region?.toLowerCase().includes(q) ?? false) ||\n (c.environment?.toLowerCase().includes(q) ?? false)\n );\n }, [items, search]);\n\n return (\n <PageLayout\n title={t('adaptercloud.connections.title', 'Connections')}\n description={t(\n 'adaptercloud.connections.subtitle',\n 'Configured, authenticated targets — each connection is where the fabric actually reaches.'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/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.connections.new', 'New connection')}\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaConnectionStatus | '');\n setOffset(0);\n }}\n aria-label={t('adaptercloud.connections.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.connections.allStatuses', 'All statuses')}</option>\n {(Object.keys(connectionStatusLabels) as AdaConnectionStatus[]).map((s) => (\n <option key={s} value={s}>\n {connectionStatusLabels[s]}\n </option>\n ))}\n </select>\n\n <select\n value={adapterId}\n onChange={(e) => {\n setAdapterId(e.target.value);\n setOffset(0);\n }}\n aria-label={t('adaptercloud.connections.filterByAdapter', 'Filter by adapter')}\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.connections.allAdapters', 'All adapters')}</option>\n {adapterOptions.map((a) => (\n <option key={a.id} value={a.id}>\n {a.name}\n </option>\n ))}\n </select>\n\n <div className=\"relative w-full sm:ml-auto sm:w-64\">\n <Search\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\"\n />\n <input\n type=\"search\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n aria-label={t('adaptercloud.connections.search', 'Search connections')}\n placeholder={t('adaptercloud.connections.searchPlaceholder', 'Search…')}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\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.connections.emptyTitle', 'No connections yet')}\n emptyDescription={t(\n 'adaptercloud.connections.emptyDescription',\n 'Create a connection to a real target to start discovering resources.'\n )}\n emptyIcon={<Cable className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n {t('adaptercloud.connections.new', 'New connection')}\n </button>\n }\n >\n {filtered.length === 0 ? (\n <p className=\"rounded-xl border border-border-subtle bg-bg-surface px-4 py-10 text-center text-sm text-text-secondary\">\n {t('adaptercloud.connections.noSearchMatch', 'No connections match your search.')}\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((conn) => {\n const KindIcon = conn.adapter?.kind ? adapterKindIcon[conn.adapter.kind] : Cable;\n return (\n <GlassCard\n key={conn.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => navigateTo(`/connections/${conn.id}`)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateTo(`/connections/${conn.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 gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-accent-blue\">\n <KindIcon className=\"h-5 w-5\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\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 {conn.name}\n </h3>\n {conn.adapter && (\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">\n {conn.adapter.name}\n </p>\n )}\n </div>\n <StatusBadge status={conn.status} />\n </div>\n </div>\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5\">\n {authMethodLabels[conn.authMethod]}\n </span>\n {conn.region && (\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" /> {conn.region}\n </span>\n )}\n {conn.environment && <span>· {conn.environment}</span>}\n </div>\n\n <div className=\"mt-4 flex items-center gap-2 text-sm text-text-primary\">\n <Server className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"font-semibold tabular-nums\">{conn.resourceCount}</span>\n <span className=\"text-text-secondary\">\n {t('adaptercloud.connections.resources', 'resources')}\n </span>\n </div>\n\n {conn.lastError && (\n <p className=\"mt-3 line-clamp-2 rounded-lg bg-status-error-bg-subtle px-2 py-1 text-xs text-status-error-text\">\n {conn.lastError}\n </p>\n )}\n\n <p className=\"mt-4 text-xs text-text-secondary\">\n {conn.lastSyncedAt\n ? `${t('adaptercloud.connections.lastSynced', 'Last synced')} ${formatRelativeTime(conn.lastSyncedAt)}`\n : t('adaptercloud.connections.neverSynced', 'Never synced')}\n </p>\n </GlassCard>\n );\n })}\n </div>\n )}\n\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":"ConnectionsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/connections/ConnectionsListPage.tsx"],"sourcesContent":["/**\n * Connections List Page\n * @module adaptercloud/pages/connections\n *\n * Every configured, authenticated target in the workspace. Lists from\n * `adaListConnections` with an adapter + status filter, a client-side search,\n * and offset pagination. Each card carries a per-adapter-kind glyph tile so the\n * fabric's reach reads at a glance (mirrors the aws/azure/gke/snowflake logos in\n * the mock).\n */\n\nimport { useState, useCallback, useMemo } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Cable,\n Plus,\n ChevronLeft,\n ChevronRight,\n MapPin,\n Server,\n Search,\n Cloud,\n Radio,\n Cpu,\n Boxes,\n Network,\n Database,\n HardDrive,\n Puzzle,\n type LucideIcon,\n} 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 { useConnections, useAdapters } from '../../hooks/useAdapterCloudApi';\nimport { authMethodLabels, connectionStatusLabels } from '../../utils/domain';\nimport { formatRelativeTime } from '../../utils/formatters';\nimport type { AdaAdapterKind, AdaConnectionStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\n/**\n * Per-adapter-kind glyph — stands in for the vendor logos (aws / azure / gke /\n * snowflake) in the mock. Keyed off the connection's bound adapter kind; every\n * `AdaAdapterKind` maps to one of the eight allowed lucide marks.\n */\nconst adapterKindIcon: Record<AdaAdapterKind, LucideIcon> = {\n PUBLIC_CLOUD: Cloud,\n PRIVATE_CLOUD: Cloud,\n SAAS: Cloud,\n ON_PREM: HardDrive,\n EDGE: Radio,\n IOT: Cpu,\n KUBERNETES: Boxes,\n NETWORK: Network,\n DATA_SYSTEM: Database,\n CUSTOM: Puzzle,\n};\n\nexport function ConnectionsListPage() {\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 [status, setStatus] = useState<AdaConnectionStatus | ''>('');\n const [adapterId, setAdapterId] = useState('');\n const [search, setSearch] = useState('');\n const [offset, setOffset] = useState(0);\n\n const query = useConnections({\n adapterId: adapterId || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n\n // Published adapters power the adapter filter dropdown (mock's \"Adapter filter\").\n const adaptersQuery = useAdapters({ status: 'PUBLISHED', pagination: { limit: 100 } });\n const adapterOptions = adaptersQuery.data?.items ?? [];\n\n const items = useMemo(() => query.data?.items ?? [], [query.data?.items]);\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n // Client-side search over the loaded page (name / region / environment).\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return items;\n return items.filter(\n (c) =>\n c.name.toLowerCase().includes(q) ||\n (c.region?.toLowerCase().includes(q) ?? false) ||\n (c.environment?.toLowerCase().includes(q) ?? false)\n );\n }, [items, search]);\n\n return (\n <PageLayout\n title={t('adaptercloud.connections.title', 'Connections')}\n description={t(\n 'adaptercloud.connections.subtitle',\n 'Configured, authenticated targets — each connection is where the fabric actually reaches.'\n )}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/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.connections.new', 'New connection')}\n </button>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaConnectionStatus | '');\n setOffset(0);\n }}\n aria-label={t('adaptercloud.connections.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.connections.allStatuses', 'All statuses')}</option>\n {(Object.keys(connectionStatusLabels) as AdaConnectionStatus[]).map((s) => (\n <option key={s} value={s}>\n {connectionStatusLabels[s]}\n </option>\n ))}\n </select>\n\n <select\n value={adapterId}\n onChange={(e) => {\n setAdapterId(e.target.value);\n setOffset(0);\n }}\n aria-label={t('adaptercloud.connections.filterByAdapter', 'Filter by adapter')}\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.connections.allAdapters', 'All adapters')}</option>\n {adapterOptions.map((a) => (\n <option key={a.id} value={a.id}>\n {a.name}\n </option>\n ))}\n </select>\n\n <div className=\"relative w-full sm:ml-auto sm:w-64\">\n <Search\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\"\n />\n <input\n type=\"search\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n aria-label={t('adaptercloud.connections.search', 'Search connections')}\n placeholder={t('adaptercloud.connections.searchPlaceholder', 'Search…')}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface py-2 pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\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.connections.emptyTitle', 'No connections yet')}\n emptyDescription={t(\n 'adaptercloud.connections.emptyDescription',\n 'Create a connection to a real target to start discovering resources.'\n )}\n emptyIcon={<Cable className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90\"\n >\n {t('adaptercloud.connections.new', 'New connection')}\n </button>\n }\n >\n {filtered.length === 0 ? (\n <p className=\"rounded-xl border border-border-subtle bg-bg-surface px-4 py-10 text-center text-sm text-text-secondary\">\n {t('adaptercloud.connections.noSearchMatch', 'No connections match your search.')}\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((conn) => {\n const KindIcon = conn.adapter?.kind ? adapterKindIcon[conn.adapter.kind] : Cable;\n return (\n <GlassCard\n key={conn.id}\n role=\"button\"\n tabIndex={0}\n onClick={() => navigateTo(`/connections/${conn.id}`)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n navigateTo(`/connections/${conn.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 gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-accent-blue\">\n <KindIcon className=\"h-5 w-5\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\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 {conn.name}\n </h3>\n {conn.adapter && (\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">\n {conn.adapter.name}\n </p>\n )}\n </div>\n <StatusBadge status={conn.status} />\n </div>\n </div>\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-3 text-xs text-text-secondary\">\n <span className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5\">\n {authMethodLabels[conn.authMethod]}\n </span>\n {conn.region && (\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3 w-3\" /> {conn.region}\n </span>\n )}\n {conn.environment && <span>· {conn.environment}</span>}\n </div>\n\n <div className=\"mt-4 flex items-center gap-2 text-sm text-text-primary\">\n <Server className=\"h-4 w-4 text-text-secondary\" />\n <span className=\"font-semibold tabular-nums\">{conn.resourceCount}</span>\n <span className=\"text-text-secondary\">\n {t('adaptercloud.connections.resources', 'resources')}\n </span>\n </div>\n\n {conn.lastError && (\n <p className=\"mt-3 line-clamp-2 rounded-lg bg-status-error-bg-subtle px-2 py-1 text-xs text-status-error-text\">\n {conn.lastError}\n </p>\n )}\n\n <p className=\"mt-4 text-xs text-text-secondary\">\n {conn.lastSyncedAt\n ? `${t('adaptercloud.connections.lastSynced', 'Last synced')} ${formatRelativeTime(conn.lastSyncedAt)}`\n : t('adaptercloud.connections.neverSynced', 'Never synced')}\n </p>\n </GlassCard>\n );\n })}\n </div>\n )}\n\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageContext.d.ts","sourceRoot":"","sources":["../../src/utils/pageContext.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,wBAAwB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAG1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAoB/C;AAMD,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,wBAAwB,
|
|
1
|
+
{"version":3,"file":"pageContext.d.ts","sourceRoot":"","sources":["../../src/utils/pageContext.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,wBAAwB;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAG1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,iBAAiB,IAAI,WAAW,CAoB/C;AAMD,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,wBAAwB,CA+D1B"}
|
|
@@ -17,12 +17,29 @@ function t(e, t) {
|
|
|
17
17
|
return t.match(e);
|
|
18
18
|
}
|
|
19
19
|
function n(e, n) {
|
|
20
|
-
let r = new URLSearchParams(n)
|
|
20
|
+
let r = new URLSearchParams(n), i = new Map([
|
|
21
|
+
["/adaptercloud/adapters", "ADAPTERCLOUD_ADAPTER"],
|
|
22
|
+
["/adaptercloud/adapters/new", "ADAPTERCLOUD_ADAPTER"],
|
|
23
|
+
["/adaptercloud/connections", "ADAPTERCLOUD_CONNECTION"],
|
|
24
|
+
["/adaptercloud/connections/new", "ADAPTERCLOUD_CONNECTION"],
|
|
25
|
+
["/adaptercloud/resources", "ADAPTERCLOUD_RESOURCE"],
|
|
26
|
+
["/adaptercloud/topology", "ADAPTERCLOUD_TOPOLOGY"],
|
|
27
|
+
["/adaptercloud/policies", "ADAPTERCLOUD_POLICY"],
|
|
28
|
+
["/adaptercloud/policies/new", "ADAPTERCLOUD_POLICY"],
|
|
29
|
+
["/adaptercloud/violations", "ADAPTERCLOUD_VIOLATION"],
|
|
30
|
+
["/adaptercloud/drift", "ADAPTERCLOUD_DRIFT"],
|
|
31
|
+
["/adaptercloud/sync-runs", "ADAPTERCLOUD_SYNC_RUN"],
|
|
32
|
+
["/adaptercloud/costs", "ADAPTERCLOUD_COST"]
|
|
33
|
+
]).get(e);
|
|
34
|
+
if (i) return {
|
|
35
|
+
entityType: i,
|
|
36
|
+
metadata: { routePattern: e }
|
|
37
|
+
};
|
|
21
38
|
for (let [n, r] of [
|
|
22
|
-
[/^\/adaptercloud\/adapters\/([^/]+)
|
|
23
|
-
[/^\/adaptercloud\/connections\/([^/]+)
|
|
39
|
+
[/^\/adaptercloud\/adapters\/([^/]+)(?:\/edit)?$/, "ADAPTERCLOUD_ADAPTER"],
|
|
40
|
+
[/^\/adaptercloud\/connections\/([^/]+)(?:\/edit)?$/, "ADAPTERCLOUD_CONNECTION"],
|
|
24
41
|
[/^\/adaptercloud\/resources\/([^/]+)$/, "ADAPTERCLOUD_RESOURCE"],
|
|
25
|
-
[/^\/adaptercloud\/policies\/([^/]+)
|
|
42
|
+
[/^\/adaptercloud\/policies\/([^/]+)(?:\/edit)?$/, "ADAPTERCLOUD_POLICY"],
|
|
26
43
|
[/^\/adaptercloud\/sync-runs\/([^/]+)$/, "ADAPTERCLOUD_SYNC_RUN"]
|
|
27
44
|
]) {
|
|
28
45
|
let i = t(n, e);
|
|
@@ -32,13 +49,13 @@ function n(e, n) {
|
|
|
32
49
|
metadata: { routePattern: n.source }
|
|
33
50
|
};
|
|
34
51
|
}
|
|
35
|
-
let
|
|
52
|
+
let a = r.get("tab") ?? (() => {
|
|
36
53
|
let t = e.split("/").filter(Boolean);
|
|
37
54
|
return t.length > 2 ? t[t.length - 1] : void 0;
|
|
38
55
|
})();
|
|
39
56
|
return {
|
|
40
|
-
activeTab:
|
|
41
|
-
metadata: { ...
|
|
57
|
+
activeTab: a ?? void 0,
|
|
58
|
+
metadata: { ...a ? { activeTab: a } : {} }
|
|
42
59
|
};
|
|
43
60
|
}
|
|
44
61
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageContext.js","names":[],"sources":["../../src/utils/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering — captures the user's current browser context\n * to be sent alongside every assistant prompt for better AI awareness.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n entityType?: string;\n entityId?: string;\n platform: string;\n version: string;\n viewportSize: string;\n userAgent: string;\n timestamp: string;\n}\n\nexport function gatherPageContext(): PageContext {\n const url = window.location.href;\n const pathSegments = window.location.pathname.split('/').filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join('/') || 'home';\n const entity = resolveAdapterCloudConversationContext(\n window.location.pathname,\n window.location.search\n );\n\n return {\n currentUrl: url,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n platform: 'adaptercloud',\n version: import.meta.env.VITE_APP_VERSION ?? '2026.707.1',\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction matchPath(pattern: RegExp, pathname: string): RegExpMatchArray | null {\n return pathname.match(pattern);\n}\n\nexport function resolveAdapterCloudConversationContext(\n pathname: string,\n search: string\n): ConversationContextShape {\n const params = new URLSearchParams(search);\n const directMatches: Array<[RegExp, string]> = [\n [/^\\/adaptercloud\\/adapters\\/([^/]+)
|
|
1
|
+
{"version":3,"file":"pageContext.js","names":[],"sources":["../../src/utils/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering — captures the user's current browser context\n * to be sent alongside every assistant prompt for better AI awareness.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n entityType?: string;\n entityId?: string;\n platform: string;\n version: string;\n viewportSize: string;\n userAgent: string;\n timestamp: string;\n}\n\nexport function gatherPageContext(): PageContext {\n const url = window.location.href;\n const pathSegments = window.location.pathname.split('/').filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join('/') || 'home';\n const entity = resolveAdapterCloudConversationContext(\n window.location.pathname,\n window.location.search\n );\n\n return {\n currentUrl: url,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n platform: 'adaptercloud',\n version: import.meta.env.VITE_APP_VERSION ?? '2026.707.1',\n viewportSize: `${window.innerWidth}x${window.innerHeight}`,\n userAgent: navigator.userAgent,\n timestamp: new Date().toISOString(),\n };\n}\n\nfunction matchPath(pattern: RegExp, pathname: string): RegExpMatchArray | null {\n return pathname.match(pattern);\n}\n\nexport function resolveAdapterCloudConversationContext(\n pathname: string,\n search: string\n): ConversationContextShape {\n const params = new URLSearchParams(search);\n\n // List, tool, and creation routes still identify the product entity family,\n // but intentionally carry no entityId. This lets the assistant understand\n // \"this page\" without fabricating a record identifier from route words such\n // as `new` (BOFF-3697).\n const pageMatches = new Map<string, string>([\n ['/adaptercloud/adapters', 'ADAPTERCLOUD_ADAPTER'],\n ['/adaptercloud/adapters/new', 'ADAPTERCLOUD_ADAPTER'],\n ['/adaptercloud/connections', 'ADAPTERCLOUD_CONNECTION'],\n ['/adaptercloud/connections/new', 'ADAPTERCLOUD_CONNECTION'],\n ['/adaptercloud/resources', 'ADAPTERCLOUD_RESOURCE'],\n ['/adaptercloud/topology', 'ADAPTERCLOUD_TOPOLOGY'],\n ['/adaptercloud/policies', 'ADAPTERCLOUD_POLICY'],\n ['/adaptercloud/policies/new', 'ADAPTERCLOUD_POLICY'],\n ['/adaptercloud/violations', 'ADAPTERCLOUD_VIOLATION'],\n ['/adaptercloud/drift', 'ADAPTERCLOUD_DRIFT'],\n ['/adaptercloud/sync-runs', 'ADAPTERCLOUD_SYNC_RUN'],\n ['/adaptercloud/costs', 'ADAPTERCLOUD_COST'],\n ]);\n const pageEntityType = pageMatches.get(pathname);\n if (pageEntityType) {\n return {\n entityType: pageEntityType,\n metadata: { routePattern: pathname },\n };\n }\n\n const directMatches: Array<[RegExp, string]> = [\n [/^\\/adaptercloud\\/adapters\\/([^/]+)(?:\\/edit)?$/, 'ADAPTERCLOUD_ADAPTER'],\n [/^\\/adaptercloud\\/connections\\/([^/]+)(?:\\/edit)?$/, 'ADAPTERCLOUD_CONNECTION'],\n [/^\\/adaptercloud\\/resources\\/([^/]+)$/, 'ADAPTERCLOUD_RESOURCE'],\n [/^\\/adaptercloud\\/policies\\/([^/]+)(?:\\/edit)?$/, 'ADAPTERCLOUD_POLICY'],\n [/^\\/adaptercloud\\/sync-runs\\/([^/]+)$/, 'ADAPTERCLOUD_SYNC_RUN'],\n ];\n\n for (const [pattern, entityType] of directMatches) {\n const match = matchPath(pattern, pathname);\n if (match) {\n return {\n entityType,\n entityId: match[1],\n metadata: {\n routePattern: pattern.source,\n },\n };\n }\n }\n\n const activeTab =\n params.get('tab') ??\n (() => {\n const segments = pathname.split('/').filter(Boolean);\n return segments.length > 2 ? segments[segments.length - 1] : undefined;\n })();\n\n return {\n activeTab: activeTab ?? undefined,\n metadata: {\n ...(activeTab ? { activeTab } : {}),\n },\n };\n}\n"],"mappings":";AA0BA,SAAgB,IAAiC;CAC/C,IAAM,IAAM,OAAO,SAAS,MAEtB,IADe,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,OAAO,OAC5C,EAAa,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,QACpD,IAAS,EACb,OAAO,SAAS,UAChB,OAAO,SAAS,MAClB;CAEA,OAAO;EACL,YAAY;EACZ;EACA,YAAY,EAAO;EACnB,UAAU,EAAO;EACjB,UAAU;EACV,SAA6C;EAC7C,cAAc,GAAG,OAAO,WAAW,GAAG,OAAO;EAC7C,WAAW,UAAU;EACrB,4BAAW,IAAI,KAAK,GAAE,YAAY;CACpC;AACF;AAEA,SAAS,EAAU,GAAiB,GAA2C;CAC7E,OAAO,EAAS,MAAM,CAAO;AAC/B;AAEA,SAAgB,EACd,GACA,GAC0B;CAC1B,IAAM,IAAS,IAAI,gBAAgB,CAAM,GAoBnC,IAAiB,IAdC,IAAoB;EAC1C,CAAC,0BAA0B,sBAAsB;EACjD,CAAC,8BAA8B,sBAAsB;EACrD,CAAC,6BAA6B,yBAAyB;EACvD,CAAC,iCAAiC,yBAAyB;EAC3D,CAAC,2BAA2B,uBAAuB;EACnD,CAAC,0BAA0B,uBAAuB;EAClD,CAAC,0BAA0B,qBAAqB;EAChD,CAAC,8BAA8B,qBAAqB;EACpD,CAAC,4BAA4B,wBAAwB;EACrD,CAAC,uBAAuB,oBAAoB;EAC5C,CAAC,2BAA2B,uBAAuB;EACnD,CAAC,uBAAuB,mBAAmB;CAC7C,CACuB,EAAY,IAAI,CAAQ;CAC/C,IAAI,GACF,OAAO;EACL,YAAY;EACZ,UAAU,EAAE,cAAc,EAAS;CACrC;CAWF,KAAK,IAAM,CAAC,GAAS,MAAe;EAPlC,CAAC,kDAAkD,sBAAsB;EACzE,CAAC,qDAAqD,yBAAyB;EAC/E,CAAC,wCAAwC,uBAAuB;EAChE,CAAC,kDAAkD,qBAAqB;EACxE,CAAC,wCAAwC,uBAAuB;CAG9B,GAAe;EACjD,IAAM,IAAQ,EAAU,GAAS,CAAQ;EACzC,IAAI,GACF,OAAO;GACL;GACA,UAAU,EAAM;GAChB,UAAU,EACR,cAAc,EAAQ,OACxB;EACF;CAEJ;CAEA,IAAM,IACJ,EAAO,IAAI,KAAK,YACT;EACL,IAAM,IAAW,EAAS,MAAM,GAAG,EAAE,OAAO,OAAO;EACnD,OAAO,EAAS,SAAS,IAAI,EAAS,EAAS,SAAS,KAAK,KAAA;CAC/D,GAAG;CAEL,OAAO;EACL,WAAW,KAAa,KAAA;EACxB,UAAU,EACR,GAAI,IAAY,EAAE,aAAU,IAAI,CAAC,EACnC;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-adaptercloud",
|
|
3
|
-
"version": "2026.825.
|
|
3
|
+
"version": "2026.825.4",
|
|
4
4
|
"description": "Burdenoff AdapterCloud Microfrontend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -34,9 +34,10 @@
|
|
|
34
34
|
"lint:sanity": "if [ \"${CI:-}\" = \"true\" ]; then bun run lint; else bun run lint -- --cache --cache-location .eslintcache; fi",
|
|
35
35
|
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
|
|
36
36
|
"type:check": "bash scripts/build-limits.sh tsc --noEmit",
|
|
37
|
-
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run lint:sanity && bun run format && bun run type:check && bun run build && bun run build-storybook'",
|
|
37
|
+
"sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run codegen && bun run lint:sanity && bun run format && bun run type:check && bun run test && bun run build && bun run build-storybook'",
|
|
38
38
|
"storybook": "storybook dev -p 6006",
|
|
39
39
|
"build-storybook": "storybook build",
|
|
40
|
+
"test": "bun test",
|
|
40
41
|
"test:storybook": "test-storybook",
|
|
41
42
|
"switch:status": "bun scripts/deps-mode.ts status",
|
|
42
43
|
"switch:remote": "bun scripts/deps-mode.ts remote",
|
|
@@ -83,14 +84,15 @@
|
|
|
83
84
|
"eslint-plugin-react": "^7.37.5",
|
|
84
85
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
85
86
|
"lefthook": "^2.1.1",
|
|
86
|
-
"postcss": "^8.
|
|
87
|
+
"postcss": "^8.5.26",
|
|
87
88
|
"prettier": "^3.4.2",
|
|
88
89
|
"storybook": "^8.6.0",
|
|
89
90
|
"tailwindcss": "^4.0.0",
|
|
90
91
|
"typescript": "^5.9.0",
|
|
91
92
|
"typescript-eslint": "^8.46.0",
|
|
92
93
|
"vite": "8.0.16",
|
|
93
|
-
"vite-plugin-dts": "3.9.1"
|
|
94
|
+
"vite-plugin-dts": "3.9.1",
|
|
95
|
+
"vitest": "^4.1.11"
|
|
94
96
|
},
|
|
95
97
|
"peerDependencies": {
|
|
96
98
|
"@apollo/client": "^4.0.11",
|
|
@@ -109,12 +111,13 @@
|
|
|
109
111
|
"fast-xml-parser": ">=4.5.5",
|
|
110
112
|
"@xmldom/xmldom": ">=0.8.12",
|
|
111
113
|
"swiper": ">=12.1.2",
|
|
112
|
-
"brace-expansion": ">=
|
|
114
|
+
"brace-expansion": ">=5.0.8",
|
|
113
115
|
"follow-redirects": ">=1.15.12",
|
|
114
116
|
"smol-toml": ">=1.6.1",
|
|
115
117
|
"axios": ">=1.15.0",
|
|
116
118
|
"flatted": ">=3.4.1",
|
|
117
119
|
"yaml": ">=2.8.3",
|
|
120
|
+
"js-yaml": "4.3.1",
|
|
118
121
|
"picomatch": ">=2.3.2",
|
|
119
122
|
"immutable": ">=3.8.3",
|
|
120
123
|
"minimatch": ">=3.1.3"
|