@burdenoff/microfe-assethandler 2026.826.15 → 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.
- package/dist/assethandler/pages/AiPredictionsPage.d.ts +9 -3
- package/dist/assethandler/pages/AiPredictionsPage.d.ts.map +1 -1
- package/dist/assethandler/pages/AiPredictionsPage.js +120 -353
- package/dist/assethandler/pages/AiPredictionsPage.js.map +1 -1
- package/dist/assethandler/pages/DiscoveryJobsPage.d.ts.map +1 -1
- package/dist/assethandler/pages/DiscoveryJobsPage.js +103 -104
- package/dist/assethandler/pages/DiscoveryJobsPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceFinanceHubPage.d.ts +1 -0
- package/dist/assethandler/pages/FinanceFinanceHubPage.d.ts.map +1 -1
- package/dist/assethandler/pages/FinanceFinanceHubPage.js +1 -1
- package/dist/assethandler/pages/FinanceFinanceHubPage.js.map +1 -1
- package/dist/assethandler/pages/KnowledgeBasePage.d.ts.map +1 -1
- package/dist/assethandler/pages/KnowledgeBasePage.js +189 -170
- package/dist/assethandler/pages/KnowledgeBasePage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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":"
|
|
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 {
|
|
2
|
-
import {
|
|
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 {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
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
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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__ */
|
|
20
|
+
/* @__PURE__ */ s(t, {
|
|
186
21
|
hero: !0,
|
|
187
|
-
icon:
|
|
188
|
-
title: "
|
|
189
|
-
description: "
|
|
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__ */
|
|
197
|
-
/* @__PURE__ */
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
203
|
-
className: "grid gap-4
|
|
204
|
-
children: [/* @__PURE__ */
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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__ */
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
children:
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
|
|
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 {
|
|
137
|
+
export { p as AiPredictionsPage };
|
|
371
138
|
|
|
372
139
|
//# sourceMappingURL=AiPredictionsPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiPredictionsPage.js","names":[],"sources":["../../../src/assethandler/pages/AiPredictionsPage.tsx"],"sourcesContent":["import type React from 'react';\nimport { BrainCircuit, Plus, Wrench, Loader2, BarChart3 } from 'lucide-react';\nimport {\n Button,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport {\n Pagination,\n usePagination,\n SectionHeader,\n ChartCard,\n DonutChart,\n BarsChart,\n RadialGauge,\n seriesColor,\n type DonutSlice,\n} from '../components';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport { cn } from '../utils/cn';\nimport { notify } from '../utils/toast';\n\nconst AI_PREDICTIONS_QUERY = gql`\n query AssetHandlerAiPredictions {\n aiPredictions {\n id\n assetId\n predictionType\n score\n confidence\n recommendation\n features\n status\n generatedAt\n modelVersion\n }\n }\n`;\n\nconst REQUEST_AI_PREDICTION_MUTATION = gql`\n mutation AssetHandlerRequestAiPrediction($input: RequestAIPredictionInput!) {\n requestAIPrediction(input: $input) {\n id\n }\n }\n`;\n\ninterface AiPrediction {\n id: string;\n assetId: string;\n predictionType: string;\n score: number;\n confidence: number;\n recommendation: string;\n features: Record<string, unknown> | null;\n status: string;\n generatedAt: string;\n modelVersion: string;\n}\n\nconst PREDICTION_TYPES = [\n { value: 'maintenance-risk', label: 'Maintenance risk' },\n { value: 'failure-forecast', label: 'Failure forecast' },\n { value: 'utilization-forecast', label: 'Utilization forecast' },\n { value: 'anomaly-detection', label: 'Anomaly detection' },\n { value: 'end-of-life', label: 'End-of-life projection' },\n] as const;\n\nconst humanizePredictionType = (value: string): string =>\n PREDICTION_TYPES.find((t) => t.value === value)?.label ?? value.replace(/-/g, ' ');\n\ntype RiskBand = 'high' | 'medium' | 'low';\n\nfunction riskBandOf(score: number): {\n band: RiskBand;\n label: string;\n tone: 'danger' | 'warning' | 'success';\n} {\n if (score >= 0.66) return { band: 'high', label: 'High', tone: 'danger' };\n if (score >= 0.33) return { band: 'medium', label: 'Medium', tone: 'warning' };\n return { band: 'low', label: 'Low', tone: 'success' };\n}\n\n/** Extract numeric feature importances from the backend `features` JSONObject. */\nfunction featureBars(\n features: Record<string, unknown> | null | undefined\n): { name: string; importance: number }[] {\n if (!features) return [];\n return Object.entries(features)\n .map(([name, value]) => ({\n name,\n importance: typeof value === 'number' ? value : Number(value),\n }))\n .filter((f) => Number.isFinite(f.importance))\n .sort((a, b) => b.importance - a.importance)\n .slice(0, 8);\n}\n\nfunction RunPredictionDialog({\n open,\n onOpenChange,\n onRun,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onRun: () => void;\n}) {\n const assets = useAssetHandlerStore((s) => s.assets);\n const [assetId, setAssetId] = useState('');\n const [predictionType, setPredictionType] =\n useState<(typeof PREDICTION_TYPES)[number]['value']>('maintenance-risk');\n\n const [requestPrediction, { loading: requesting }] = useMutation(REQUEST_AI_PREDICTION_MUTATION, {\n onCompleted: () => {\n notify.success('Prediction requested', 'The model result will appear shortly.');\n onOpenChange(false);\n onRun();\n },\n onError: (error) => notify.error('Could not run prediction', error.message),\n });\n\n const handleRun = (event: React.FormEvent) => {\n event.preventDefault();\n if (!assetId) {\n notify.warning('Asset required', 'Select an asset to run a prediction against.');\n return;\n }\n void requestPrediction({ variables: { input: { assetId, predictionType } } });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Run Prediction</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Pick an asset and a model to forecast failure risk and get a recommended action.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <form className=\"space-y-4\" onSubmit={handleRun}>\n <div className=\"space-y-2\">\n <Label>Asset</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.assetTag} — {asset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Prediction Type</Label>\n <Select\n value={predictionType}\n onValueChange={(v) => setPredictionType(v as typeof predictionType)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {PREDICTION_TYPES.map((t) => (\n <SelectItem key={t.value} value={t.value}>\n {t.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <ResponsiveDialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => onOpenChange(false)}\n disabled={requesting}\n >\n Cancel\n </Button>\n <Button type=\"submit\" disabled={requesting}>\n {requesting ? 'Running…' : 'Run Prediction'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function AiPredictionsPage() {\n const assets = useAssetHandlerStore((s) => s.assets);\n const navigate = useAssetHandlerNavigate();\n const [dialogOpen, setDialogOpen] = useState(false);\n const [typeFilter, setTypeFilter] = useState<string>('ALL');\n\n const { data, loading, refetch } = useQuery<{ aiPredictions: AiPrediction[] }>(\n AI_PREDICTIONS_QUERY,\n { fetchPolicy: 'cache-and-network' }\n );\n\n const predictions = useMemo(() => data?.aiPredictions ?? [], [data?.aiPredictions]);\n\n const assetLabelById = useMemo(() => {\n const map = new Map<string, string>();\n for (const a of assets) map.set(a.id, `${a.assetTag} — ${a.name}`);\n return map;\n }, [assets]);\n\n const labelFor = (assetId: string): string =>\n assetLabelById.get(assetId) ?? `Asset ${assetId.slice(0, 8)}`;\n\n const sorted = useMemo(() => {\n const list =\n typeFilter === 'ALL'\n ? predictions\n : predictions.filter((p) => p.predictionType === typeFilter);\n return [...list].sort((a, b) => b.score - a.score);\n }, [predictions, typeFilter]);\n\n const riskMix = useMemo<DonutSlice[]>(() => {\n const counts: Record<RiskBand, number> = { high: 0, medium: 0, low: 0 };\n for (const p of predictions) counts[riskBandOf(p.score).band] += 1;\n const order: { band: RiskBand; label: string }[] = [\n { band: 'high', label: 'High' },\n { band: 'medium', label: 'Medium' },\n { band: 'low', label: 'Low' },\n ];\n return order\n .filter((o) => counts[o.band] > 0)\n .map((o, i) => ({ name: o.label, value: counts[o.band], color: seriesColor(i) }));\n }, [predictions]);\n\n // Feature importance is shown for the highest-risk prediction that carries features.\n const featureFocus = useMemo(() => {\n const withFeatures = sorted.find((p) => featureBars(p.features).length > 0);\n return withFeatures ?? null;\n }, [sorted]);\n const focusBars = featureBars(featureFocus?.features);\n\n const pagination = usePagination(sorted, { pageSize: 6, resetKey: typeFilter });\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={BrainCircuit}\n title=\"AI Predictions\"\n description=\"Forecast failures before they happen and prioritise which assets to service next.\"\n actions={\n <Button className=\"w-full sm:w-auto\" onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n Run Prediction\n </Button>\n }\n />\n <PagePurpose>\n Pick an asset and a model to get a risk score, confidence level and a concrete\n recommendation — so you can schedule preventive maintenance instead of reacting to\n breakdowns.\n </PagePurpose>\n\n <RunPredictionDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onRun={() => void refetch()}\n />\n\n {predictions.length > 0 ? (\n <div className=\"grid gap-4 lg:grid-cols-2\">\n <ChartCard title=\"Risk distribution\" subtitle=\"Predicted failure risk across assets\">\n <DonutChart\n data={riskMix}\n height={210}\n centerLabel=\"Assets\"\n centerValue={predictions.length}\n ariaLabel=\"Risk distribution across predictions\"\n />\n </ChartCard>\n <ChartCard\n title=\"Feature importance\"\n subtitle={\n featureFocus\n ? `Top drivers · ${labelFor(featureFocus.assetId)}`\n : 'Model feature drivers'\n }\n icon={BarChart3}\n >\n {focusBars.length > 0 ? (\n <BarsChart\n data={focusBars}\n xKey=\"name\"\n series={[{ key: 'importance', label: 'Importance' }]}\n orientation=\"horizontal\"\n height={210}\n categoryWidth={140}\n ariaLabel=\"Feature importance\"\n />\n ) : (\n <div className=\"flex h-[210px] items-center justify-center px-4 text-center text-sm text-text-secondary\">\n Feature importance appears here once a model returns feature drivers.\n </div>\n )}\n </ChartCard>\n </div>\n ) : null}\n\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n Predicted failure risk per asset\n </h3>\n <div className=\"w-full sm:w-64\">\n <Select value={typeFilter} onValueChange={setTypeFilter}>\n <SelectTrigger>\n <SelectValue placeholder=\"Prediction type\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"ALL\">All prediction types</SelectItem>\n {PREDICTION_TYPES.map((t) => (\n <SelectItem key={t.value} value={t.value}>\n {t.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {loading && predictions.length === 0 ? (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"h-56 rounded-xl bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && sorted.length === 0 ? (\n <IllustratedEmptyState\n illustration={typeFilter === 'ALL' ? 'empty-data' : 'empty-search'}\n title={\n typeFilter === 'ALL' ? 'No AI predictions available yet' : 'No predictions of this type'\n }\n description={\n typeFilter === 'ALL'\n ? 'Run a prediction to generate a risk score and recommendation.'\n : 'Try a different prediction type or run a new prediction.'\n }\n />\n ) : null}\n\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {pagination.pageItems.map((prediction, index) => {\n const risk = riskBandOf(prediction.score);\n const isTop = index === 0 && pagination.page === 1 && risk.band === 'high';\n const pending = prediction.status && prediction.status.toLowerCase() !== 'completed';\n const confidencePct = Math.round(prediction.confidence * 100);\n return (\n <GlassCard\n key={prediction.id}\n treatment=\"glass\"\n glow={isTop}\n className={cn('border-border-seam', isTop && 'ring-1 ring-status-error-border')}\n >\n <div className=\"flex h-full flex-col gap-3 p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n onClick={() => navigate(`/assets/${prediction.assetId}`)}\n className=\"truncate text-left text-sm font-semibold text-text-primary hover:underline\"\n >\n {labelFor(prediction.assetId)}\n </button>\n <p className=\"text-xs text-text-secondary\">\n {humanizePredictionType(prediction.predictionType)}\n </p>\n </div>\n {pending ? (\n <span 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\">\n <Loader2 className=\"h-3 w-3 motion-safe:animate-spin\" />\n Processing\n </span>\n ) : null}\n </div>\n\n <div className=\"flex items-center gap-3\">\n <div className=\"w-[120px] shrink-0\">\n <RadialGauge\n value={prediction.score * 100}\n tone={risk.tone}\n label={risk.label}\n height={110}\n format={(v) => `${Math.round(v)}%`}\n ariaLabel={`${risk.label} risk, ${Math.round(prediction.score * 100)} percent`}\n />\n </div>\n <div className=\"min-w-0 flex-1 space-y-1\">\n <p className=\"text-xs text-text-secondary\">Confidence</p>\n <div className=\"flex items-center gap-2\">\n <div className=\"h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-full rounded-full bg-action-primary-bg\"\n style={{ width: `${confidencePct}%` }}\n />\n </div>\n <span className=\"text-xs font-medium tabular-nums text-text-primary\">\n {confidencePct}%\n </span>\n </div>\n </div>\n </div>\n\n <p className=\"flex-1 text-sm text-text-secondary\">{prediction.recommendation}</p>\n\n <div className=\"flex items-center justify-between gap-2 border-t border-border-seam/60 pt-3\">\n <span className=\"truncate text-xs text-text-muted\">\n {prediction.modelVersion} ·{' '}\n {new Date(prediction.generatedAt).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigate('/maintenance/maintenance-scheduler')}\n >\n <Wrench className=\"mr-1.5 h-3.5 w-3.5\" />\n Schedule\n </Button>\n </div>\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n {sorted.length > 0 ? (\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"predictions\"\n />\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AiPredictionsPage.js","names":[],"sources":["../../../src/assethandler/pages/AiPredictionsPage.tsx"],"sourcesContent":["import { BrainCircuit, Clock3, Database, ShieldCheck, Wrench } from 'lucide-react';\nimport { Button, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { SectionHeader } from '../components';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\n\nconst PLANNED_PREDICTION_TYPES = [\n 'Maintenance risk',\n 'Failure forecast',\n 'Utilization forecast',\n 'Anomaly detection',\n 'End-of-life projection',\n] as const;\n\n/**\n * Honest boundary for BOFF-4254 / BOFF-6955.\n *\n * AssetHandler intentionally removed its old deterministic prediction stub. Do\n * not issue prediction GraphQL operations from this page until the owned engine\n * and schema ship together; a generic `aiPredictions` field belongs to another\n * product in the composed graph and must never be treated as AssetHandler data.\n */\nexport function AiPredictionsPage() {\n const navigate = useAssetHandlerNavigate();\n\n return (\n <div className=\"space-y-5 p-4 sm:p-6\">\n <SectionHeader\n hero\n icon={BrainCircuit}\n title=\"Predictive Maintenance\"\n description=\"A transparent home for AssetHandler's planned risk-scoring engine.\"\n />\n\n <PagePurpose>\n Predictive maintenance scoring is not available yet. AssetHandler does not generate or\n display invented risk scores, confidence values, feature importance, or recommendations\n while the owned prediction engine is in progress.\n </PagePurpose>\n\n <GlassCard treatment=\"glass\" className=\"border-status-info-border\">\n <div className=\"space-y-4 p-5 sm:p-6\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <span 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\">\n <Clock3 className=\"h-4 w-4\" aria-hidden=\"true\" />\n Engine in progress\n </span>\n <span className=\"text-sm text-text-secondary\">Tracked as BOFF-4254</span>\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n Predictive maintenance engine is not available yet\n </h2>\n <p className=\"mt-2 max-w-3xl text-sm leading-6 text-text-secondary\">\n The future engine will consume workspace-scoped operating history and return an\n attributable score, confidence, drivers, and recommendation. This page will only\n enable prediction requests after that supported AssetHandler API is deployed.\n </p>\n </div>\n <div className=\"flex flex-col gap-2 sm:flex-row\">\n <Button onClick={() => navigate('/maintenance/maintenance-scheduler')}>\n <Wrench className=\"mr-2 h-4 w-4\" aria-hidden=\"true\" />\n Open maintenance scheduler\n </Button>\n <Button variant=\"outline\" onClick={() => navigate('/reports/reports-dashboard')}>\n Review source-backed reports\n </Button>\n </div>\n </div>\n </GlassCard>\n\n <div className=\"grid gap-4 md:grid-cols-2\">\n <GlassCard treatment=\"glass\">\n <div className=\"space-y-3 p-5\">\n <div className=\"flex items-center gap-2 text-text-primary\">\n <Database className=\"h-5 w-5 text-action-primary-text\" aria-hidden=\"true\" />\n <h2 className=\"font-semibold\">Source data available today</h2>\n </div>\n <p className=\"text-sm leading-6 text-text-secondary\">\n The registry records condition, age and useful life, warranty, usage meter,\n maintenance history, work orders, and ownership cost. Use the scheduler and reports to\n act on those persisted facts today.\n </p>\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"glass\">\n <div className=\"space-y-3 p-5\">\n <div className=\"flex items-center gap-2 text-text-primary\">\n <ShieldCheck className=\"h-5 w-5 text-action-primary-text\" aria-hidden=\"true\" />\n <h2 className=\"font-semibold\">Guardrails for the planned engine</h2>\n </div>\n <p className=\"text-sm leading-6 text-text-secondary\">\n Results must be workspace-scoped, permission-checked, attributable, reload-stable, and\n backed by real AssetHandler inputs. Missing providers must fail closed instead of\n returning placeholder numbers.\n </p>\n </div>\n </GlassCard>\n </div>\n\n <GlassCard treatment=\"glass\">\n <div className=\"p-5\">\n <h2 className=\"font-semibold text-text-primary\">Planned prediction types</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n These are the proposed engine contract, not results available in the product today.\n </p>\n <ul className=\"mt-4 grid gap-2 sm:grid-cols-2 lg:grid-cols-3\">\n {PLANNED_PREDICTION_TYPES.map((type) => (\n <li\n key={type}\n className=\"rounded-lg border border-border-seam bg-bg-sunken px-3 py-2 text-sm text-text-secondary\"\n >\n {type}\n </li>\n ))}\n </ul>\n </div>\n </GlassCard>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAKA,IAAM,IAA2B;CAC/B;CACA;CACA;CACA;CACA;AACF;AAUA,SAAgB,IAAoB;CAClC,IAAM,IAAW,EAAwB;CAEzC,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IACE,MAAA;IACA,MAAM;IACN,OAAM;IACN,aAAY;GACb,CAAA;GAED,kBAAC,GAAD,EAAA,UAAa,mOAIA,CAAA;GAEb,kBAAC,GAAD;IAAW,WAAU;IAAQ,WAAU;cACrC,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CACE,kBAAC,GAAD;SAAQ,WAAU;SAAU,eAAY;QAAQ,CAAA,GAAC,oBAE7C;WACN,kBAAC,QAAD;QAAM,WAAU;kBAA8B;OAA0B,CAAA,CACrE;;MACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;OAAI,WAAU;iBAA0C;MAEpD,CAAA,GACJ,kBAAC,KAAD;OAAG,WAAU;iBAAuD;MAIjE,CAAA,CACA,EAAA,CAAA;MACL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAQ,eAAe,EAAS,oCAAoC;kBAApE,CACE,kBAAC,GAAD;SAAQ,WAAU;SAAe,eAAY;QAAQ,CAAA,GAAC,4BAEhD;WACR,kBAAC,GAAD;QAAQ,SAAQ;QAAU,eAAe,EAAS,4BAA4B;kBAAG;OAEzE,CAAA,CACL;;KACF;;GACI,CAAA;GAEX,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAW,WAAU;eACnB,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAU,WAAU;QAAmC,eAAY;OAAQ,CAAA,GAC3E,kBAAC,MAAD;QAAI,WAAU;kBAAgB;OAA+B,CAAA,CAC1D;UACL,kBAAC,KAAD;OAAG,WAAU;iBAAwC;MAIlD,CAAA,CACA;;IACI,CAAA,GAEX,kBAAC,GAAD;KAAW,WAAU;eACnB,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAa,WAAU;QAAmC,eAAY;OAAQ,CAAA,GAC9E,kBAAC,MAAD;QAAI,WAAU;kBAAgB;OAAqC,CAAA,CAChE;UACL,kBAAC,KAAD;OAAG,WAAU;iBAAwC;MAIlD,CAAA,CACA;;IACI,CAAA,CACR;;GAEL,kBAAC,GAAD;IAAW,WAAU;cACnB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBAAkC;MAA4B,CAAA;MAC5E,kBAAC,KAAD;OAAG,WAAU;iBAAmC;MAE7C,CAAA;MACH,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAyB,KAAK,MAC7B,kBAAC,MAAD;QAEE,WAAU;kBAET;OACC,GAJG,CAIH,CACL;MACC,CAAA;KACD;;GACI,CAAA;EACR;;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiscoveryJobsPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/DiscoveryJobsPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"DiscoveryJobsPage.d.ts","sourceRoot":"","sources":["../../../src/assethandler/pages/DiscoveryJobsPage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA2O/B,wBAAgB,iBAAiB,sBAqQhC"}
|