@burdenoff/microfe-assethandler 2026.826.14 → 2026.826.16

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.
@@ -1 +1 @@
1
- {"version":3,"file":"useCopy.d.ts","sourceRoot":"","sources":["../../../src/assethandler/hooks/useCopy.ts"],"names":[],"mappings":"AAKA,KAAK,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,iBAAiB,KAAK,MAAM,CAAC;AAK3F;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAiChC"}
1
+ {"version":3,"file":"useCopy.d.ts","sourceRoot":"","sources":["../../../src/assethandler/hooks/useCopy.ts"],"names":[],"mappings":"AAKA,KAAK,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,iBAAiB,KAAK,MAAM,CAAC;AAM3F;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAwChC"}
@@ -2,32 +2,34 @@ import { useAssetHandler as e, useAssetTerminology as t } from "../providers/Ass
2
2
  import { useCallback as n } from "react";
3
3
  import { useI18n as r } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
4
4
  //#region src/assethandler/hooks/useCopy.ts
5
- var i = /\{\{(asset|assets|assetLower|assetsLower)\}\}/g;
6
- function a() {
7
- let { t: a } = r(), { copy: o } = e(), { asset: s, assets: c } = t();
5
+ var i = /\{\{(asset|assets|assetLower|assetsLower)\}\}/g, a = /\{\{([^{}]+)\}\}/g;
6
+ function o() {
7
+ let { t: o } = r(), { copy: s } = e(), { asset: c, assets: l } = t();
8
8
  return n((e, t, n) => {
9
- let r = o?.[e];
9
+ let r = s?.[e];
10
10
  if (r === void 0) {
11
- let i = a(e, n);
11
+ let i = o(e, n);
12
12
  r = i === e ? t : i;
13
13
  }
14
- return r.includes("{{") ? r.replace(i, (e, t) => {
14
+ if (!r.includes("{{")) return r;
15
+ let u = r.replace(i, (e, t) => {
15
16
  switch (t) {
16
- case "asset": return s;
17
- case "assets": return c;
18
- case "assetLower": return s.toLowerCase();
19
- case "assetsLower": return c.toLowerCase();
17
+ case "asset": return c;
18
+ case "assets": return l;
19
+ case "assetLower": return c.toLowerCase();
20
+ case "assetsLower": return l.toLowerCase();
20
21
  default: return e;
21
22
  }
22
- }) : r;
23
+ });
24
+ return !n || !u.includes("{{") ? u : u.replace(a, (e, t) => Object.prototype.hasOwnProperty.call(n, t) ? String(n[t]) : e);
23
25
  }, [
24
- o,
25
- a,
26
26
  s,
27
- c
27
+ o,
28
+ c,
29
+ l
28
30
  ]);
29
31
  }
30
32
  //#endregion
31
- export { a as useCopy };
33
+ export { o as useCopy };
32
34
 
33
35
  //# sourceMappingURL=useCopy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCopy.js","names":[],"sources":["../../../src/assethandler/hooks/useCopy.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nimport { useAssetHandler, useAssetTerminology } from '../providers/AssetHandlerProvider';\n\ntype TranslationParams = Record<string, string | number>;\n\n/**\n * Resolves a single piece of module copy.\n *\n * @param key i18n key, e.g. \"assethandler.dashboard.metrics.totalAssets\".\n * @param fallback The module's own English copy, used when neither the host nor\n * the platform provides a string. May contain terminology\n * tokens (see {@link useCopy}).\n */\nexport type CopyFn = (key: string, fallback: string, params?: TranslationParams) => string;\n\n/** Terminology tokens substituted into resolved copy. */\nconst TOKEN_PATTERN = /\\{\\{(asset|assets|assetLower|assetsLower)\\}\\}/g;\n\n/**\n * Copy resolver for the module, in precedence order:\n *\n * 1. the host's `copy[key]` override (the `copy` prop on `AssetHandlerRoot`),\n * 2. the platform translation for `key`, when the locale provides one,\n * 3. the module's own default fallback.\n *\n * The resolved string then has its `{{asset}}` / `{{assets}}` /\n * `{{assetLower}}` / `{{assetsLower}}` tokens substituted with the terminology\n * from the `terminology` prop.\n *\n * With no `copy` and no `terminology` props the tokens resolve to\n * \"Asset\"/\"Assets\"/\"asset\"/\"assets\", so output is identical to the module's\n * previous `tWithFallback(t, key, fallback)` behaviour.\n */\nexport function useCopy(): CopyFn {\n const { t } = useI18n();\n const { copy } = useAssetHandler();\n const { asset, assets } = useAssetTerminology();\n\n return useCallback(\n (key: string, fallback: string, params?: TranslationParams): string => {\n // 1. host override, 2. platform translation, 3. module fallback.\n let resolved = copy?.[key];\n if (resolved === undefined) {\n const translated = t(key, params);\n resolved = translated === key ? fallback : translated;\n }\n\n if (!resolved.includes('{{')) return resolved;\n\n return resolved.replace(TOKEN_PATTERN, (_match, token: string) => {\n switch (token) {\n case 'asset':\n return asset;\n case 'assets':\n return assets;\n case 'assetLower':\n return asset.toLowerCase();\n case 'assetsLower':\n return assets.toLowerCase();\n default:\n return _match;\n }\n });\n },\n [copy, t, asset, assets]\n );\n}\n"],"mappings":";;;;AAkBA,IAAM,IAAgB;AAiBtB,SAAgB,IAAkB;CAChC,IAAM,EAAE,SAAM,EAAQ,GAChB,EAAE,YAAS,EAAgB,GAC3B,EAAE,UAAO,cAAW,EAAoB;CAE9C,OAAO,GACJ,GAAa,GAAkB,MAAuC;EAErE,IAAI,IAAW,IAAO;EACtB,IAAI,MAAa,KAAA,GAAW;GAC1B,IAAM,IAAa,EAAE,GAAK,CAAM;GAChC,IAAW,MAAe,IAAM,IAAW;EAC7C;EAIA,OAFK,EAAS,SAAS,IAAI,IAEpB,EAAS,QAAQ,IAAgB,GAAQ,MAAkB;GAChE,QAAQ,GAAR;IACE,KAAK,SACH,OAAO;IACT,KAAK,UACH,OAAO;IACT,KAAK,cACH,OAAO,EAAM,YAAY;IAC3B,KAAK,eACH,OAAO,EAAO,YAAY;IAC5B,SACE,OAAO;GACX;EACF,CAAC,IAfoC;CAgBvC,GACA;EAAC;EAAM;EAAG;EAAO;CAAM,CACzB;AACF"}
1
+ {"version":3,"file":"useCopy.js","names":[],"sources":["../../../src/assethandler/hooks/useCopy.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\nimport { useAssetHandler, useAssetTerminology } from '../providers/AssetHandlerProvider';\n\ntype TranslationParams = Record<string, string | number>;\n\n/**\n * Resolves a single piece of module copy.\n *\n * @param key i18n key, e.g. \"assethandler.dashboard.metrics.totalAssets\".\n * @param fallback The module's own English copy, used when neither the host nor\n * the platform provides a string. May contain terminology\n * tokens (see {@link useCopy}).\n */\nexport type CopyFn = (key: string, fallback: string, params?: TranslationParams) => string;\n\n/** Terminology tokens substituted into resolved copy. */\nconst TOKEN_PATTERN = /\\{\\{(asset|assets|assetLower|assetsLower)\\}\\}/g;\nconst PARAM_PATTERN = /\\{\\{([^{}]+)\\}\\}/g;\n\n/**\n * Copy resolver for the module, in precedence order:\n *\n * 1. the host's `copy[key]` override (the `copy` prop on `AssetHandlerRoot`),\n * 2. the platform translation for `key`, when the locale provides one,\n * 3. the module's own default fallback.\n *\n * The resolved string then has its `{{asset}}` / `{{assets}}` /\n * `{{assetLower}}` / `{{assetsLower}}` tokens substituted with the terminology\n * from the `terminology` prop.\n *\n * With no `copy` and no `terminology` props the tokens resolve to\n * \"Asset\"/\"Assets\"/\"asset\"/\"assets\", so output is identical to the module's\n * previous `tWithFallback(t, key, fallback)` behaviour.\n */\nexport function useCopy(): CopyFn {\n const { t } = useI18n();\n const { copy } = useAssetHandler();\n const { asset, assets } = useAssetTerminology();\n\n return useCallback(\n (key: string, fallback: string, params?: TranslationParams): string => {\n // 1. host override, 2. platform translation, 3. module fallback.\n let resolved = copy?.[key];\n if (resolved === undefined) {\n const translated = t(key, params);\n resolved = translated === key ? fallback : translated;\n }\n\n if (!resolved.includes('{{')) return resolved;\n\n const withTerminology = resolved.replace(TOKEN_PATTERN, (_match, token: string) => {\n switch (token) {\n case 'asset':\n return asset;\n case 'assets':\n return assets;\n case 'assetLower':\n return asset.toLowerCase();\n case 'assetsLower':\n return assets.toLowerCase();\n default:\n return _match;\n }\n });\n\n if (!params || !withTerminology.includes('{{')) return withTerminology;\n\n return withTerminology.replace(PARAM_PATTERN, (match, token: string) => {\n if (!Object.prototype.hasOwnProperty.call(params, token)) return match;\n return String(params[token]);\n });\n },\n [copy, t, asset, assets]\n );\n}\n"],"mappings":";;;;AAkBA,IAAM,IAAgB,kDAChB,IAAgB;AAiBtB,SAAgB,IAAkB;CAChC,IAAM,EAAE,SAAM,EAAQ,GAChB,EAAE,YAAS,EAAgB,GAC3B,EAAE,UAAO,cAAW,EAAoB;CAE9C,OAAO,GACJ,GAAa,GAAkB,MAAuC;EAErE,IAAI,IAAW,IAAO;EACtB,IAAI,MAAa,KAAA,GAAW;GAC1B,IAAM,IAAa,EAAE,GAAK,CAAM;GAChC,IAAW,MAAe,IAAM,IAAW;EAC7C;EAEA,IAAI,CAAC,EAAS,SAAS,IAAI,GAAG,OAAO;EAErC,IAAM,IAAkB,EAAS,QAAQ,IAAgB,GAAQ,MAAkB;GACjF,QAAQ,GAAR;IACE,KAAK,SACH,OAAO;IACT,KAAK,UACH,OAAO;IACT,KAAK,cACH,OAAO,EAAM,YAAY;IAC3B,KAAK,eACH,OAAO,EAAO,YAAY;IAC5B,SACE,OAAO;GACX;EACF,CAAC;EAID,OAFI,CAAC,KAAU,CAAC,EAAgB,SAAS,IAAI,IAAU,IAEhD,EAAgB,QAAQ,IAAgB,GAAO,MAC/C,OAAO,UAAU,eAAe,KAAK,GAAQ,CAAK,IAChD,OAAO,EAAO,EAAM,IADsC,CAElE;CACH,GACA;EAAC;EAAM;EAAG;EAAO;CAAM,CACzB;AACF"}
@@ -1,4 +1,10 @@
1
- import { default as React } from 'react';
2
-
3
- export declare function AiPredictionsPage(): React.JSX.Element;
1
+ /**
2
+ * Honest boundary for BOFF-4254 / BOFF-6955.
3
+ *
4
+ * AssetHandler intentionally removed its old deterministic prediction stub. Do
5
+ * not issue prediction GraphQL operations from this page until the owned engine
6
+ * and schema ship together; a generic `aiPredictions` field belongs to another
7
+ * product in the composed graph and must never be treated as AssetHandler data.
8
+ */
9
+ export declare function AiPredictionsPage(): import("react").JSX.Element;
4
10
  //# sourceMappingURL=AiPredictionsPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AiPredictionsPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/AiPredictionsPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAiN/B,wBAAgB,iBAAiB,sBAsQhC"}
1
+ {"version":3,"file":"AiPredictionsPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/AiPredictionsPage.tsx"],"names":[],"mappings":"AAaA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,gCAmGhC"}
@@ -1,372 +1,139 @@
1
- import { useAssetHandlerStore as e } from "../store/assethandlerStore.js";
2
- import { seriesColor as t } from "../components/charts/chartTheme.js";
3
- import { useAssetHandlerNavigate as n } from "../hooks/useAssetHandlerNavigate.js";
4
- import { cn as r } from "../utils/cn.js";
5
- import { notify as i } from "../utils/toast.js";
6
- import { BarsChart as a } from "../components/charts/BarsChart.js";
7
- import { DonutChart as o } from "../components/charts/DonutChart.js";
8
- import { RadialGauge as s } from "../components/charts/RadialGauge.js";
9
- import { Pagination as c, usePagination as l } from "../components/Pagination.js";
10
- import { ChartCard as u } from "../components/ChartCard.js";
11
- import { SectionHeader as d } from "../components/SectionHeader.js";
1
+ import { useAssetHandlerNavigate as e } from "../hooks/useAssetHandlerNavigate.js";
2
+ import { SectionHeader as t } from "../components/SectionHeader.js";
12
3
  import "../components/index.js";
13
- import { useMemo as f, useState as p } from "react";
14
- import { BarChart3 as m, BrainCircuit as h, Loader2 as g, Plus as _, Wrench as v } from "lucide-react";
15
- import { gql as y } from "@apollo/client";
16
- import { useMutation as b, useQuery as x } from "@apollo/client/react";
17
- import { jsx as S, jsxs as C } from "react/jsx-runtime";
18
- import { Button as w, GlassCard as T, IllustratedEmptyState as E, Label as D, PagePurpose as O, ResponsiveDialog as k, ResponsiveDialogContent as A, ResponsiveDialogDescription as j, ResponsiveDialogFooter as M, ResponsiveDialogHeader as N, ResponsiveDialogTitle as P, Select as F, SelectContent as I, SelectItem as L, SelectTrigger as R, SelectValue as z } from "@burdenoff/fe-libs/ui";
4
+ import { BrainCircuit as n, Clock3 as r, Database as i, ShieldCheck as a, Wrench as o } from "lucide-react";
5
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
6
+ import { Button as l, GlassCard as u, PagePurpose as d } from "@burdenoff/fe-libs/ui";
19
7
  //#region src/assethandler/pages/AiPredictionsPage.tsx
20
- var B = y`
21
- query AssetHandlerAiPredictions {
22
- aiPredictions {
23
- id
24
- assetId
25
- predictionType
26
- score
27
- confidence
28
- recommendation
29
- features
30
- status
31
- generatedAt
32
- modelVersion
33
- }
34
- }
35
- `, V = y`
36
- mutation AssetHandlerRequestAiPrediction($input: RequestAIPredictionInput!) {
37
- requestAIPrediction(input: $input) {
38
- id
39
- }
40
- }
41
- `, H = [
42
- {
43
- value: "maintenance-risk",
44
- label: "Maintenance risk"
45
- },
46
- {
47
- value: "failure-forecast",
48
- label: "Failure forecast"
49
- },
50
- {
51
- value: "utilization-forecast",
52
- label: "Utilization forecast"
53
- },
54
- {
55
- value: "anomaly-detection",
56
- label: "Anomaly detection"
57
- },
58
- {
59
- value: "end-of-life",
60
- label: "End-of-life projection"
61
- }
62
- ], U = (e) => H.find((t) => t.value === e)?.label ?? e.replace(/-/g, " ");
63
- function W(e) {
64
- return e >= .66 ? {
65
- band: "high",
66
- label: "High",
67
- tone: "danger"
68
- } : e >= .33 ? {
69
- band: "medium",
70
- label: "Medium",
71
- tone: "warning"
72
- } : {
73
- band: "low",
74
- label: "Low",
75
- tone: "success"
76
- };
77
- }
78
- function G(e) {
79
- return e ? Object.entries(e).map(([e, t]) => ({
80
- name: e,
81
- importance: typeof t == "number" ? t : Number(t)
82
- })).filter((e) => Number.isFinite(e.importance)).sort((e, t) => t.importance - e.importance).slice(0, 8) : [];
83
- }
84
- function K({ open: t, onOpenChange: n, onRun: r }) {
85
- let a = e((e) => e.assets), [o, s] = p(""), [c, l] = p("maintenance-risk"), [u, { loading: d }] = b(V, {
86
- onCompleted: () => {
87
- i.success("Prediction requested", "The model result will appear shortly."), n(!1), r();
88
- },
89
- onError: (e) => i.error("Could not run prediction", e.message)
90
- });
91
- return /* @__PURE__ */ S(k, {
92
- open: t,
93
- onOpenChange: n,
94
- children: /* @__PURE__ */ C(A, { children: [/* @__PURE__ */ C(N, { children: [/* @__PURE__ */ S(P, { children: "Run Prediction" }), /* @__PURE__ */ S(j, { children: "Pick an asset and a model to forecast failure risk and get a recommended action." })] }), /* @__PURE__ */ C("form", {
95
- className: "space-y-4",
96
- onSubmit: (e) => {
97
- if (e.preventDefault(), !o) {
98
- i.warning("Asset required", "Select an asset to run a prediction against.");
99
- return;
100
- }
101
- u({ variables: { input: {
102
- assetId: o,
103
- predictionType: c
104
- } } });
105
- },
106
- children: [
107
- /* @__PURE__ */ C("div", {
108
- className: "space-y-2",
109
- children: [/* @__PURE__ */ S(D, { children: "Asset" }), /* @__PURE__ */ C(F, {
110
- value: o,
111
- onValueChange: s,
112
- children: [/* @__PURE__ */ S(R, { children: /* @__PURE__ */ S(z, { placeholder: "Select an asset" }) }), /* @__PURE__ */ S(I, { children: a.map((e) => /* @__PURE__ */ C(L, {
113
- value: e.id,
114
- children: [
115
- e.assetTag,
116
- " — ",
117
- e.name
118
- ]
119
- }, e.id)) })]
120
- })]
121
- }),
122
- /* @__PURE__ */ C("div", {
123
- className: "space-y-2",
124
- children: [/* @__PURE__ */ S(D, { children: "Prediction Type" }), /* @__PURE__ */ C(F, {
125
- value: c,
126
- onValueChange: (e) => l(e),
127
- children: [/* @__PURE__ */ S(R, { children: /* @__PURE__ */ S(z, {}) }), /* @__PURE__ */ S(I, { children: H.map((e) => /* @__PURE__ */ S(L, {
128
- value: e.value,
129
- children: e.label
130
- }, e.value)) })]
131
- })]
132
- }),
133
- /* @__PURE__ */ C(M, { children: [/* @__PURE__ */ S(w, {
134
- type: "button",
135
- variant: "outline",
136
- onClick: () => n(!1),
137
- disabled: d,
138
- children: "Cancel"
139
- }), /* @__PURE__ */ S(w, {
140
- type: "submit",
141
- disabled: d,
142
- children: d ? "Running…" : "Run Prediction"
143
- })] })
144
- ]
145
- })] })
146
- });
147
- }
148
- function q() {
149
- let i = e((e) => e.assets), y = n(), [b, D] = p(!1), [k, A] = p("ALL"), { data: j, loading: M, refetch: N } = x(B, { fetchPolicy: "cache-and-network" }), P = f(() => j?.aiPredictions ?? [], [j?.aiPredictions]), V = f(() => {
150
- let e = /* @__PURE__ */ new Map();
151
- for (let t of i) e.set(t.id, `${t.assetTag} — ${t.name}`);
152
- return e;
153
- }, [i]), q = (e) => V.get(e) ?? `Asset ${e.slice(0, 8)}`, J = f(() => [...k === "ALL" ? P : P.filter((e) => e.predictionType === k)].sort((e, t) => t.score - e.score), [P, k]), Y = f(() => {
154
- let e = {
155
- high: 0,
156
- medium: 0,
157
- low: 0
158
- };
159
- for (let t of P) e[W(t.score).band] += 1;
160
- return [
161
- {
162
- band: "high",
163
- label: "High"
164
- },
165
- {
166
- band: "medium",
167
- label: "Medium"
168
- },
169
- {
170
- band: "low",
171
- label: "Low"
172
- }
173
- ].filter((t) => e[t.band] > 0).map((n, r) => ({
174
- name: n.label,
175
- value: e[n.band],
176
- color: t(r)
177
- }));
178
- }, [P]), X = f(() => J.find((e) => G(e.features).length > 0) ?? null, [J]), Z = G(X?.features), Q = l(J, {
179
- pageSize: 6,
180
- resetKey: k
181
- });
182
- return /* @__PURE__ */ C("div", {
8
+ var f = [
9
+ "Maintenance risk",
10
+ "Failure forecast",
11
+ "Utilization forecast",
12
+ "Anomaly detection",
13
+ "End-of-life projection"
14
+ ];
15
+ function p() {
16
+ let p = e();
17
+ return /* @__PURE__ */ c("div", {
183
18
  className: "space-y-5 p-4 sm:p-6",
184
19
  children: [
185
- /* @__PURE__ */ S(d, {
20
+ /* @__PURE__ */ s(t, {
186
21
  hero: !0,
187
- icon: h,
188
- title: "AI Predictions",
189
- description: "Forecast failures before they happen and prioritise which assets to service next.",
190
- actions: /* @__PURE__ */ C(w, {
191
- className: "w-full sm:w-auto",
192
- onClick: () => D(!0),
193
- children: [/* @__PURE__ */ S(_, { className: "mr-2 h-4 w-4" }), "Run Prediction"]
194
- })
22
+ icon: n,
23
+ title: "Predictive Maintenance",
24
+ description: "A transparent home for AssetHandler's planned risk-scoring engine."
195
25
  }),
196
- /* @__PURE__ */ S(O, { children: "Pick an asset and a model to get a risk score, confidence level and a concrete recommendation — so you can schedule preventive maintenance instead of reacting to breakdowns." }),
197
- /* @__PURE__ */ S(K, {
198
- open: b,
199
- onOpenChange: D,
200
- onRun: () => void N()
26
+ /* @__PURE__ */ s(d, { children: "Predictive maintenance scoring is not available yet. AssetHandler does not generate or display invented risk scores, confidence values, feature importance, or recommendations while the owned prediction engine is in progress." }),
27
+ /* @__PURE__ */ s(u, {
28
+ treatment: "glass",
29
+ className: "border-status-info-border",
30
+ children: /* @__PURE__ */ c("div", {
31
+ className: "space-y-4 p-5 sm:p-6",
32
+ children: [
33
+ /* @__PURE__ */ c("div", {
34
+ className: "flex flex-wrap items-center gap-3",
35
+ children: [/* @__PURE__ */ c("span", {
36
+ className: "inline-flex items-center gap-2 rounded-full bg-status-info-bg-subtle px-3 py-1 text-sm font-medium text-status-info-text",
37
+ children: [/* @__PURE__ */ s(r, {
38
+ className: "h-4 w-4",
39
+ "aria-hidden": "true"
40
+ }), "Engine in progress"]
41
+ }), /* @__PURE__ */ s("span", {
42
+ className: "text-sm text-text-secondary",
43
+ children: "Tracked as BOFF-4254"
44
+ })]
45
+ }),
46
+ /* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("h2", {
47
+ className: "text-lg font-semibold text-text-primary",
48
+ children: "Predictive maintenance engine is not available yet"
49
+ }), /* @__PURE__ */ s("p", {
50
+ className: "mt-2 max-w-3xl text-sm leading-6 text-text-secondary",
51
+ children: "The future engine will consume workspace-scoped operating history and return an attributable score, confidence, drivers, and recommendation. This page will only enable prediction requests after that supported AssetHandler API is deployed."
52
+ })] }),
53
+ /* @__PURE__ */ c("div", {
54
+ className: "flex flex-col gap-2 sm:flex-row",
55
+ children: [/* @__PURE__ */ c(l, {
56
+ onClick: () => p("/maintenance/maintenance-scheduler"),
57
+ children: [/* @__PURE__ */ s(o, {
58
+ className: "mr-2 h-4 w-4",
59
+ "aria-hidden": "true"
60
+ }), "Open maintenance scheduler"]
61
+ }), /* @__PURE__ */ s(l, {
62
+ variant: "outline",
63
+ onClick: () => p("/reports/reports-dashboard"),
64
+ children: "Review source-backed reports"
65
+ })]
66
+ })
67
+ ]
68
+ })
201
69
  }),
202
- P.length > 0 ? /* @__PURE__ */ C("div", {
203
- className: "grid gap-4 lg:grid-cols-2",
204
- children: [/* @__PURE__ */ S(u, {
205
- title: "Risk distribution",
206
- subtitle: "Predicted failure risk across assets",
207
- children: /* @__PURE__ */ S(o, {
208
- data: Y,
209
- height: 210,
210
- centerLabel: "Assets",
211
- centerValue: P.length,
212
- ariaLabel: "Risk distribution across predictions"
70
+ /* @__PURE__ */ c("div", {
71
+ className: "grid gap-4 md:grid-cols-2",
72
+ children: [/* @__PURE__ */ s(u, {
73
+ treatment: "glass",
74
+ children: /* @__PURE__ */ c("div", {
75
+ className: "space-y-3 p-5",
76
+ children: [/* @__PURE__ */ c("div", {
77
+ className: "flex items-center gap-2 text-text-primary",
78
+ children: [/* @__PURE__ */ s(i, {
79
+ className: "h-5 w-5 text-action-primary-text",
80
+ "aria-hidden": "true"
81
+ }), /* @__PURE__ */ s("h2", {
82
+ className: "font-semibold",
83
+ children: "Source data available today"
84
+ })]
85
+ }), /* @__PURE__ */ s("p", {
86
+ className: "text-sm leading-6 text-text-secondary",
87
+ children: "The registry records condition, age and useful life, warranty, usage meter, maintenance history, work orders, and ownership cost. Use the scheduler and reports to act on those persisted facts today."
88
+ })]
213
89
  })
214
- }), /* @__PURE__ */ S(u, {
215
- title: "Feature importance",
216
- subtitle: X ? `Top drivers · ${q(X.assetId)}` : "Model feature drivers",
217
- icon: m,
218
- children: Z.length > 0 ? /* @__PURE__ */ S(a, {
219
- data: Z,
220
- xKey: "name",
221
- series: [{
222
- key: "importance",
223
- label: "Importance"
224
- }],
225
- orientation: "horizontal",
226
- height: 210,
227
- categoryWidth: 140,
228
- ariaLabel: "Feature importance"
229
- }) : /* @__PURE__ */ S("div", {
230
- className: "flex h-[210px] items-center justify-center px-4 text-center text-sm text-text-secondary",
231
- children: "Feature importance appears here once a model returns feature drivers."
232
- })
233
- })]
234
- }) : null,
235
- /* @__PURE__ */ C("div", {
236
- className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
237
- children: [/* @__PURE__ */ S("h3", {
238
- className: "text-base font-semibold text-text-primary",
239
- children: "Predicted failure risk per asset"
240
- }), /* @__PURE__ */ S("div", {
241
- className: "w-full sm:w-64",
242
- children: /* @__PURE__ */ C(F, {
243
- value: k,
244
- onValueChange: A,
245
- children: [/* @__PURE__ */ S(R, { children: /* @__PURE__ */ S(z, { placeholder: "Prediction type" }) }), /* @__PURE__ */ C(I, { children: [/* @__PURE__ */ S(L, {
246
- value: "ALL",
247
- children: "All prediction types"
248
- }), H.map((e) => /* @__PURE__ */ S(L, {
249
- value: e.value,
250
- children: e.label
251
- }, e.value))] })]
90
+ }), /* @__PURE__ */ s(u, {
91
+ treatment: "glass",
92
+ children: /* @__PURE__ */ c("div", {
93
+ className: "space-y-3 p-5",
94
+ children: [/* @__PURE__ */ c("div", {
95
+ className: "flex items-center gap-2 text-text-primary",
96
+ children: [/* @__PURE__ */ s(a, {
97
+ className: "h-5 w-5 text-action-primary-text",
98
+ "aria-hidden": "true"
99
+ }), /* @__PURE__ */ s("h2", {
100
+ className: "font-semibold",
101
+ children: "Guardrails for the planned engine"
102
+ })]
103
+ }), /* @__PURE__ */ s("p", {
104
+ className: "text-sm leading-6 text-text-secondary",
105
+ children: "Results must be workspace-scoped, permission-checked, attributable, reload-stable, and backed by real AssetHandler inputs. Missing providers must fail closed instead of returning placeholder numbers."
106
+ })]
252
107
  })
253
108
  })]
254
109
  }),
255
- M && P.length === 0 ? /* @__PURE__ */ S("div", {
256
- className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
257
- children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */ S("div", { className: "h-56 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer" }, t))
258
- }) : null,
259
- !M && J.length === 0 ? /* @__PURE__ */ S(E, {
260
- illustration: k === "ALL" ? "empty-data" : "empty-search",
261
- title: k === "ALL" ? "No AI predictions available yet" : "No predictions of this type",
262
- description: k === "ALL" ? "Run a prediction to generate a risk score and recommendation." : "Try a different prediction type or run a new prediction."
263
- }) : null,
264
- /* @__PURE__ */ S("div", {
265
- className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
266
- children: Q.pageItems.map((e, t) => {
267
- let n = W(e.score), i = t === 0 && Q.page === 1 && n.band === "high", a = e.status && e.status.toLowerCase() !== "completed", o = Math.round(e.confidence * 100);
268
- return /* @__PURE__ */ S(T, {
269
- treatment: "glass",
270
- glow: i,
271
- className: r("border-border-seam", i && "ring-1 ring-status-error-border"),
272
- children: /* @__PURE__ */ C("div", {
273
- className: "flex h-full flex-col gap-3 p-4",
274
- children: [
275
- /* @__PURE__ */ C("div", {
276
- className: "flex items-start justify-between gap-2",
277
- children: [/* @__PURE__ */ C("div", {
278
- className: "min-w-0",
279
- children: [/* @__PURE__ */ S("button", {
280
- type: "button",
281
- onClick: () => y(`/assets/${e.assetId}`),
282
- className: "truncate text-left text-sm font-semibold text-text-primary hover:underline",
283
- children: q(e.assetId)
284
- }), /* @__PURE__ */ S("p", {
285
- className: "text-xs text-text-secondary",
286
- children: U(e.predictionType)
287
- })]
288
- }), a ? /* @__PURE__ */ C("span", {
289
- className: "inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs font-medium text-status-info-text",
290
- children: [/* @__PURE__ */ S(g, { className: "h-3 w-3 motion-safe:animate-spin" }), "Processing"]
291
- }) : null]
292
- }),
293
- /* @__PURE__ */ C("div", {
294
- className: "flex items-center gap-3",
295
- children: [/* @__PURE__ */ S("div", {
296
- className: "w-[120px] shrink-0",
297
- children: /* @__PURE__ */ S(s, {
298
- value: e.score * 100,
299
- tone: n.tone,
300
- label: n.label,
301
- height: 110,
302
- format: (e) => `${Math.round(e)}%`,
303
- ariaLabel: `${n.label} risk, ${Math.round(e.score * 100)} percent`
304
- })
305
- }), /* @__PURE__ */ C("div", {
306
- className: "min-w-0 flex-1 space-y-1",
307
- children: [/* @__PURE__ */ S("p", {
308
- className: "text-xs text-text-secondary",
309
- children: "Confidence"
310
- }), /* @__PURE__ */ C("div", {
311
- className: "flex items-center gap-2",
312
- children: [/* @__PURE__ */ S("div", {
313
- className: "h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken",
314
- children: /* @__PURE__ */ S("div", {
315
- className: "h-full rounded-full bg-action-primary-bg",
316
- style: { width: `${o}%` }
317
- })
318
- }), /* @__PURE__ */ C("span", {
319
- className: "text-xs font-medium tabular-nums text-text-primary",
320
- children: [o, "%"]
321
- })]
322
- })]
323
- })]
324
- }),
325
- /* @__PURE__ */ S("p", {
326
- className: "flex-1 text-sm text-text-secondary",
327
- children: e.recommendation
328
- }),
329
- /* @__PURE__ */ C("div", {
330
- className: "flex items-center justify-between gap-2 border-t border-border-seam/60 pt-3",
331
- children: [/* @__PURE__ */ C("span", {
332
- className: "truncate text-xs text-text-muted",
333
- children: [
334
- e.modelVersion,
335
- " ·",
336
- " ",
337
- new Date(e.generatedAt).toLocaleDateString(void 0, {
338
- month: "short",
339
- day: "numeric"
340
- })
341
- ]
342
- }), /* @__PURE__ */ C(w, {
343
- variant: "outline",
344
- size: "sm",
345
- onClick: () => y("/maintenance/maintenance-scheduler"),
346
- children: [/* @__PURE__ */ S(v, { className: "mr-1.5 h-3.5 w-3.5" }), "Schedule"]
347
- })]
348
- })
349
- ]
110
+ /* @__PURE__ */ s(u, {
111
+ treatment: "glass",
112
+ children: /* @__PURE__ */ c("div", {
113
+ className: "p-5",
114
+ children: [
115
+ /* @__PURE__ */ s("h2", {
116
+ className: "font-semibold text-text-primary",
117
+ children: "Planned prediction types"
118
+ }),
119
+ /* @__PURE__ */ s("p", {
120
+ className: "mt-1 text-sm text-text-secondary",
121
+ children: "These are the proposed engine contract, not results available in the product today."
122
+ }),
123
+ /* @__PURE__ */ s("ul", {
124
+ className: "mt-4 grid gap-2 sm:grid-cols-2 lg:grid-cols-3",
125
+ children: f.map((e) => /* @__PURE__ */ s("li", {
126
+ className: "rounded-lg border border-border-seam bg-bg-sunken px-3 py-2 text-sm text-text-secondary",
127
+ children: e
128
+ }, e))
350
129
  })
351
- }, e.id);
130
+ ]
352
131
  })
353
- }),
354
- J.length > 0 ? /* @__PURE__ */ S(c, {
355
- page: Q.page,
356
- pageCount: Q.pageCount,
357
- rangeStart: Q.rangeStart,
358
- rangeEnd: Q.rangeEnd,
359
- totalItems: Q.totalItems,
360
- canPrev: Q.canPrev,
361
- canNext: Q.canNext,
362
- onPrev: Q.prevPage,
363
- onNext: Q.nextPage,
364
- itemLabel: "predictions"
365
- }) : null
132
+ })
366
133
  ]
367
134
  });
368
135
  }
369
136
  //#endregion
370
- export { q as AiPredictionsPage };
137
+ export { p as AiPredictionsPage };
371
138
 
372
139
  //# sourceMappingURL=AiPredictionsPage.js.map