@burdenoff/microfe-adaptercloud 2026.625.2 → 2026.628.1
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/AdapterCloudRoot.js +65 -121
- package/dist/adaptercloud/AdapterCloudRoot.js.map +1 -1
- package/dist/adaptercloud/AdapterCloudRoutes.js +70 -182
- package/dist/adaptercloud/AdapterCloudRoutes.js.map +1 -1
- package/dist/adaptercloud/components/DataState.js +42 -0
- package/dist/adaptercloud/components/DataState.js.map +1 -0
- package/dist/adaptercloud/components/SeverityBadge.js +12 -0
- package/dist/adaptercloud/components/SeverityBadge.js.map +1 -0
- package/dist/adaptercloud/components/StatusBadge.js +43 -44
- package/dist/adaptercloud/components/StatusBadge.js.map +1 -1
- package/dist/adaptercloud/context/AdapterCloudContext.js +22 -30
- package/dist/adaptercloud/context/AdapterCloudContext.js.map +1 -1
- package/dist/adaptercloud/hooks/useAdapterCloudApi.js +397 -194
- package/dist/adaptercloud/hooks/useAdapterCloudApi.js.map +1 -1
- package/dist/adaptercloud/index.js +1 -0
- package/dist/adaptercloud/pages/OverviewPage.js +334 -0
- package/dist/adaptercloud/pages/OverviewPage.js.map +1 -0
- package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js +187 -0
- package/dist/adaptercloud/pages/adapters/AdapterDetailPage.js.map +1 -0
- package/dist/adaptercloud/pages/adapters/AdapterFormPage.js +278 -0
- package/dist/adaptercloud/pages/adapters/AdapterFormPage.js.map +1 -0
- package/dist/adaptercloud/pages/adapters/AdaptersListPage.js +172 -0
- package/dist/adaptercloud/pages/adapters/AdaptersListPage.js.map +1 -0
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js +247 -0
- package/dist/adaptercloud/pages/connections/ConnectionDetailPage.js.map +1 -0
- package/dist/adaptercloud/pages/connections/ConnectionFormPage.js +271 -0
- package/dist/adaptercloud/pages/connections/ConnectionFormPage.js.map +1 -0
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js +167 -0
- package/dist/adaptercloud/pages/connections/ConnectionsListPage.js.map +1 -0
- package/dist/adaptercloud/pages/costs/CostsPage.js +169 -0
- package/dist/adaptercloud/pages/costs/CostsPage.js.map +1 -0
- package/dist/adaptercloud/pages/drift/DriftListPage.js +132 -0
- package/dist/adaptercloud/pages/drift/DriftListPage.js.map +1 -0
- package/dist/adaptercloud/pages/policies/PoliciesListPage.js +171 -0
- package/dist/adaptercloud/pages/policies/PoliciesListPage.js.map +1 -0
- package/dist/adaptercloud/pages/policies/PolicyDetailPage.js +185 -0
- package/dist/adaptercloud/pages/policies/PolicyDetailPage.js.map +1 -0
- package/dist/adaptercloud/pages/policies/PolicyFormPage.js +215 -0
- package/dist/adaptercloud/pages/policies/PolicyFormPage.js.map +1 -0
- package/dist/adaptercloud/pages/resources/ResourceDetailPage.js +207 -0
- package/dist/adaptercloud/pages/resources/ResourceDetailPage.js.map +1 -0
- package/dist/adaptercloud/pages/resources/ResourcesListPage.js +182 -0
- package/dist/adaptercloud/pages/resources/ResourcesListPage.js.map +1 -0
- package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js +196 -0
- package/dist/adaptercloud/pages/sync-runs/SyncRunsListPage.js.map +1 -0
- package/dist/adaptercloud/pages/violations/ViolationsListPage.js +258 -0
- package/dist/adaptercloud/pages/violations/ViolationsListPage.js.map +1 -0
- package/dist/adaptercloud/store/adaptercloudStore.js +1 -7
- package/dist/adaptercloud/store/adaptercloudStore.js.map +1 -1
- package/dist/adaptercloud/utils/domain.js +105 -0
- package/dist/adaptercloud/utils/domain.js.map +1 -0
- package/dist/adaptercloud/utils/formatters.js +1 -12
- package/dist/adaptercloud/utils/formatters.js.map +1 -1
- package/dist/index.js +5 -4
- package/package.json +1 -1
- package/dist/adaptercloud/components/InvestmentCard.js +0 -98
- package/dist/adaptercloud/components/InvestmentCard.js.map +0 -1
- package/dist/adaptercloud/components/RatingDisplay.js +0 -35
- package/dist/adaptercloud/components/RatingDisplay.js.map +0 -1
- package/dist/adaptercloud/mocks/data.js +0 -1517
- package/dist/adaptercloud/mocks/data.js.map +0 -1
- package/dist/adaptercloud/mocks/users.js +0 -34
- package/dist/adaptercloud/mocks/users.js.map +0 -1
- package/dist/adaptercloud/pages/HomePage.js +0 -934
- package/dist/adaptercloud/pages/HomePage.js.map +0 -1
- package/dist/adaptercloud/pages/admin/AdminAnalyticsPage.js +0 -653
- package/dist/adaptercloud/pages/admin/AdminAnalyticsPage.js.map +0 -1
- package/dist/adaptercloud/pages/admin/AdminDashboard.js +0 -665
- package/dist/adaptercloud/pages/admin/AdminDashboard.js.map +0 -1
- package/dist/adaptercloud/pages/admin/AdminFinancialPage.js +0 -426
- package/dist/adaptercloud/pages/admin/AdminFinancialPage.js.map +0 -1
- package/dist/adaptercloud/pages/admin/AdminOrdersPage.js +0 -665
- package/dist/adaptercloud/pages/admin/AdminOrdersPage.js.map +0 -1
- package/dist/adaptercloud/pages/admin/AdminProfilePage.js +0 -261
- package/dist/adaptercloud/pages/admin/AdminProfilePage.js.map +0 -1
- package/dist/adaptercloud/pages/admin/AdminSettingsPage.js +0 -663
- package/dist/adaptercloud/pages/admin/AdminSettingsPage.js.map +0 -1
- package/dist/adaptercloud/pages/admin/CartManagementPage.js +0 -874
- package/dist/adaptercloud/pages/admin/CartManagementPage.js.map +0 -1
- package/dist/adaptercloud/pages/admin/UserManagementPage.js +0 -898
- package/dist/adaptercloud/pages/admin/UserManagementPage.js.map +0 -1
- package/dist/adaptercloud/pages/cart-owner/AnalyticsDashboard.js +0 -840
- package/dist/adaptercloud/pages/cart-owner/AnalyticsDashboard.js.map +0 -1
- package/dist/adaptercloud/pages/cart-owner/BusinessSettingsPage.js +0 -714
- package/dist/adaptercloud/pages/cart-owner/BusinessSettingsPage.js.map +0 -1
- package/dist/adaptercloud/pages/cart-owner/CartOwnerDashboard.js +0 -788
- package/dist/adaptercloud/pages/cart-owner/CartOwnerDashboard.js.map +0 -1
- package/dist/adaptercloud/pages/cart-owner/CartOwnerProfilePage.js +0 -888
- package/dist/adaptercloud/pages/cart-owner/CartOwnerProfilePage.js.map +0 -1
- package/dist/adaptercloud/pages/cart-owner/CartServiceConfigPage.js +0 -634
- package/dist/adaptercloud/pages/cart-owner/CartServiceConfigPage.js.map +0 -1
- package/dist/adaptercloud/pages/cart-owner/InventoryManagementPage.js +0 -907
- package/dist/adaptercloud/pages/cart-owner/InventoryManagementPage.js.map +0 -1
- package/dist/adaptercloud/pages/cart-owner/OrderManagementPage.js +0 -875
- package/dist/adaptercloud/pages/cart-owner/OrderManagementPage.js.map +0 -1
- package/dist/adaptercloud/pages/cart-owner/StaffManagementPage.js +0 -827
- package/dist/adaptercloud/pages/cart-owner/StaffManagementPage.js.map +0 -1
- package/dist/adaptercloud/pages/common/HelpSupportPage.js +0 -1329
- package/dist/adaptercloud/pages/common/HelpSupportPage.js.map +0 -1
- package/dist/adaptercloud/pages/common/NotificationCenterPage.js +0 -671
- package/dist/adaptercloud/pages/common/NotificationCenterPage.js.map +0 -1
- package/dist/adaptercloud/pages/common/SettingsPage.js +0 -982
- package/dist/adaptercloud/pages/common/SettingsPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/BookingDetailsPage.js +0 -596
- package/dist/adaptercloud/pages/customer/BookingDetailsPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/CartDetailPage.js +0 -623
- package/dist/adaptercloud/pages/customer/CartDetailPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/CartDiscoveryPage.js +0 -552
- package/dist/adaptercloud/pages/customer/CartDiscoveryPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/CheckoutPage.js +0 -534
- package/dist/adaptercloud/pages/customer/CheckoutPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/CustomerDashboard.js +0 -525
- package/dist/adaptercloud/pages/customer/CustomerDashboard.js.map +0 -1
- package/dist/adaptercloud/pages/customer/CustomerProfilePage.js +0 -623
- package/dist/adaptercloud/pages/customer/CustomerProfilePage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/DirectServiceBookingPage.js +0 -629
- package/dist/adaptercloud/pages/customer/DirectServiceBookingPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/FavoritesPage.js +0 -480
- package/dist/adaptercloud/pages/customer/FavoritesPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/OrderHistoryPage.js +0 -444
- package/dist/adaptercloud/pages/customer/OrderHistoryPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/OrderTrackingPage.js +0 -391
- package/dist/adaptercloud/pages/customer/OrderTrackingPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/PaymentMethodsPage.js +0 -504
- package/dist/adaptercloud/pages/customer/PaymentMethodsPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/ReviewsPage.js +0 -609
- package/dist/adaptercloud/pages/customer/ReviewsPage.js.map +0 -1
- package/dist/adaptercloud/pages/customer/SavedAddressesPage.js +0 -459
- package/dist/adaptercloud/pages/customer/SavedAddressesPage.js.map +0 -1
- package/dist/adaptercloud/pages/investor/InvestmentDetailsPage.js +0 -851
- package/dist/adaptercloud/pages/investor/InvestmentDetailsPage.js.map +0 -1
- package/dist/adaptercloud/pages/investor/InvestmentOpportunitiesPage.js +0 -942
- package/dist/adaptercloud/pages/investor/InvestmentOpportunitiesPage.js.map +0 -1
- package/dist/adaptercloud/pages/investor/InvestorAnalyticsPage.js +0 -683
- package/dist/adaptercloud/pages/investor/InvestorAnalyticsPage.js.map +0 -1
- package/dist/adaptercloud/pages/investor/InvestorDashboard.js +0 -452
- package/dist/adaptercloud/pages/investor/InvestorDashboard.js.map +0 -1
- package/dist/adaptercloud/pages/investor/InvestorInvestmentsPage.js +0 -402
- package/dist/adaptercloud/pages/investor/InvestorInvestmentsPage.js.map +0 -1
- package/dist/adaptercloud/pages/investor/InvestorPortfolioPage.js +0 -571
- package/dist/adaptercloud/pages/investor/InvestorPortfolioPage.js.map +0 -1
- package/dist/adaptercloud/pages/investor/InvestorProfilePage.js +0 -1067
- package/dist/adaptercloud/pages/investor/InvestorProfilePage.js.map +0 -1
- package/dist/adaptercloud/pages/worker/TaskDetailsPage.js +0 -526
- package/dist/adaptercloud/pages/worker/TaskDetailsPage.js.map +0 -1
- package/dist/adaptercloud/pages/worker/WorkerDashboard.js +0 -659
- package/dist/adaptercloud/pages/worker/WorkerDashboard.js.map +0 -1
- package/dist/adaptercloud/pages/worker/WorkerOrdersPage.js +0 -678
- package/dist/adaptercloud/pages/worker/WorkerOrdersPage.js.map +0 -1
- package/dist/adaptercloud/pages/worker/WorkerProfilePage.js +0 -689
- package/dist/adaptercloud/pages/worker/WorkerProfilePage.js.map +0 -1
- package/dist/adaptercloud/pages/worker/WorkerSchedulePage.js +0 -582
- package/dist/adaptercloud/pages/worker/WorkerSchedulePage.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SyncRunsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/sync-runs/SyncRunsListPage.tsx"],"sourcesContent":["/**\n * Sync Runs History Page\n * @module adaptercloud/pages/sync-runs\n *\n * The operations log (`adaListSyncRuns`) — every discovery / reconcile /\n * cost-ingest / full execution with its lifecycle and counters. Filters by\n * status; queued/running runs can be cancelled via `adaCancelSyncRun`.\n */\n\nimport { useState, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n Activity,\n ChevronLeft,\n ChevronRight,\n XCircle,\n Loader2,\n Server,\n GitCompareArrows,\n ShieldAlert,\n RotateCcw,\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 { useSyncRuns, useCancelSyncRun } from '../../hooks/useAdapterCloudApi';\nimport { syncKindLabels, syncStatusLabels } from '../../utils/domain';\nimport { formatDate, formatRelativeTime } from '../../utils/formatters';\nimport type { AdaSyncStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nexport function SyncRunsListPage() {\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<AdaSyncStatus | ''>('');\n const [offset, setOffset] = useState(0);\n const [actionError, setActionError] = useState<string | null>(null);\n\n const query = useSyncRuns({\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n const cancel = useCancelSyncRun();\n\n const items = query.data?.items ?? [];\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n const handleCancel = useCallback(\n (id: string) => {\n setActionError(null);\n cancel.mutate(id, {\n onError: (err) =>\n setActionError(err instanceof Error ? err.message : 'Failed to cancel run.'),\n });\n },\n [cancel]\n );\n\n return (\n <PageLayout\n title={t('adaptercloud.syncRuns.title', 'Sync Runs')}\n description={t(\n 'adaptercloud.syncRuns.subtitle',\n 'Discovery, reconciliation and cost-ingest executions that keep the picture live.'\n )}\n >\n <div className=\"mb-6 flex flex-wrap gap-3\">\n <select\n value={status}\n onChange={(e) => {\n setStatus(e.target.value as AdaSyncStatus | '');\n setOffset(0);\n }}\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.syncRuns.allStatuses', 'All statuses')}</option>\n {(Object.keys(syncStatusLabels) as AdaSyncStatus[]).map((s) => (\n <option key={s} value={s}>\n {syncStatusLabels[s]}\n </option>\n ))}\n </select>\n </div>\n\n {actionError && (\n <p className=\"mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {actionError}\n </p>\n )}\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.syncRuns.emptyTitle', 'No sync runs yet')}\n emptyDescription={t(\n 'adaptercloud.syncRuns.emptyDescription',\n 'Start a sync run from a connection to keep the inventory current.'\n )}\n emptyIcon={<Activity className=\"h-10 w-10\" />}\n emptyAction={\n <button\n type=\"button\"\n onClick={() => navigateTo('/connections')}\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.syncRuns.goToConnections', 'Go to connections')}\n </button>\n }\n >\n <div className=\"space-y-3\">\n {items.map((run) => {\n const cancellable = run.status === 'QUEUED' || run.status === 'RUNNING';\n return (\n <GlassCard key={run.id} className=\"p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-1.5 flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-semibold text-text-primary\">\n {syncKindLabels[run.kind]}\n </span>\n <StatusBadge status={run.status} />\n </div>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <Server className=\"h-3.5 w-3.5\" /> {run.discoveredCount}{' '}\n {t('adaptercloud.syncRuns.discovered', 'discovered')}\n </span>\n <span className=\"flex items-center gap-1\">\n <RotateCcw className=\"h-3.5 w-3.5\" /> {run.reconciledCount}{' '}\n {t('adaptercloud.syncRuns.reconciled', 'reconciled')}\n </span>\n <span className=\"flex items-center gap-1\">\n <GitCompareArrows className=\"h-3.5 w-3.5\" /> {run.driftCount}{' '}\n {t('adaptercloud.syncRuns.drift', 'drift')}\n </span>\n <span className=\"flex items-center gap-1\">\n <ShieldAlert className=\"h-3.5 w-3.5\" /> {run.violationCount}{' '}\n {t('adaptercloud.syncRuns.violations', 'violations')}\n </span>\n </div>\n <p className=\"mt-2 text-xs text-text-secondary\">\n {run.startedAt\n ? `${t('adaptercloud.syncRuns.started', 'Started')} ${formatDate(run.startedAt)}`\n : `${t('adaptercloud.syncRuns.created', 'Created')} ${formatRelativeTime(run.createdAt)}`}\n {run.finishedAt &&\n ` · ${t('adaptercloud.syncRuns.finished', 'Finished')} ${formatDate(run.finishedAt)}`}\n {' · '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/connections/${run.connectionId}`)}\n className=\"hover:underline\"\n >\n {t('adaptercloud.syncRuns.viewConnection', 'View connection')}\n </button>\n </p>\n {run.error && (\n <p className=\"mt-2 rounded-lg bg-status-error-bg-subtle px-3 py-1.5 text-xs text-status-error-text\">\n {run.error}\n </p>\n )}\n </div>\n\n {cancellable && (\n <button\n type=\"button\"\n disabled={cancel.isPending}\n onClick={() => handleCancel(run.id)}\n className=\"inline-flex shrink-0 items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-50\"\n >\n {cancel.isPending ? (\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <XCircle className=\"h-3.5 w-3.5\" />\n )}\n {t('adaptercloud.syncRuns.cancel', 'Cancel')}\n </button>\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\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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"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { useAdapterCloud as e } from "../../context/AdapterCloudContext.js";
|
|
2
|
+
import { PageLayout as t } from "../../components/PageLayout.js";
|
|
3
|
+
import { severityRank as n, violationStatusLabels as r } from "../../utils/domain.js";
|
|
4
|
+
import { StatusBadge as i } from "../../components/StatusBadge.js";
|
|
5
|
+
import { SeverityBadge as a } from "../../components/SeverityBadge.js";
|
|
6
|
+
import { DataState as o } from "../../components/DataState.js";
|
|
7
|
+
import { useResolveViolation as s, useViolations as c } from "../../hooks/useAdapterCloudApi.js";
|
|
8
|
+
import { formatDate as l } from "../../utils/formatters.js";
|
|
9
|
+
import { useCallback as u, useState as d } from "react";
|
|
10
|
+
import { useI18n as f } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
|
+
import { Check as p, CheckCheck as m, ChevronLeft as h, ChevronRight as g, FileText as _, Loader2 as v, ShieldAlert as y } from "lucide-react";
|
|
12
|
+
import { useSearchParams as b } from "react-router-dom";
|
|
13
|
+
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
14
|
+
import { GlassCard as C, ResponsiveDialog as w, ResponsiveDialogContent as T, ResponsiveDialogFooter as E, ResponsiveDialogHeader as D, ResponsiveDialogTitle as O } from "@burdenoff/fe-libs/ui";
|
|
15
|
+
//#region src/adaptercloud/pages/violations/ViolationsListPage.tsx
|
|
16
|
+
var k = 20;
|
|
17
|
+
function A() {
|
|
18
|
+
let { navigateTo: A } = e(), [j] = b(), M = j.get("policyId") ?? void 0, N = j.get("resourceId") ?? void 0, { t: P } = f(), F = u((e, t) => {
|
|
19
|
+
let n = P(e);
|
|
20
|
+
return n === e ? t : n;
|
|
21
|
+
}, [P]), [I, L] = d("OPEN"), [R, z] = d(0), [B, V] = d(null), [H, U] = d(""), [W, G] = d(null), K = c({
|
|
22
|
+
policyId: M,
|
|
23
|
+
resourceId: N,
|
|
24
|
+
status: I || void 0,
|
|
25
|
+
pagination: {
|
|
26
|
+
limit: k,
|
|
27
|
+
offset: R
|
|
28
|
+
}
|
|
29
|
+
}), q = s(), J = [...K.data?.items ?? []].sort((e, t) => n[t.severity] - n[e.severity]), Y = K.data?.pageInfo.hasMore ?? !1, X = u((e) => G(e instanceof Error ? e.message : "Action failed. Please try again."), []), Z = u((e, t) => {
|
|
30
|
+
G(null), q.mutate({
|
|
31
|
+
id: e,
|
|
32
|
+
status: t
|
|
33
|
+
}, { onError: X });
|
|
34
|
+
}, [q, X]), Q = u(() => {
|
|
35
|
+
if (B) {
|
|
36
|
+
if (!H.trim()) {
|
|
37
|
+
G(F("adaptercloud.violations.reasonRequired", "A waiver requires a reason."));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
G(null), q.mutate({
|
|
41
|
+
id: B.id,
|
|
42
|
+
status: "WAIVED",
|
|
43
|
+
waiverReason: H.trim()
|
|
44
|
+
}, {
|
|
45
|
+
onSuccess: () => {
|
|
46
|
+
V(null), U("");
|
|
47
|
+
},
|
|
48
|
+
onError: X
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}, [
|
|
52
|
+
B,
|
|
53
|
+
H,
|
|
54
|
+
q,
|
|
55
|
+
X,
|
|
56
|
+
F
|
|
57
|
+
]);
|
|
58
|
+
return /* @__PURE__ */ S(t, {
|
|
59
|
+
title: F("adaptercloud.violations.title", "Violations"),
|
|
60
|
+
description: F("adaptercloud.violations.subtitle", "Work the governance queue — acknowledge, resolve, or waive policy breaches."),
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ S("div", {
|
|
63
|
+
className: "mb-6 flex flex-wrap items-center gap-3",
|
|
64
|
+
children: [/* @__PURE__ */ S("select", {
|
|
65
|
+
value: I,
|
|
66
|
+
onChange: (e) => {
|
|
67
|
+
L(e.target.value), z(0);
|
|
68
|
+
},
|
|
69
|
+
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)]",
|
|
70
|
+
children: [/* @__PURE__ */ x("option", {
|
|
71
|
+
value: "",
|
|
72
|
+
children: F("adaptercloud.violations.allStatuses", "All statuses")
|
|
73
|
+
}), Object.keys(r).map((e) => /* @__PURE__ */ x("option", {
|
|
74
|
+
value: e,
|
|
75
|
+
children: r[e]
|
|
76
|
+
}, e))]
|
|
77
|
+
}), (M || N) && /* @__PURE__ */ x("button", {
|
|
78
|
+
type: "button",
|
|
79
|
+
onClick: () => A("/violations"),
|
|
80
|
+
className: "inline-flex items-center gap-1.5 rounded-full bg-accent-blue-subtle px-2.5 py-1 text-xs text-accent-blue hover:underline",
|
|
81
|
+
children: F("adaptercloud.violations.clearScope", "Clear scope ×")
|
|
82
|
+
})]
|
|
83
|
+
}),
|
|
84
|
+
W && /* @__PURE__ */ x("p", {
|
|
85
|
+
className: "mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text",
|
|
86
|
+
children: W
|
|
87
|
+
}),
|
|
88
|
+
/* @__PURE__ */ S(o, {
|
|
89
|
+
isLoading: K.isLoading,
|
|
90
|
+
isError: K.isError,
|
|
91
|
+
isEmpty: J.length === 0,
|
|
92
|
+
error: K.error,
|
|
93
|
+
onRetry: () => void K.refetch(),
|
|
94
|
+
emptyTitle: F("adaptercloud.violations.emptyTitle", "No violations"),
|
|
95
|
+
emptyDescription: F("adaptercloud.violations.emptyDescription", "Nothing matches this filter — your estate is clean here."),
|
|
96
|
+
emptyIcon: /* @__PURE__ */ x(y, { className: "h-10 w-10" }),
|
|
97
|
+
children: [/* @__PURE__ */ x("div", {
|
|
98
|
+
className: "space-y-3",
|
|
99
|
+
children: J.map((e) => {
|
|
100
|
+
let t = e.status === "OPEN" || e.status === "ACKNOWLEDGED";
|
|
101
|
+
return /* @__PURE__ */ x(C, {
|
|
102
|
+
className: "p-5",
|
|
103
|
+
children: /* @__PURE__ */ S("div", {
|
|
104
|
+
className: "flex flex-wrap items-start justify-between gap-3",
|
|
105
|
+
children: [/* @__PURE__ */ S("div", {
|
|
106
|
+
className: "min-w-0 flex-1",
|
|
107
|
+
children: [
|
|
108
|
+
/* @__PURE__ */ S("div", {
|
|
109
|
+
className: "mb-1.5 flex flex-wrap items-center gap-2",
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ x(a, { severity: e.severity }),
|
|
112
|
+
/* @__PURE__ */ x(i, { status: e.status }),
|
|
113
|
+
e.policy && /* @__PURE__ */ x("button", {
|
|
114
|
+
type: "button",
|
|
115
|
+
onClick: () => A(`/policies/${e.policyId}`),
|
|
116
|
+
className: "text-xs font-medium text-primary hover:underline",
|
|
117
|
+
children: e.policy.name
|
|
118
|
+
})
|
|
119
|
+
]
|
|
120
|
+
}),
|
|
121
|
+
/* @__PURE__ */ x("p", {
|
|
122
|
+
className: "text-sm font-medium text-text-primary",
|
|
123
|
+
children: e.message
|
|
124
|
+
}),
|
|
125
|
+
/* @__PURE__ */ S("p", {
|
|
126
|
+
className: "mt-1 text-xs text-text-secondary",
|
|
127
|
+
children: [
|
|
128
|
+
F("adaptercloud.violations.detected", "Detected"),
|
|
129
|
+
" ",
|
|
130
|
+
l(e.detectedAt),
|
|
131
|
+
" · ",
|
|
132
|
+
/* @__PURE__ */ x("button", {
|
|
133
|
+
type: "button",
|
|
134
|
+
onClick: () => A(`/resources/${e.resourceId}`),
|
|
135
|
+
className: "hover:underline",
|
|
136
|
+
children: F("adaptercloud.violations.viewResource", "View resource")
|
|
137
|
+
})
|
|
138
|
+
]
|
|
139
|
+
}),
|
|
140
|
+
e.waiverReason && /* @__PURE__ */ S("p", {
|
|
141
|
+
className: "mt-2 rounded-lg bg-bg-sunken px-3 py-1.5 text-xs text-text-secondary",
|
|
142
|
+
children: [
|
|
143
|
+
F("adaptercloud.violations.waiver", "Waiver"),
|
|
144
|
+
": ",
|
|
145
|
+
e.waiverReason
|
|
146
|
+
]
|
|
147
|
+
})
|
|
148
|
+
]
|
|
149
|
+
}), t && /* @__PURE__ */ S("div", {
|
|
150
|
+
className: "flex shrink-0 flex-wrap gap-2",
|
|
151
|
+
children: [
|
|
152
|
+
e.status === "OPEN" && /* @__PURE__ */ S("button", {
|
|
153
|
+
type: "button",
|
|
154
|
+
disabled: q.isPending,
|
|
155
|
+
onClick: () => Z(e.id, "ACKNOWLEDGED"),
|
|
156
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-accent disabled:opacity-50",
|
|
157
|
+
children: [/* @__PURE__ */ x(p, { className: "h-3.5 w-3.5" }), F("adaptercloud.violations.acknowledge", "Acknowledge")]
|
|
158
|
+
}),
|
|
159
|
+
/* @__PURE__ */ S("button", {
|
|
160
|
+
type: "button",
|
|
161
|
+
disabled: q.isPending,
|
|
162
|
+
onClick: () => Z(e.id, "RESOLVED"),
|
|
163
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-50",
|
|
164
|
+
children: [/* @__PURE__ */ x(m, { className: "h-3.5 w-3.5" }), F("adaptercloud.violations.resolve", "Resolve")]
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ S("button", {
|
|
167
|
+
type: "button",
|
|
168
|
+
disabled: q.isPending,
|
|
169
|
+
onClick: () => {
|
|
170
|
+
G(null), U(""), V(e);
|
|
171
|
+
},
|
|
172
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-secondary transition-colors hover:bg-accent disabled:opacity-50",
|
|
173
|
+
children: [/* @__PURE__ */ x(_, { className: "h-3.5 w-3.5" }), F("adaptercloud.violations.waive", "Waive")]
|
|
174
|
+
})
|
|
175
|
+
]
|
|
176
|
+
})]
|
|
177
|
+
})
|
|
178
|
+
}, e.id);
|
|
179
|
+
})
|
|
180
|
+
}), (R > 0 || Y) && /* @__PURE__ */ S("div", {
|
|
181
|
+
className: "mt-6 flex items-center justify-between",
|
|
182
|
+
children: [
|
|
183
|
+
/* @__PURE__ */ S("button", {
|
|
184
|
+
type: "button",
|
|
185
|
+
disabled: R === 0,
|
|
186
|
+
onClick: () => z((e) => Math.max(0, e - k)),
|
|
187
|
+
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",
|
|
188
|
+
children: [/* @__PURE__ */ x(h, { className: "h-4 w-4" }), F("adaptercloud.common.prev", "Previous")]
|
|
189
|
+
}),
|
|
190
|
+
/* @__PURE__ */ S("span", {
|
|
191
|
+
className: "text-sm text-text-secondary",
|
|
192
|
+
children: [
|
|
193
|
+
F("adaptercloud.common.showing", "Showing"),
|
|
194
|
+
" ",
|
|
195
|
+
R + 1,
|
|
196
|
+
"–",
|
|
197
|
+
R + J.length
|
|
198
|
+
]
|
|
199
|
+
}),
|
|
200
|
+
/* @__PURE__ */ S("button", {
|
|
201
|
+
type: "button",
|
|
202
|
+
disabled: !Y,
|
|
203
|
+
onClick: () => z((e) => e + k),
|
|
204
|
+
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",
|
|
205
|
+
children: [F("adaptercloud.common.next", "Next"), /* @__PURE__ */ x(g, { className: "h-4 w-4" })]
|
|
206
|
+
})
|
|
207
|
+
]
|
|
208
|
+
})]
|
|
209
|
+
}),
|
|
210
|
+
/* @__PURE__ */ x(w, {
|
|
211
|
+
open: !!B,
|
|
212
|
+
onOpenChange: (e) => {
|
|
213
|
+
e || V(null);
|
|
214
|
+
},
|
|
215
|
+
children: /* @__PURE__ */ S(T, { children: [
|
|
216
|
+
/* @__PURE__ */ x(D, { children: /* @__PURE__ */ x(O, { children: F("adaptercloud.violations.waiveTitle", "Waive violation") }) }),
|
|
217
|
+
/* @__PURE__ */ S("div", {
|
|
218
|
+
className: "px-1 py-2",
|
|
219
|
+
children: [
|
|
220
|
+
/* @__PURE__ */ x("p", {
|
|
221
|
+
className: "mb-3 text-sm text-text-secondary",
|
|
222
|
+
children: F("adaptercloud.violations.waivePrompt", "A waiver requires a documented reason and is recorded on the violation.")
|
|
223
|
+
}),
|
|
224
|
+
/* @__PURE__ */ x("textarea", {
|
|
225
|
+
value: H,
|
|
226
|
+
onChange: (e) => U(e.target.value),
|
|
227
|
+
rows: 4,
|
|
228
|
+
autoFocus: !0,
|
|
229
|
+
placeholder: F("adaptercloud.violations.waiveReasonPlaceholder", "Why is this acceptable?"),
|
|
230
|
+
className: "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
|
|
231
|
+
}),
|
|
232
|
+
W && /* @__PURE__ */ x("p", {
|
|
233
|
+
className: "mt-2 text-sm text-status-error-text",
|
|
234
|
+
children: W
|
|
235
|
+
})
|
|
236
|
+
]
|
|
237
|
+
}),
|
|
238
|
+
/* @__PURE__ */ S(E, { children: [/* @__PURE__ */ x("button", {
|
|
239
|
+
type: "button",
|
|
240
|
+
onClick: () => V(null),
|
|
241
|
+
className: "rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent",
|
|
242
|
+
children: F("adaptercloud.common.cancel", "Cancel")
|
|
243
|
+
}), /* @__PURE__ */ S("button", {
|
|
244
|
+
type: "button",
|
|
245
|
+
disabled: q.isPending,
|
|
246
|
+
onClick: Q,
|
|
247
|
+
className: "inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90 disabled:opacity-50",
|
|
248
|
+
children: [q.isPending && /* @__PURE__ */ x(v, { className: "h-4 w-4 animate-spin" }), F("adaptercloud.violations.confirmWaive", "Waive")]
|
|
249
|
+
})] })
|
|
250
|
+
] })
|
|
251
|
+
})
|
|
252
|
+
]
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
//#endregion
|
|
256
|
+
export { A as ViolationsListPage };
|
|
257
|
+
|
|
258
|
+
//# sourceMappingURL=ViolationsListPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ViolationsListPage.js","names":[],"sources":["../../../../src/adaptercloud/pages/violations/ViolationsListPage.tsx"],"sourcesContent":["/**\n * Violations Queue Page\n * @module adaptercloud/pages/violations\n *\n * The governance work queue (`adaListViolations`). Filters by status (and by\n * policy/resource via URL params). Each open/acknowledged violation can be\n * transitioned via `adaResolveViolation` — acknowledge, resolve, or waive (a\n * waiver requires a reason, enforced both client-side and at the service).\n */\n\nimport { useState, useCallback } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n ShieldAlert,\n ChevronLeft,\n ChevronRight,\n Check,\n CheckCheck,\n FileText,\n Loader2,\n} from 'lucide-react';\nimport { GlassCard, ResponsiveDialog, ResponsiveDialogContent, ResponsiveDialogHeader, ResponsiveDialogTitle, ResponsiveDialogFooter } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { SeverityBadge } from '../../components/SeverityBadge';\nimport { DataState } from '../../components/DataState';\nimport { useAdapterCloud } from '../../context/AdapterCloudContext';\nimport { useViolations, useResolveViolation } from '../../hooks/useAdapterCloudApi';\nimport { violationStatusLabels, severityRank } from '../../utils/domain';\nimport { formatDate } from '../../utils/formatters';\nimport type { AdaPolicyViolation, AdaViolationStatus } from '../../types';\n\nconst PAGE_SIZE = 20;\n\nexport function ViolationsListPage() {\n const { navigateTo } = useAdapterCloud();\n const [searchParams] = useSearchParams();\n const policyId = searchParams.get('policyId') ?? undefined;\n const resourceId = searchParams.get('resourceId') ?? undefined;\n\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<AdaViolationStatus | ''>('OPEN');\n const [offset, setOffset] = useState(0);\n const [waiveTarget, setWaiveTarget] = useState<AdaPolicyViolation | null>(null);\n const [waiverReason, setWaiverReason] = useState('');\n const [actionError, setActionError] = useState<string | null>(null);\n\n const query = useViolations({\n policyId,\n resourceId,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset },\n });\n const resolve = useResolveViolation();\n\n const items = [...(query.data?.items ?? [])].sort(\n (a, b) => severityRank[b.severity] - severityRank[a.severity]\n );\n const hasMore = query.data?.pageInfo.hasMore ?? false;\n\n const onError = useCallback(\n (err: unknown) =>\n setActionError(err instanceof Error ? err.message : 'Action failed. Please try again.'),\n []\n );\n\n const transition = useCallback(\n (id: string, newStatus: AdaViolationStatus) => {\n setActionError(null);\n resolve.mutate({ id, status: newStatus }, { onError });\n },\n [resolve, onError]\n );\n\n const confirmWaive = useCallback(() => {\n if (!waiveTarget) return;\n if (!waiverReason.trim()) {\n setActionError(t('adaptercloud.violations.reasonRequired', 'A waiver requires a reason.'));\n return;\n }\n setActionError(null);\n resolve.mutate(\n { id: waiveTarget.id, status: 'WAIVED', waiverReason: waiverReason.trim() },\n {\n onSuccess: () => {\n setWaiveTarget(null);\n setWaiverReason('');\n },\n onError,\n }\n );\n }, [waiveTarget, waiverReason, resolve, onError, t]);\n\n return (\n <PageLayout\n title={t('adaptercloud.violations.title', 'Violations')}\n description={t(\n 'adaptercloud.violations.subtitle',\n 'Work the governance queue — acknowledge, resolve, or waive policy breaches.'\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 AdaViolationStatus | '');\n setOffset(0);\n }}\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.violations.allStatuses', 'All statuses')}</option>\n {(Object.keys(violationStatusLabels) as AdaViolationStatus[]).map((s) => (\n <option key={s} value={s}>\n {violationStatusLabels[s]}\n </option>\n ))}\n </select>\n {(policyId || resourceId) && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/violations')}\n className=\"inline-flex items-center gap-1.5 rounded-full bg-accent-blue-subtle px-2.5 py-1 text-xs text-accent-blue hover:underline\"\n >\n {t('adaptercloud.violations.clearScope', 'Clear scope ×')}\n </button>\n )}\n </div>\n\n {actionError && (\n <p className=\"mb-4 rounded-lg bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {actionError}\n </p>\n )}\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.violations.emptyTitle', 'No violations')}\n emptyDescription={t(\n 'adaptercloud.violations.emptyDescription',\n 'Nothing matches this filter — your estate is clean here.'\n )}\n emptyIcon={<ShieldAlert className=\"h-10 w-10\" />}\n >\n <div className=\"space-y-3\">\n {items.map((v) => {\n const isOpen = v.status === 'OPEN' || v.status === 'ACKNOWLEDGED';\n return (\n <GlassCard key={v.id} className=\"p-5\">\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"mb-1.5 flex flex-wrap items-center gap-2\">\n <SeverityBadge severity={v.severity} />\n <StatusBadge status={v.status} />\n {v.policy && (\n <button\n type=\"button\"\n onClick={() => navigateTo(`/policies/${v.policyId}`)}\n className=\"text-xs font-medium text-primary hover:underline\"\n >\n {v.policy.name}\n </button>\n )}\n </div>\n <p className=\"text-sm font-medium text-text-primary\">{v.message}</p>\n <p className=\"mt-1 text-xs text-text-secondary\">\n {t('adaptercloud.violations.detected', 'Detected')} {formatDate(v.detectedAt)}\n {' · '}\n <button\n type=\"button\"\n onClick={() => navigateTo(`/resources/${v.resourceId}`)}\n className=\"hover:underline\"\n >\n {t('adaptercloud.violations.viewResource', 'View resource')}\n </button>\n </p>\n {v.waiverReason && (\n <p className=\"mt-2 rounded-lg bg-bg-sunken px-3 py-1.5 text-xs text-text-secondary\">\n {t('adaptercloud.violations.waiver', 'Waiver')}: {v.waiverReason}\n </p>\n )}\n </div>\n\n {isOpen && (\n <div className=\"flex shrink-0 flex-wrap gap-2\">\n {v.status === 'OPEN' && (\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => transition(v.id, 'ACKNOWLEDGED')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-accent disabled:opacity-50\"\n >\n <Check className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.acknowledge', 'Acknowledge')}\n </button>\n )}\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => transition(v.id, 'RESOLVED')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-50\"\n >\n <CheckCheck className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.resolve', 'Resolve')}\n </button>\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={() => {\n setActionError(null);\n setWaiverReason('');\n setWaiveTarget(v);\n }}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-secondary transition-colors hover:bg-accent disabled:opacity-50\"\n >\n <FileText className=\"h-3.5 w-3.5\" />\n {t('adaptercloud.violations.waive', 'Waive')}\n </button>\n </div>\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\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\n {/* Waive dialog */}\n <ResponsiveDialog\n open={Boolean(waiveTarget)}\n onOpenChange={(open) => {\n if (!open) setWaiveTarget(null);\n }}\n >\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {t('adaptercloud.violations.waiveTitle', 'Waive violation')}\n </ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <div className=\"px-1 py-2\">\n <p className=\"mb-3 text-sm text-text-secondary\">\n {t(\n 'adaptercloud.violations.waivePrompt',\n 'A waiver requires a documented reason and is recorded on the violation.'\n )}\n </p>\n <textarea\n value={waiverReason}\n onChange={(e) => setWaiverReason(e.target.value)}\n rows={4}\n autoFocus\n placeholder={t('adaptercloud.violations.waiveReasonPlaceholder', 'Why is this acceptable?')}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n {actionError && (\n <p className=\"mt-2 text-sm text-status-error-text\">{actionError}</p>\n )}\n </div>\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={() => setWaiveTarget(null)}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-accent\"\n >\n {t('adaptercloud.common.cancel', 'Cancel')}\n </button>\n <button\n type=\"button\"\n disabled={resolve.isPending}\n onClick={confirmWaive}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:opacity-90 disabled:opacity-50\"\n >\n {resolve.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n {t('adaptercloud.violations.confirmWaive', 'Waive')}\n </button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,19 +6,13 @@ var i = {
|
|
|
6
6
|
viewMode: "grid",
|
|
7
7
|
activeSection: "dashboard",
|
|
8
8
|
sidebarCollapsed: !1,
|
|
9
|
-
searchQuery: ""
|
|
10
|
-
categoryFilter: "",
|
|
11
|
-
selectedCartId: null,
|
|
12
|
-
selectedOrderId: null
|
|
9
|
+
searchQuery: ""
|
|
13
10
|
}, a = e()(t(n((e) => ({
|
|
14
11
|
...i,
|
|
15
12
|
setViewMode: (t) => e({ viewMode: t }),
|
|
16
13
|
setActiveSection: (t) => e({ activeSection: t }),
|
|
17
14
|
toggleSidebar: () => e((e) => ({ sidebarCollapsed: !e.sidebarCollapsed })),
|
|
18
15
|
setSearchQuery: (t) => e({ searchQuery: t }),
|
|
19
|
-
setCategoryFilter: (t) => e({ categoryFilter: t }),
|
|
20
|
-
setSelectedCartId: (t) => e({ selectedCartId: t }),
|
|
21
|
-
setSelectedOrderId: (t) => e({ selectedOrderId: t }),
|
|
22
16
|
reset: () => e(i)
|
|
23
17
|
}), {
|
|
24
18
|
name: "burdenoff-adaptercloud-storage",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adaptercloudStore.js","names":[],"sources":["../../../src/adaptercloud/store/adaptercloudStore.ts"],"sourcesContent":["/**\n * AdapterCloud Zustand Store\n * @module adaptercloud/store\n */\n\nimport { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\nimport { createProfileScopedStorage } from '@burdenoff/fe-libs/shared/utils';\nimport type { ViewMode } from '../types';\n\n// ============================================================================\n// State Interface\n// ============================================================================\n\ninterface AdapterCloudState {\n // View state\n viewMode: ViewMode;\n activeSection: string;\n sidebarCollapsed: boolean;\n\n // Search
|
|
1
|
+
{"version":3,"file":"adaptercloudStore.js","names":[],"sources":["../../../src/adaptercloud/store/adaptercloudStore.ts"],"sourcesContent":["/**\n * AdapterCloud Zustand Store\n * @module adaptercloud/store\n *\n * Local, persisted UI state for the AdapterCloud MFE (view mode, the active\n * domain section, sidebar collapse, and the global search term). Server state\n * lives in React Query — this store holds only view preferences.\n */\n\nimport { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\nimport { createProfileScopedStorage } from '@burdenoff/fe-libs/shared/utils';\nimport type { ViewMode } from '../types';\n\n// ============================================================================\n// State Interface\n// ============================================================================\n\ninterface AdapterCloudState {\n // View state\n viewMode: ViewMode;\n activeSection: string;\n sidebarCollapsed: boolean;\n\n // Search\n searchQuery: string;\n\n // Actions\n setViewMode: (mode: ViewMode) => void;\n setActiveSection: (section: string) => void;\n setSearchQuery: (query: string) => void;\n toggleSidebar: () => void;\n reset: () => void;\n}\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst initialState = {\n viewMode: 'grid' as ViewMode,\n activeSection: 'dashboard',\n sidebarCollapsed: false,\n searchQuery: '',\n};\n\n// ============================================================================\n// Store\n// ============================================================================\n\nexport const useAdapterCloudStore = create<AdapterCloudState>()(\n devtools(\n persist(\n (set) => ({\n ...initialState,\n\n setViewMode: (mode) => set({ viewMode: mode }),\n setActiveSection: (section) => set({ activeSection: section }),\n toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),\n setSearchQuery: (query) => set({ searchQuery: query }),\n\n reset: () => set(initialState),\n }),\n {\n name: 'burdenoff-adaptercloud-storage',\n storage: createProfileScopedStorage(),\n partialize: (state) => ({\n viewMode: state.viewMode,\n sidebarCollapsed: state.sidebarCollapsed,\n activeSection: state.activeSection,\n }),\n }\n ),\n { name: 'AdapterCloud Store', enabled: import.meta.env.DEV }\n )\n);\n"],"mappings":";;;;AAuCA,IAAM,IAAe;CACnB,UAAU;CACV,eAAe;CACf,kBAAkB;CAClB,aAAa;CACd,EAMY,IAAuB,GAA2B,CAC7D,EACE,GACG,OAAS;CACR,GAAG;CAEH,cAAc,MAAS,EAAI,EAAE,UAAU,GAAM,CAAC;CAC9C,mBAAmB,MAAY,EAAI,EAAE,eAAe,GAAS,CAAC;CAC9D,qBAAqB,GAAK,OAAW,EAAE,kBAAkB,CAAC,EAAM,kBAAkB,EAAE;CACpF,iBAAiB,MAAU,EAAI,EAAE,aAAa,GAAO,CAAC;CAEtD,aAAa,EAAI,EAAa;CAC/B,GACD;CACE,MAAM;CACN,SAAS,GAA4B;CACrC,aAAa,OAAW;EACtB,UAAU,EAAM;EAChB,kBAAkB,EAAM;EACxB,eAAe,EAAM;EACtB;CACF,CACF,EACD;CAAE,MAAM;CAAsB,SAAA;CAA8B,CAC7D,CACF"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
//#region src/adaptercloud/utils/domain.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
return e.toLowerCase().split("_").map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join(" ");
|
|
4
|
+
}
|
|
5
|
+
var t = {
|
|
6
|
+
CUSTOM: "Custom",
|
|
7
|
+
DATA_SYSTEM: "Data System",
|
|
8
|
+
EDGE: "Edge",
|
|
9
|
+
KUBERNETES: "Kubernetes",
|
|
10
|
+
NETWORK: "Network",
|
|
11
|
+
ON_PREM: "On-Prem",
|
|
12
|
+
PRIVATE_CLOUD: "Private Cloud",
|
|
13
|
+
PUBLIC_CLOUD: "Public Cloud",
|
|
14
|
+
SAAS: "SaaS"
|
|
15
|
+
}, n = {
|
|
16
|
+
ARCHIVED: "Archived",
|
|
17
|
+
DEPRECATED: "Deprecated",
|
|
18
|
+
DRAFT: "Draft",
|
|
19
|
+
PUBLISHED: "Published"
|
|
20
|
+
}, r = {
|
|
21
|
+
API_KEY: "API Key",
|
|
22
|
+
CERTIFICATE: "Certificate",
|
|
23
|
+
IAM_ROLE: "IAM Role",
|
|
24
|
+
NONE: "None",
|
|
25
|
+
OAUTH2: "OAuth2",
|
|
26
|
+
SERVICE_ACCOUNT: "Service Account"
|
|
27
|
+
}, i = {
|
|
28
|
+
CONNECTED: "Connected",
|
|
29
|
+
DEGRADED: "Degraded",
|
|
30
|
+
DISABLED: "Disabled",
|
|
31
|
+
ERROR: "Error",
|
|
32
|
+
PENDING: "Pending"
|
|
33
|
+
}, a = {
|
|
34
|
+
DELETED: "Deleted",
|
|
35
|
+
DISCOVERED: "Discovered",
|
|
36
|
+
DRIFTED: "Drifted",
|
|
37
|
+
ORPHANED: "Orphaned",
|
|
38
|
+
RECONCILED: "Reconciled"
|
|
39
|
+
}, o = {
|
|
40
|
+
COMPLIANCE: "Compliance",
|
|
41
|
+
COST: "Cost",
|
|
42
|
+
GUARDRAIL: "Guardrail",
|
|
43
|
+
NAMING: "Naming",
|
|
44
|
+
SECURITY: "Security",
|
|
45
|
+
TAGGING: "Tagging"
|
|
46
|
+
}, s = {
|
|
47
|
+
ADVISORY: "Advisory",
|
|
48
|
+
BLOCK: "Block",
|
|
49
|
+
WARN: "Warn"
|
|
50
|
+
}, c = {
|
|
51
|
+
CRITICAL: "Critical",
|
|
52
|
+
HIGH: "High",
|
|
53
|
+
INFO: "Info",
|
|
54
|
+
LOW: "Low",
|
|
55
|
+
MEDIUM: "Medium"
|
|
56
|
+
}, l = {
|
|
57
|
+
ACKNOWLEDGED: "Acknowledged",
|
|
58
|
+
OPEN: "Open",
|
|
59
|
+
RESOLVED: "Resolved",
|
|
60
|
+
WAIVED: "Waived"
|
|
61
|
+
}, u = {
|
|
62
|
+
ACKNOWLEDGED: "Acknowledged",
|
|
63
|
+
DETECTED: "Detected",
|
|
64
|
+
IGNORED: "Ignored",
|
|
65
|
+
REMEDIATED: "Remediated"
|
|
66
|
+
}, d = {
|
|
67
|
+
COST_INGEST: "Cost Ingest",
|
|
68
|
+
DISCOVERY: "Discovery",
|
|
69
|
+
FULL: "Full",
|
|
70
|
+
RECONCILE: "Reconcile"
|
|
71
|
+
}, f = {
|
|
72
|
+
CANCELLED: "Cancelled",
|
|
73
|
+
FAILED: "Failed",
|
|
74
|
+
QUEUED: "Queued",
|
|
75
|
+
RUNNING: "Running",
|
|
76
|
+
SUCCEEDED: "Succeeded"
|
|
77
|
+
}, p = {
|
|
78
|
+
CRITICAL: 5,
|
|
79
|
+
HIGH: 4,
|
|
80
|
+
MEDIUM: 3,
|
|
81
|
+
LOW: 2,
|
|
82
|
+
INFO: 1
|
|
83
|
+
}, m = {
|
|
84
|
+
CRITICAL: "bg-status-error-bg-subtle text-status-error-text",
|
|
85
|
+
HIGH: "bg-status-error-bg-subtle text-status-error-text",
|
|
86
|
+
MEDIUM: "bg-status-warning-bg-subtle text-status-warning-text",
|
|
87
|
+
LOW: "bg-accent-blue-subtle text-accent-blue",
|
|
88
|
+
INFO: "bg-bg-sunken text-text-secondary"
|
|
89
|
+
};
|
|
90
|
+
function h(e, t = "USD") {
|
|
91
|
+
try {
|
|
92
|
+
return new Intl.NumberFormat("en-US", {
|
|
93
|
+
style: "currency",
|
|
94
|
+
currency: t,
|
|
95
|
+
minimumFractionDigits: 2,
|
|
96
|
+
maximumFractionDigits: 2
|
|
97
|
+
}).format(e);
|
|
98
|
+
} catch {
|
|
99
|
+
return `${t} ${e.toFixed(2)}`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
export { t as adapterKindLabels, n as adapterStatusLabels, r as authMethodLabels, i as connectionStatusLabels, u as driftStatusLabels, h as formatMoney, e as humanizeEnum, s as policyEnforcementLabels, o as policyKindLabels, a as resourceStateLabels, c as severityLabels, m as severityPillClass, p as severityRank, d as syncKindLabels, f as syncStatusLabels, l as violationStatusLabels };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=domain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain.js","names":[],"sources":["../../../src/adaptercloud/utils/domain.ts"],"sourcesContent":["/**\n * AdapterCloud domain helpers\n * @module adaptercloud/utils\n *\n * Human-readable labels and severity/status ordering for the AdapterCloud\n * domain enums, plus a USD-default money formatter (cost records carry their\n * own currency). Keeps page components free of inline enum-to-label maps.\n */\n\nimport type {\n AdaAdapterKind,\n AdaAdapterStatus,\n AdaAuthMethod,\n AdaConnectionStatus,\n AdaDriftStatus,\n AdaPolicyEnforcement,\n AdaPolicyKind,\n AdaResourceState,\n AdaSeverity,\n AdaSyncKind,\n AdaSyncStatus,\n AdaViolationStatus,\n} from '../types';\n\n/** Title-case an UPPER_SNAKE enum value into a readable label. */\nexport function humanizeEnum(value: string): string {\n return value\n .toLowerCase()\n .split('_')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(' ');\n}\n\nexport const adapterKindLabels: Record<AdaAdapterKind, string> = {\n CUSTOM: 'Custom',\n DATA_SYSTEM: 'Data System',\n EDGE: 'Edge',\n KUBERNETES: 'Kubernetes',\n NETWORK: 'Network',\n ON_PREM: 'On-Prem',\n PRIVATE_CLOUD: 'Private Cloud',\n PUBLIC_CLOUD: 'Public Cloud',\n SAAS: 'SaaS',\n};\n\nexport const adapterStatusLabels: Record<AdaAdapterStatus, string> = {\n ARCHIVED: 'Archived',\n DEPRECATED: 'Deprecated',\n DRAFT: 'Draft',\n PUBLISHED: 'Published',\n};\n\nexport const authMethodLabels: Record<AdaAuthMethod, string> = {\n API_KEY: 'API Key',\n CERTIFICATE: 'Certificate',\n IAM_ROLE: 'IAM Role',\n NONE: 'None',\n OAUTH2: 'OAuth2',\n SERVICE_ACCOUNT: 'Service Account',\n};\n\nexport const connectionStatusLabels: Record<AdaConnectionStatus, string> = {\n CONNECTED: 'Connected',\n DEGRADED: 'Degraded',\n DISABLED: 'Disabled',\n ERROR: 'Error',\n PENDING: 'Pending',\n};\n\nexport const resourceStateLabels: Record<AdaResourceState, string> = {\n DELETED: 'Deleted',\n DISCOVERED: 'Discovered',\n DRIFTED: 'Drifted',\n ORPHANED: 'Orphaned',\n RECONCILED: 'Reconciled',\n};\n\nexport const policyKindLabels: Record<AdaPolicyKind, string> = {\n COMPLIANCE: 'Compliance',\n COST: 'Cost',\n GUARDRAIL: 'Guardrail',\n NAMING: 'Naming',\n SECURITY: 'Security',\n TAGGING: 'Tagging',\n};\n\nexport const policyEnforcementLabels: Record<AdaPolicyEnforcement, string> = {\n ADVISORY: 'Advisory',\n BLOCK: 'Block',\n WARN: 'Warn',\n};\n\nexport const severityLabels: Record<AdaSeverity, string> = {\n CRITICAL: 'Critical',\n HIGH: 'High',\n INFO: 'Info',\n LOW: 'Low',\n MEDIUM: 'Medium',\n};\n\nexport const violationStatusLabels: Record<AdaViolationStatus, string> = {\n ACKNOWLEDGED: 'Acknowledged',\n OPEN: 'Open',\n RESOLVED: 'Resolved',\n WAIVED: 'Waived',\n};\n\nexport const driftStatusLabels: Record<AdaDriftStatus, string> = {\n ACKNOWLEDGED: 'Acknowledged',\n DETECTED: 'Detected',\n IGNORED: 'Ignored',\n REMEDIATED: 'Remediated',\n};\n\nexport const syncKindLabels: Record<AdaSyncKind, string> = {\n COST_INGEST: 'Cost Ingest',\n DISCOVERY: 'Discovery',\n FULL: 'Full',\n RECONCILE: 'Reconcile',\n};\n\nexport const syncStatusLabels: Record<AdaSyncStatus, string> = {\n CANCELLED: 'Cancelled',\n FAILED: 'Failed',\n QUEUED: 'Queued',\n RUNNING: 'Running',\n SUCCEEDED: 'Succeeded',\n};\n\n/** Highest = most urgent. Used to sort violations/drift queues. */\nexport const severityRank: Record<AdaSeverity, number> = {\n CRITICAL: 5,\n HIGH: 4,\n MEDIUM: 3,\n LOW: 2,\n INFO: 1,\n};\n\n/** Tailwind classes (semantic tokens only) for a severity pill. */\nexport const severityPillClass: Record<AdaSeverity, string> = {\n CRITICAL: 'bg-status-error-bg-subtle text-status-error-text',\n HIGH: 'bg-status-error-bg-subtle text-status-error-text',\n MEDIUM: 'bg-status-warning-bg-subtle text-status-warning-text',\n LOW: 'bg-accent-blue-subtle text-accent-blue',\n INFO: 'bg-bg-sunken text-text-secondary',\n};\n\n/**\n * Format a money amount with its currency. AdapterCloud cost is multi-cloud and\n * typically USD; cost records carry an explicit currency code.\n */\nexport function formatMoney(amount: number, currency = 'USD'): string {\n try {\n return new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }).format(amount);\n } catch {\n return `${currency} ${amount.toFixed(2)}`;\n }\n}\n"],"mappings":";AAyBA,SAAgB,EAAa,GAAuB;AAClD,QAAO,EACJ,aAAa,CACb,MAAM,IAAI,CACV,KAAK,MAAS,EAAK,OAAO,EAAE,CAAC,aAAa,GAAG,EAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,IAAI;;AAGd,IAAa,IAAoD;CAC/D,QAAQ;CACR,aAAa;CACb,MAAM;CACN,YAAY;CACZ,SAAS;CACT,SAAS;CACT,eAAe;CACf,cAAc;CACd,MAAM;CACP,EAEY,IAAwD;CACnE,UAAU;CACV,YAAY;CACZ,OAAO;CACP,WAAW;CACZ,EAEY,IAAkD;CAC7D,SAAS;CACT,aAAa;CACb,UAAU;CACV,MAAM;CACN,QAAQ;CACR,iBAAiB;CAClB,EAEY,IAA8D;CACzE,WAAW;CACX,UAAU;CACV,UAAU;CACV,OAAO;CACP,SAAS;CACV,EAEY,IAAwD;CACnE,SAAS;CACT,YAAY;CACZ,SAAS;CACT,UAAU;CACV,YAAY;CACb,EAEY,IAAkD;CAC7D,YAAY;CACZ,MAAM;CACN,WAAW;CACX,QAAQ;CACR,UAAU;CACV,SAAS;CACV,EAEY,IAAgE;CAC3E,UAAU;CACV,OAAO;CACP,MAAM;CACP,EAEY,IAA8C;CACzD,UAAU;CACV,MAAM;CACN,MAAM;CACN,KAAK;CACL,QAAQ;CACT,EAEY,IAA4D;CACvE,cAAc;CACd,MAAM;CACN,UAAU;CACV,QAAQ;CACT,EAEY,IAAoD;CAC/D,cAAc;CACd,UAAU;CACV,SAAS;CACT,YAAY;CACb,EAEY,IAA8C;CACzD,aAAa;CACb,WAAW;CACX,MAAM;CACN,WAAW;CACZ,EAEY,IAAkD;CAC7D,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,WAAW;CACZ,EAGY,IAA4C;CACvD,UAAU;CACV,MAAM;CACN,QAAQ;CACR,KAAK;CACL,MAAM;CACP,EAGY,IAAiD;CAC5D,UAAU;CACV,MAAM;CACN,QAAQ;CACR,KAAK;CACL,MAAM;CACP;AAMD,SAAgB,EAAY,GAAgB,IAAW,OAAe;AACpE,KAAI;AACF,SAAO,IAAI,KAAK,aAAa,SAAS;GACpC,OAAO;GACP;GACA,uBAAuB;GACvB,uBAAuB;GACxB,CAAC,CAAC,OAAO,EAAO;SACX;AACN,SAAO,GAAG,EAAS,GAAG,EAAO,QAAQ,EAAE"}
|
|
@@ -34,18 +34,7 @@ function n(e) {
|
|
|
34
34
|
function r(e, t) {
|
|
35
35
|
return new Intl.NumberFormat("en-IN", t).format(e);
|
|
36
36
|
}
|
|
37
|
-
function i(e) {
|
|
38
|
-
return e < 1 ? `${Math.round(e * 1e3)} m` : e < 10 ? `${e.toFixed(1)} km` : `${Math.round(e)} km`;
|
|
39
|
-
}
|
|
40
|
-
function a(e) {
|
|
41
|
-
if (e < 1) return "instant";
|
|
42
|
-
if (e < 60) return `${e} min`;
|
|
43
|
-
let t = Math.floor(e / 60), n = e % 60;
|
|
44
|
-
if (t < 24) return n === 0 ? `${t}h` : `${t}h ${n}min`;
|
|
45
|
-
let r = Math.floor(t / 24), i = t % 24;
|
|
46
|
-
return i === 0 ? `${r} day${r === 1 ? "" : "s"}` : `${r} day${r === 1 ? "" : "s"} ${i}h`;
|
|
47
|
-
}
|
|
48
37
|
//#endregion
|
|
49
|
-
export { e as formatCurrency, t as formatDate,
|
|
38
|
+
export { e as formatCurrency, t as formatDate, r as formatNumber, n as formatRelativeTime };
|
|
50
39
|
|
|
51
40
|
//# sourceMappingURL=formatters.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatters.js","names":[],"sources":["../../../src/adaptercloud/utils/formatters.ts"],"sourcesContent":["/**\n * Formatting utilities for the AdapterCloud microfrontend\n * @module adaptercloud/utils/formatters\n */\n\n/**\n * Format a number as Indian Rupees (INR) currency\n *\n * @param amount - The numeric amount to format\n * @param options - Optional Intl.NumberFormat options to override defaults\n * @returns Formatted currency string (e.g., \"₹1,200.00\")\n *\n * @example\n * formatCurrency(1200) // => \"₹1,200.00\"\n * formatCurrency(0) // => \"₹0.00\"\n * formatCurrency(1200, { minimumFractionDigits: 0 }) // => \"₹1,200\"\n */\nexport function formatCurrency(\n amount: number,\n options?: Partial<Intl.NumberFormatOptions>\n): string {\n return new Intl.NumberFormat('en-IN', {\n style: 'currency',\n currency: 'INR',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n ...options,\n }).format(amount);\n}\n\n/**\n * Format a date string or Date object into a human-readable format\n *\n * @param date - ISO date string or Date object\n * @param options - Optional Intl.DateTimeFormat options\n * @returns Formatted date string (e.g., \"15 Jan 2024, 4:00 PM\")\n *\n * @example\n * formatDate('2024-01-15T10:30:00Z')\n * // => \"15 Jan 2024, 4:00 PM\" (in IST)\n */\nexport function formatDate(\n date: string | Date,\n options?: Partial<Intl.DateTimeFormatOptions>\n): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n return new Intl.DateTimeFormat('en-IN', {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n ...options,\n }).format(d);\n}\n\n/**\n * Format a date into a relative time string (e.g., \"2 hours ago\")\n *\n * @param date - ISO date string or Date object\n * @returns Human-readable relative time string\n *\n * @example\n * formatRelativeTime('2024-01-15T10:30:00Z') // => \"3 days ago\"\n * formatRelativeTime(new Date()) // => \"just now\"\n */\nexport function formatRelativeTime(date: string | Date): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n const now = new Date();\n const diffMs = now.getTime() - d.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n const diffWeeks = Math.floor(diffDays / 7);\n const diffMonths = Math.floor(diffDays / 30);\n\n if (diffSeconds < 60) return 'just now';\n if (diffMinutes < 60) return `${diffMinutes} min${diffMinutes !== 1 ? 's' : ''} ago`;\n if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;\n if (diffDays < 7) return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`;\n if (diffWeeks < 4) return `${diffWeeks} week${diffWeeks !== 1 ? 's' : ''} ago`;\n if (diffMonths < 12) return `${diffMonths} month${diffMonths !== 1 ? 's' : ''} ago`;\n\n const diffYears = Math.floor(diffDays / 365);\n return `${diffYears} year${diffYears !== 1 ? 's' : ''} ago`;\n}\n\n/**\n * Format a number with Indian locale grouping (lakhs, crores)\n *\n * @param value - The number to format\n * @param options - Optional Intl.NumberFormat options\n * @returns Formatted number string (e.g., \"12,345\" or \"1,24,500\")\n *\n * @example\n * formatNumber(1245) // => \"1,245\"\n * formatNumber(124500) // => \"1,24,500\"\n */\nexport function formatNumber(value: number, options?: Partial<Intl.NumberFormatOptions>): string {\n return new Intl.NumberFormat('en-IN', options).format(value);\n}\n\n/**\n * Format a distance value in kilometers\n *\n * @param km - Distance in kilometers\n * @returns Formatted distance string\n *\n * @example\n * formatDistance(0.5) // => \"500 m\"\n * formatDistance(1.2) // => \"1.2 km\"\n * formatDistance(15) // => \"15 km\"\n */\nexport function formatDistance(km: number): string {\n if (km < 1) {\n return `${Math.round(km * 1000)} m`;\n }\n if (km < 10) {\n return `${km.toFixed(1)} km`;\n }\n return `${Math.round(km)} km`;\n}\n\n/**\n * Format a duration in minutes into a human-readable string\n *\n * @param minutes - Duration in minutes\n * @returns Formatted duration string\n *\n * @example\n * formatDuration(5) // => \"5 min\"\n * formatDuration(90) // => \"1h 30min\"\n * formatDuration(1440) // => \"1 day\"\n * formatDuration(4320) // => \"3 days\"\n */\nexport function formatDuration(minutes: number): string {\n if (minutes < 1) return 'instant';\n if (minutes < 60) return `${minutes} min`;\n\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n\n if (hours < 24) {\n if (remainingMinutes === 0) {\n return `${hours}h`;\n }\n return `${hours}h ${remainingMinutes}min`;\n }\n\n const days = Math.floor(hours / 24);\n const remainingHours = hours % 24;\n\n if (remainingHours === 0) {\n return `${days} day${days !== 1 ? 's' : ''}`;\n }\n return `${days} day${days !== 1 ? 's' : ''} ${remainingHours}h`;\n}\n"],"mappings":";AAiBA,SAAgB,EACd,GACA,GACQ;AACR,QAAO,IAAI,KAAK,aAAa,SAAS;EACpC,OAAO;EACP,UAAU;EACV,uBAAuB;EACvB,uBAAuB;EACvB,GAAG;EACJ,CAAC,CAAC,OAAO,EAAO;;AAcnB,SAAgB,EACd,GACA,GACQ;CACR,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,EAAK,GAAG;AACtD,QAAO,IAAI,KAAK,eAAe,SAAS;EACtC,KAAK;EACL,OAAO;EACP,MAAM;EACN,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,GAAG;EACJ,CAAC,CAAC,OAAO,EAAE;;AAad,SAAgB,EAAmB,GAA6B;CAC9D,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,EAAK,GAAG,GAEhD,qBADM,IAAI,MAAM,EACH,SAAS,GAAG,EAAE,SAAS,EACpC,IAAc,KAAK,MAAM,IAAS,IAAK,EACvC,IAAc,KAAK,MAAM,IAAc,GAAG,EAC1C,IAAY,KAAK,MAAM,IAAc,GAAG,EACxC,IAAW,KAAK,MAAM,IAAY,GAAG,EACrC,IAAY,KAAK,MAAM,IAAW,EAAE,EACpC,IAAa,KAAK,MAAM,IAAW,GAAG;AAE5C,KAAI,IAAc,GAAI,QAAO;AAC7B,KAAI,IAAc,GAAI,QAAO,GAAG,EAAY,MAAM,MAAgB,IAAU,KAAN,IAAS;AAC/E,KAAI,IAAY,GAAI,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;AAC1E,KAAI,IAAW,EAAG,QAAO,GAAG,EAAS,MAAM,MAAa,IAAU,KAAN,IAAS;AACrE,KAAI,IAAY,EAAG,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;AACzE,KAAI,IAAa,GAAI,QAAO,GAAG,EAAW,QAAQ,MAAe,IAAU,KAAN,IAAS;CAE9E,IAAM,IAAY,KAAK,MAAM,IAAW,IAAI;AAC5C,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;;AAcxD,SAAgB,EAAa,GAAe,GAAqD;AAC/F,QAAO,IAAI,KAAK,aAAa,SAAS,EAAQ,CAAC,OAAO,EAAM
|
|
1
|
+
{"version":3,"file":"formatters.js","names":[],"sources":["../../../src/adaptercloud/utils/formatters.ts"],"sourcesContent":["/**\n * Formatting utilities for the AdapterCloud microfrontend\n * @module adaptercloud/utils/formatters\n */\n\n/**\n * Format a number as Indian Rupees (INR) currency\n *\n * @param amount - The numeric amount to format\n * @param options - Optional Intl.NumberFormat options to override defaults\n * @returns Formatted currency string (e.g., \"₹1,200.00\")\n *\n * @example\n * formatCurrency(1200) // => \"₹1,200.00\"\n * formatCurrency(0) // => \"₹0.00\"\n * formatCurrency(1200, { minimumFractionDigits: 0 }) // => \"₹1,200\"\n */\nexport function formatCurrency(\n amount: number,\n options?: Partial<Intl.NumberFormatOptions>\n): string {\n return new Intl.NumberFormat('en-IN', {\n style: 'currency',\n currency: 'INR',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n ...options,\n }).format(amount);\n}\n\n/**\n * Format a date string or Date object into a human-readable format\n *\n * @param date - ISO date string or Date object\n * @param options - Optional Intl.DateTimeFormat options\n * @returns Formatted date string (e.g., \"15 Jan 2024, 4:00 PM\")\n *\n * @example\n * formatDate('2024-01-15T10:30:00Z')\n * // => \"15 Jan 2024, 4:00 PM\" (in IST)\n */\nexport function formatDate(\n date: string | Date,\n options?: Partial<Intl.DateTimeFormatOptions>\n): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n return new Intl.DateTimeFormat('en-IN', {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n ...options,\n }).format(d);\n}\n\n/**\n * Format a date into a relative time string (e.g., \"2 hours ago\")\n *\n * @param date - ISO date string or Date object\n * @returns Human-readable relative time string\n *\n * @example\n * formatRelativeTime('2024-01-15T10:30:00Z') // => \"3 days ago\"\n * formatRelativeTime(new Date()) // => \"just now\"\n */\nexport function formatRelativeTime(date: string | Date): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n const now = new Date();\n const diffMs = now.getTime() - d.getTime();\n const diffSeconds = Math.floor(diffMs / 1000);\n const diffMinutes = Math.floor(diffSeconds / 60);\n const diffHours = Math.floor(diffMinutes / 60);\n const diffDays = Math.floor(diffHours / 24);\n const diffWeeks = Math.floor(diffDays / 7);\n const diffMonths = Math.floor(diffDays / 30);\n\n if (diffSeconds < 60) return 'just now';\n if (diffMinutes < 60) return `${diffMinutes} min${diffMinutes !== 1 ? 's' : ''} ago`;\n if (diffHours < 24) return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;\n if (diffDays < 7) return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`;\n if (diffWeeks < 4) return `${diffWeeks} week${diffWeeks !== 1 ? 's' : ''} ago`;\n if (diffMonths < 12) return `${diffMonths} month${diffMonths !== 1 ? 's' : ''} ago`;\n\n const diffYears = Math.floor(diffDays / 365);\n return `${diffYears} year${diffYears !== 1 ? 's' : ''} ago`;\n}\n\n/**\n * Format a number with Indian locale grouping (lakhs, crores)\n *\n * @param value - The number to format\n * @param options - Optional Intl.NumberFormat options\n * @returns Formatted number string (e.g., \"12,345\" or \"1,24,500\")\n *\n * @example\n * formatNumber(1245) // => \"1,245\"\n * formatNumber(124500) // => \"1,24,500\"\n */\nexport function formatNumber(value: number, options?: Partial<Intl.NumberFormatOptions>): string {\n return new Intl.NumberFormat('en-IN', options).format(value);\n}\n\n/**\n * Format a distance value in kilometers\n *\n * @param km - Distance in kilometers\n * @returns Formatted distance string\n *\n * @example\n * formatDistance(0.5) // => \"500 m\"\n * formatDistance(1.2) // => \"1.2 km\"\n * formatDistance(15) // => \"15 km\"\n */\nexport function formatDistance(km: number): string {\n if (km < 1) {\n return `${Math.round(km * 1000)} m`;\n }\n if (km < 10) {\n return `${km.toFixed(1)} km`;\n }\n return `${Math.round(km)} km`;\n}\n\n/**\n * Format a duration in minutes into a human-readable string\n *\n * @param minutes - Duration in minutes\n * @returns Formatted duration string\n *\n * @example\n * formatDuration(5) // => \"5 min\"\n * formatDuration(90) // => \"1h 30min\"\n * formatDuration(1440) // => \"1 day\"\n * formatDuration(4320) // => \"3 days\"\n */\nexport function formatDuration(minutes: number): string {\n if (minutes < 1) return 'instant';\n if (minutes < 60) return `${minutes} min`;\n\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n\n if (hours < 24) {\n if (remainingMinutes === 0) {\n return `${hours}h`;\n }\n return `${hours}h ${remainingMinutes}min`;\n }\n\n const days = Math.floor(hours / 24);\n const remainingHours = hours % 24;\n\n if (remainingHours === 0) {\n return `${days} day${days !== 1 ? 's' : ''}`;\n }\n return `${days} day${days !== 1 ? 's' : ''} ${remainingHours}h`;\n}\n"],"mappings":";AAiBA,SAAgB,EACd,GACA,GACQ;AACR,QAAO,IAAI,KAAK,aAAa,SAAS;EACpC,OAAO;EACP,UAAU;EACV,uBAAuB;EACvB,uBAAuB;EACvB,GAAG;EACJ,CAAC,CAAC,OAAO,EAAO;;AAcnB,SAAgB,EACd,GACA,GACQ;CACR,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,EAAK,GAAG;AACtD,QAAO,IAAI,KAAK,eAAe,SAAS;EACtC,KAAK;EACL,OAAO;EACP,MAAM;EACN,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,GAAG;EACJ,CAAC,CAAC,OAAO,EAAE;;AAad,SAAgB,EAAmB,GAA6B;CAC9D,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,EAAK,GAAG,GAEhD,qBADM,IAAI,MAAM,EACH,SAAS,GAAG,EAAE,SAAS,EACpC,IAAc,KAAK,MAAM,IAAS,IAAK,EACvC,IAAc,KAAK,MAAM,IAAc,GAAG,EAC1C,IAAY,KAAK,MAAM,IAAc,GAAG,EACxC,IAAW,KAAK,MAAM,IAAY,GAAG,EACrC,IAAY,KAAK,MAAM,IAAW,EAAE,EACpC,IAAa,KAAK,MAAM,IAAW,GAAG;AAE5C,KAAI,IAAc,GAAI,QAAO;AAC7B,KAAI,IAAc,GAAI,QAAO,GAAG,EAAY,MAAM,MAAgB,IAAU,KAAN,IAAS;AAC/E,KAAI,IAAY,GAAI,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;AAC1E,KAAI,IAAW,EAAG,QAAO,GAAG,EAAS,MAAM,MAAa,IAAU,KAAN,IAAS;AACrE,KAAI,IAAY,EAAG,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;AACzE,KAAI,IAAa,GAAI,QAAO,GAAG,EAAW,QAAQ,MAAe,IAAU,KAAN,IAAS;CAE9E,IAAM,IAAY,KAAK,MAAM,IAAW,IAAI;AAC5C,QAAO,GAAG,EAAU,OAAO,MAAc,IAAU,KAAN,IAAS;;AAcxD,SAAgB,EAAa,GAAe,GAAqD;AAC/F,QAAO,IAAI,KAAK,aAAa,SAAS,EAAQ,CAAC,OAAO,EAAM"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AdapterCloudProvider as e, useAdapterCloud as t } from "./adaptercloud/context/AdapterCloudContext.js";
|
|
2
2
|
import { cn as n } from "./adaptercloud/utils/cn.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { formatMoney as r, humanizeEnum as i } from "./adaptercloud/utils/domain.js";
|
|
4
|
+
import { formatCurrency as a, formatDate as o, formatNumber as s, formatRelativeTime as c } from "./adaptercloud/utils/formatters.js";
|
|
5
|
+
import { AdapterCloudRoot as l } from "./adaptercloud/AdapterCloudRoot.js";
|
|
6
|
+
import { useAdapterCloudStore as u } from "./adaptercloud/store/adaptercloudStore.js";
|
|
6
7
|
import "./adaptercloud/index.js";
|
|
7
|
-
export { e as AdapterCloudProvider,
|
|
8
|
+
export { e as AdapterCloudProvider, l as AdapterCloudRoot, n as cn, a as formatCurrency, o as formatDate, r as formatMoney, s as formatNumber, c as formatRelativeTime, i as humanizeEnum, t as useAdapterCloud, u as useAdapterCloudStore };
|