@burdenoff/microfe-ecoimpacthub 2026.720.4 → 2026.720.6
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/ecoimpacthub/EcoImpactHubAdminRoot.d.ts +10 -0
- package/dist/ecoimpacthub/EcoImpactHubAdminRoot.d.ts.map +1 -0
- package/dist/ecoimpacthub/EcoImpactHubAdminRoot.js +579 -0
- package/dist/ecoimpacthub/EcoImpactHubAdminRoot.js.map +1 -0
- package/dist/ecoimpacthub/components/DashboardCustomizerDialog.d.ts +11 -0
- package/dist/ecoimpacthub/components/DashboardCustomizerDialog.d.ts.map +1 -0
- package/dist/ecoimpacthub/components/DashboardCustomizerDialog.js +182 -0
- package/dist/ecoimpacthub/components/DashboardCustomizerDialog.js.map +1 -0
- package/dist/ecoimpacthub/hooks/index.d.ts +1 -0
- package/dist/ecoimpacthub/hooks/index.d.ts.map +1 -1
- package/dist/ecoimpacthub/hooks/index.js +1 -0
- package/dist/ecoimpacthub/hooks/useDashboardLayout.d.ts +29 -0
- package/dist/ecoimpacthub/hooks/useDashboardLayout.d.ts.map +1 -0
- package/dist/ecoimpacthub/hooks/useDashboardLayout.js +95 -0
- package/dist/ecoimpacthub/hooks/useDashboardLayout.js.map +1 -0
- package/dist/ecoimpacthub/index.d.ts +1 -0
- package/dist/ecoimpacthub/index.d.ts.map +1 -1
- package/dist/ecoimpacthub/index.js +1 -0
- package/dist/ecoimpacthub/pages/DashboardPage.d.ts +7 -0
- package/dist/ecoimpacthub/pages/DashboardPage.d.ts.map +1 -1
- package/dist/ecoimpacthub/pages/DashboardPage.js +505 -447
- package/dist/ecoimpacthub/pages/DashboardPage.js.map +1 -1
- package/dist/ecoimpacthub/pages/carbon/CarbonPage.js +1 -1
- package/dist/ecoimpacthub/pages/habitat/HabitatProjectsPage.js +4 -4
- package/dist/ecoimpacthub/pages/monitoring/MonitoringPage.js +1 -1
- package/dist/ecoimpacthub/pages/reports/ReportsPage.js +4 -4
- package/dist/index.js +3 -2
- package/dist/stories/DashboardCustomizerDialog.stories.d.ts +9 -0
- package/dist/stories/DashboardCustomizerDialog.stories.d.ts.map +1 -0
- package/dist/stories/DataTable.stories.d.ts +11 -0
- package/dist/stories/DataTable.stories.d.ts.map +1 -0
- package/dist/stories/FeatureFlagGate.stories.d.ts +19 -0
- package/dist/stories/FeatureFlagGate.stories.d.ts.map +1 -0
- package/dist/stories/FilterTabs.stories.d.ts +9 -0
- package/dist/stories/FilterTabs.stories.d.ts.map +1 -0
- package/dist/stories/PageLayout.stories.d.ts +10 -0
- package/dist/stories/PageLayout.stories.d.ts.map +1 -0
- package/dist/stories/Pagination.stories.d.ts +11 -0
- package/dist/stories/Pagination.stories.d.ts.map +1 -0
- package/dist/stories/StateViews.stories.d.ts +10 -0
- package/dist/stories/StateViews.stories.d.ts.map +1 -0
- package/dist/stories/Tabs.stories.d.ts +9 -0
- package/dist/stories/Tabs.stories.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { EcoImpactHubRootProps } from './types';
|
|
3
|
+
|
|
4
|
+
export interface EcoImpactHubAdminRootProps extends EcoImpactHubRootProps {
|
|
5
|
+
/** Workspace token is supplied by admin-app for workspace-scoped MFEs. */
|
|
6
|
+
workspaceToken?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const EcoImpactHubAdminRoot: FC<EcoImpactHubAdminRootProps>;
|
|
9
|
+
export { EcoImpactHubAdminRoot as AdminRoot };
|
|
10
|
+
//# sourceMappingURL=EcoImpactHubAdminRoot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EcoImpactHubAdminRoot.d.ts","sourceRoot":"","sources":["../../src/ecoimpacthub/EcoImpactHubAdminRoot.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AA2BhC,OAAO,KAAK,EACV,qBAAqB,EAStB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,0BAA2B,SAAQ,qBAAqB;IACvE,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAyiBD,eAAO,MAAM,qBAAqB,EAAE,EAAE,CAAC,0BAA0B,CAmBhE,CAAC;AAEF,OAAO,EAAE,qBAAqB,IAAI,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
import { EcoImpactHubProvider as e } from "./context/EcoImpactHubContext.js";
|
|
2
|
+
import { PageLayout as t } from "./components/PageLayout.js";
|
|
3
|
+
import { formatCo2e as n, formatDate as r, formatEnumLabel as i } from "./utils/formatters.js";
|
|
4
|
+
import { StatusBadge as a } from "./components/StatusBadge.js";
|
|
5
|
+
import { ErrorView as o, LoadingView as s, Section as c } from "./components/StateViews.js";
|
|
6
|
+
import { EmptyState as l } from "./components/EmptyState.js";
|
|
7
|
+
import { useEcoArchiveSite as u, useEcoCarbonEntries as d, useEcoPublishReport as f, useEcoReports as p, useEcoSensors as m, useEcoSetSensorStatus as h, useEcoSites as g, useEcoVerifyCarbonEntry as _ } from "./hooks/useEcoImpactHubApi.js";
|
|
8
|
+
import { Tabs as v } from "./components/Tabs.js";
|
|
9
|
+
import { DataTable as y } from "./components/DataTable.js";
|
|
10
|
+
import { Pagination as b } from "./components/Pagination.js";
|
|
11
|
+
import { FilterTabs as x } from "./components/FilterTabs.js";
|
|
12
|
+
import { useMemo as S, useState as C } from "react";
|
|
13
|
+
import { QueryClient as w, QueryClientProvider as T } from "@tanstack/react-query";
|
|
14
|
+
import { FeatureFlagProvider as E } from "@burdenoff/fe-libs/shared/feature-flags";
|
|
15
|
+
import { Factory as D, FileText as O, MapPin as k, Radio as A, ShieldCheck as j } from "lucide-react";
|
|
16
|
+
import { Fragment as M, jsx as N, jsxs as P } from "react/jsx-runtime";
|
|
17
|
+
import { Button as F } from "@burdenoff/fe-libs/ui";
|
|
18
|
+
import { PermissionProvider as I } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
19
|
+
//#region src/ecoimpacthub/EcoImpactHubAdminRoot.tsx
|
|
20
|
+
var L = new w({ defaultOptions: { queries: {
|
|
21
|
+
staleTime: 30 * 1e3,
|
|
22
|
+
retry: 1,
|
|
23
|
+
refetchOnWindowFocus: !1
|
|
24
|
+
} } }), R = 12, z = [
|
|
25
|
+
{
|
|
26
|
+
value: "ALL",
|
|
27
|
+
label: "All"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
value: "ACTIVE",
|
|
31
|
+
label: "Active"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
value: "MONITORING_PAUSED",
|
|
35
|
+
label: "Paused"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
value: "ARCHIVED",
|
|
39
|
+
label: "Archived"
|
|
40
|
+
}
|
|
41
|
+
], B = [
|
|
42
|
+
{
|
|
43
|
+
value: "ALL",
|
|
44
|
+
label: "All"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
value: "ONLINE",
|
|
48
|
+
label: "Online"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
value: "OFFLINE",
|
|
52
|
+
label: "Offline"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
value: "DEGRADED",
|
|
56
|
+
label: "Degraded"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
value: "MAINTENANCE",
|
|
60
|
+
label: "Maintenance"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
value: "RETIRED",
|
|
64
|
+
label: "Retired"
|
|
65
|
+
}
|
|
66
|
+
], V = [
|
|
67
|
+
{
|
|
68
|
+
value: "ALL",
|
|
69
|
+
label: "All"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
value: "DRAFT",
|
|
73
|
+
label: "Draft"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
value: "RECORDED",
|
|
77
|
+
label: "Recorded"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
value: "VERIFIED",
|
|
81
|
+
label: "Verified"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
value: "ADJUSTED",
|
|
85
|
+
label: "Adjusted"
|
|
86
|
+
}
|
|
87
|
+
], H = [
|
|
88
|
+
{
|
|
89
|
+
value: "ALL",
|
|
90
|
+
label: "All"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
value: "DRAFT",
|
|
94
|
+
label: "Draft"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
value: "IN_REVIEW",
|
|
98
|
+
label: "In Review"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
value: "PUBLISHED",
|
|
102
|
+
label: "Published"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
value: "ARCHIVED",
|
|
106
|
+
label: "Archived"
|
|
107
|
+
}
|
|
108
|
+
];
|
|
109
|
+
function U({ site: e }) {
|
|
110
|
+
let t = u();
|
|
111
|
+
return e.status === "ARCHIVED" ? /* @__PURE__ */ N("span", {
|
|
112
|
+
className: "text-xs text-text-secondary",
|
|
113
|
+
children: "Archived"
|
|
114
|
+
}) : /* @__PURE__ */ N(F, {
|
|
115
|
+
variant: "outline",
|
|
116
|
+
size: "sm",
|
|
117
|
+
onClick: () => t.mutate(e.id),
|
|
118
|
+
disabled: t.isPending,
|
|
119
|
+
children: "Archive"
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function W() {
|
|
123
|
+
let [e, t] = C("ALL"), { data: n, isLoading: u, error: d, refetch: f } = g({
|
|
124
|
+
status: e === "ALL" ? void 0 : e,
|
|
125
|
+
pagination: { limit: 100 }
|
|
126
|
+
}), p = S(() => [
|
|
127
|
+
{
|
|
128
|
+
key: "name",
|
|
129
|
+
header: "Site",
|
|
130
|
+
render: (e) => /* @__PURE__ */ P("div", {
|
|
131
|
+
className: "min-w-0",
|
|
132
|
+
children: [/* @__PURE__ */ N("p", {
|
|
133
|
+
className: "font-medium text-text-primary truncate",
|
|
134
|
+
children: e.name
|
|
135
|
+
}), e.code && /* @__PURE__ */ N("p", {
|
|
136
|
+
className: "text-xs text-text-secondary",
|
|
137
|
+
children: e.code
|
|
138
|
+
})]
|
|
139
|
+
}),
|
|
140
|
+
sortValue: (e) => e.name.toLowerCase()
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
key: "type",
|
|
144
|
+
header: "Type",
|
|
145
|
+
render: (e) => i(e.type)
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
key: "region",
|
|
149
|
+
header: "Region",
|
|
150
|
+
render: (e) => e.region ?? "—",
|
|
151
|
+
hideOnMobile: !0
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
key: "status",
|
|
155
|
+
header: "Status",
|
|
156
|
+
render: (e) => /* @__PURE__ */ N(a, { status: e.status })
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
key: "created",
|
|
160
|
+
header: "Created",
|
|
161
|
+
render: (e) => r(e.createdAt),
|
|
162
|
+
sortValue: (e) => new Date(e.createdAt).getTime(),
|
|
163
|
+
hideOnMobile: !0
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
key: "actions",
|
|
167
|
+
header: "Actions",
|
|
168
|
+
align: "right",
|
|
169
|
+
render: (e) => /* @__PURE__ */ N(U, { site: e })
|
|
170
|
+
}
|
|
171
|
+
], []);
|
|
172
|
+
if (u) return /* @__PURE__ */ N(s, { label: "Loading sites…" });
|
|
173
|
+
if (d) return /* @__PURE__ */ N(o, {
|
|
174
|
+
title: "Could not load sites",
|
|
175
|
+
message: d.message,
|
|
176
|
+
onRetry: f
|
|
177
|
+
});
|
|
178
|
+
let m = n?.items ?? [];
|
|
179
|
+
return /* @__PURE__ */ P(c, {
|
|
180
|
+
title: "Site registry",
|
|
181
|
+
description: "Pause monitoring or archive decommissioned sites.",
|
|
182
|
+
children: [/* @__PURE__ */ N("div", {
|
|
183
|
+
className: "mb-4",
|
|
184
|
+
children: /* @__PURE__ */ N(x, {
|
|
185
|
+
options: z,
|
|
186
|
+
value: e,
|
|
187
|
+
onChange: t
|
|
188
|
+
})
|
|
189
|
+
}), m.length === 0 ? /* @__PURE__ */ N(l, {
|
|
190
|
+
icon: /* @__PURE__ */ N(k, { size: 40 }),
|
|
191
|
+
title: "No sites found",
|
|
192
|
+
description: `There are no ${e === "ALL" ? "" : e.toLowerCase()} sites in this workspace.`
|
|
193
|
+
}) : /* @__PURE__ */ N(y, {
|
|
194
|
+
columns: p,
|
|
195
|
+
rows: m,
|
|
196
|
+
rowKey: (e) => e.id,
|
|
197
|
+
defaultSort: {
|
|
198
|
+
key: "created",
|
|
199
|
+
dir: "desc"
|
|
200
|
+
}
|
|
201
|
+
})]
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
var G = {
|
|
205
|
+
ONLINE: "MAINTENANCE",
|
|
206
|
+
OFFLINE: "MAINTENANCE",
|
|
207
|
+
DEGRADED: "MAINTENANCE",
|
|
208
|
+
MAINTENANCE: "ONLINE",
|
|
209
|
+
RETIRED: null
|
|
210
|
+
};
|
|
211
|
+
function K({ sensor: e }) {
|
|
212
|
+
let t = h(), n = G[e.status];
|
|
213
|
+
return /* @__PURE__ */ P("div", {
|
|
214
|
+
className: "flex flex-wrap items-center justify-end gap-2",
|
|
215
|
+
children: [n && /* @__PURE__ */ N(F, {
|
|
216
|
+
variant: "outline",
|
|
217
|
+
size: "sm",
|
|
218
|
+
onClick: () => t.mutate({
|
|
219
|
+
id: e.id,
|
|
220
|
+
status: n
|
|
221
|
+
}),
|
|
222
|
+
disabled: t.isPending,
|
|
223
|
+
children: n === "MAINTENANCE" ? "Send to maintenance" : "Bring online"
|
|
224
|
+
}), e.status !== "RETIRED" && /* @__PURE__ */ N(F, {
|
|
225
|
+
variant: "outline",
|
|
226
|
+
size: "sm",
|
|
227
|
+
onClick: () => t.mutate({
|
|
228
|
+
id: e.id,
|
|
229
|
+
status: "RETIRED"
|
|
230
|
+
}),
|
|
231
|
+
disabled: t.isPending,
|
|
232
|
+
children: "Retire"
|
|
233
|
+
})]
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function q() {
|
|
237
|
+
let [e, t] = C("ALL"), { data: n, isLoading: u, error: d, refetch: f } = m({ status: e === "ALL" ? void 0 : e }), p = S(() => [
|
|
238
|
+
{
|
|
239
|
+
key: "name",
|
|
240
|
+
header: "Sensor",
|
|
241
|
+
render: (e) => /* @__PURE__ */ P("div", {
|
|
242
|
+
className: "min-w-0",
|
|
243
|
+
children: [/* @__PURE__ */ N("p", {
|
|
244
|
+
className: "font-medium text-text-primary truncate",
|
|
245
|
+
children: e.name
|
|
246
|
+
}), e.hardwareId && /* @__PURE__ */ N("p", {
|
|
247
|
+
className: "font-mono text-xs text-text-secondary",
|
|
248
|
+
children: e.hardwareId
|
|
249
|
+
})]
|
|
250
|
+
}),
|
|
251
|
+
sortValue: (e) => e.name.toLowerCase()
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
key: "kind",
|
|
255
|
+
header: "Kind",
|
|
256
|
+
render: (e) => i(e.kind)
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
key: "site",
|
|
260
|
+
header: "Site ID",
|
|
261
|
+
render: (e) => /* @__PURE__ */ N("span", {
|
|
262
|
+
className: "font-mono text-xs text-text-secondary",
|
|
263
|
+
children: e.siteId
|
|
264
|
+
}),
|
|
265
|
+
hideOnMobile: !0
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
key: "status",
|
|
269
|
+
header: "Status",
|
|
270
|
+
render: (e) => /* @__PURE__ */ N(a, { status: e.status })
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
key: "lastReading",
|
|
274
|
+
header: "Last Reading",
|
|
275
|
+
render: (e) => e.lastReadingAt ? r(e.lastReadingAt) : "—",
|
|
276
|
+
sortValue: (e) => e.lastReadingAt ? new Date(e.lastReadingAt).getTime() : 0,
|
|
277
|
+
hideOnMobile: !0
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
key: "actions",
|
|
281
|
+
header: "Actions",
|
|
282
|
+
align: "right",
|
|
283
|
+
render: (e) => /* @__PURE__ */ N(K, { sensor: e })
|
|
284
|
+
}
|
|
285
|
+
], []);
|
|
286
|
+
if (u) return /* @__PURE__ */ N(s, { label: "Loading sensors…" });
|
|
287
|
+
if (d) return /* @__PURE__ */ N(o, {
|
|
288
|
+
title: "Could not load sensors",
|
|
289
|
+
message: d.message,
|
|
290
|
+
onRetry: f
|
|
291
|
+
});
|
|
292
|
+
let h = n?.items ?? [];
|
|
293
|
+
return /* @__PURE__ */ P(c, {
|
|
294
|
+
title: "Sensor fleet",
|
|
295
|
+
description: "Retire hardware or move sensors into maintenance.",
|
|
296
|
+
children: [/* @__PURE__ */ N("div", {
|
|
297
|
+
className: "mb-4",
|
|
298
|
+
children: /* @__PURE__ */ N(x, {
|
|
299
|
+
options: B,
|
|
300
|
+
value: e,
|
|
301
|
+
onChange: t
|
|
302
|
+
})
|
|
303
|
+
}), h.length === 0 ? /* @__PURE__ */ N(l, {
|
|
304
|
+
icon: /* @__PURE__ */ N(A, { size: 40 }),
|
|
305
|
+
title: "No sensors found",
|
|
306
|
+
description: `There are no ${e === "ALL" ? "" : e.toLowerCase()} sensors in this workspace.`
|
|
307
|
+
}) : /* @__PURE__ */ N(y, {
|
|
308
|
+
columns: p,
|
|
309
|
+
rows: h,
|
|
310
|
+
rowKey: (e) => e.id,
|
|
311
|
+
defaultSort: {
|
|
312
|
+
key: "lastReading",
|
|
313
|
+
dir: "desc"
|
|
314
|
+
}
|
|
315
|
+
})]
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
function J({ entry: e }) {
|
|
319
|
+
let t = _();
|
|
320
|
+
return e.status === "VERIFIED" ? /* @__PURE__ */ N("span", {
|
|
321
|
+
className: "text-xs text-text-secondary",
|
|
322
|
+
children: "Verified"
|
|
323
|
+
}) : /* @__PURE__ */ N(F, {
|
|
324
|
+
variant: "outline",
|
|
325
|
+
size: "sm",
|
|
326
|
+
onClick: () => t.mutate(e.id),
|
|
327
|
+
disabled: t.isPending,
|
|
328
|
+
children: "Verify"
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
function Y() {
|
|
332
|
+
let [e, t] = C("ALL"), [u, f] = C(0), [p, m] = C([]), h = u > 0 ? p[u - 1] : void 0, { data: g, isLoading: _, error: v, refetch: w } = d({
|
|
333
|
+
status: e === "ALL" ? void 0 : e,
|
|
334
|
+
pagination: {
|
|
335
|
+
limit: R,
|
|
336
|
+
cursor: h
|
|
337
|
+
}
|
|
338
|
+
}), T = S(() => [
|
|
339
|
+
{
|
|
340
|
+
key: "category",
|
|
341
|
+
header: "Category",
|
|
342
|
+
render: (e) => /* @__PURE__ */ P("div", {
|
|
343
|
+
className: "min-w-0",
|
|
344
|
+
children: [/* @__PURE__ */ N("p", {
|
|
345
|
+
className: "font-medium text-text-primary truncate",
|
|
346
|
+
children: e.category
|
|
347
|
+
}), e.factor && /* @__PURE__ */ N("p", {
|
|
348
|
+
className: "text-xs text-text-secondary",
|
|
349
|
+
children: e.factor.name
|
|
350
|
+
})]
|
|
351
|
+
})
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
key: "scope",
|
|
355
|
+
header: "Scope",
|
|
356
|
+
render: (e) => i(e.scope)
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
key: "co2e",
|
|
360
|
+
header: "CO₂e",
|
|
361
|
+
align: "right",
|
|
362
|
+
render: (e) => n(e.co2eKg),
|
|
363
|
+
sortValue: (e) => e.co2eKg
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
key: "period",
|
|
367
|
+
header: "Period",
|
|
368
|
+
render: (e) => r(e.periodStart),
|
|
369
|
+
sortValue: (e) => new Date(e.periodStart).getTime(),
|
|
370
|
+
hideOnMobile: !0
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
key: "status",
|
|
374
|
+
header: "Status",
|
|
375
|
+
render: (e) => /* @__PURE__ */ N(a, { status: e.status })
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
key: "actions",
|
|
379
|
+
header: "Actions",
|
|
380
|
+
align: "right",
|
|
381
|
+
render: (e) => /* @__PURE__ */ N(J, { entry: e })
|
|
382
|
+
}
|
|
383
|
+
], []), E = (e) => {
|
|
384
|
+
e > u && g?.pageInfo.cursor ? m((e) => [...e, g.pageInfo.cursor]) : e < u && m((e) => e.slice(0, -1)), f(e);
|
|
385
|
+
};
|
|
386
|
+
if (_) return /* @__PURE__ */ N(s, { label: "Loading carbon entries…" });
|
|
387
|
+
if (v) return /* @__PURE__ */ N(o, {
|
|
388
|
+
title: "Could not load carbon entries",
|
|
389
|
+
message: v.message,
|
|
390
|
+
onRetry: w
|
|
391
|
+
});
|
|
392
|
+
let O = g?.items ?? [];
|
|
393
|
+
return /* @__PURE__ */ P(c, {
|
|
394
|
+
title: "Carbon ledger",
|
|
395
|
+
description: "Verify DRAFT/RECORDED entries across all sites and scopes.",
|
|
396
|
+
children: [/* @__PURE__ */ N("div", {
|
|
397
|
+
className: "mb-4",
|
|
398
|
+
children: /* @__PURE__ */ N(x, {
|
|
399
|
+
options: V,
|
|
400
|
+
value: e,
|
|
401
|
+
onChange: (e) => {
|
|
402
|
+
t(e), f(0), m([]);
|
|
403
|
+
}
|
|
404
|
+
})
|
|
405
|
+
}), O.length === 0 ? /* @__PURE__ */ N(l, {
|
|
406
|
+
icon: /* @__PURE__ */ N(D, { size: 40 }),
|
|
407
|
+
title: "No carbon entries found",
|
|
408
|
+
description: `There are no ${e === "ALL" ? "" : e.toLowerCase()} entries in this workspace.`
|
|
409
|
+
}) : /* @__PURE__ */ P(M, { children: [/* @__PURE__ */ N(y, {
|
|
410
|
+
columns: T,
|
|
411
|
+
rows: O,
|
|
412
|
+
rowKey: (e) => e.id,
|
|
413
|
+
defaultSort: {
|
|
414
|
+
key: "period",
|
|
415
|
+
dir: "desc"
|
|
416
|
+
}
|
|
417
|
+
}), /* @__PURE__ */ N(b, {
|
|
418
|
+
page: u,
|
|
419
|
+
pageSize: R,
|
|
420
|
+
itemCount: O.length,
|
|
421
|
+
hasMore: g?.pageInfo.hasMore ?? !1,
|
|
422
|
+
onPageChange: E
|
|
423
|
+
})] })]
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
function X({ report: e }) {
|
|
427
|
+
let t = f();
|
|
428
|
+
return e.status === "PUBLISHED" || e.status === "ARCHIVED" ? /* @__PURE__ */ N("span", {
|
|
429
|
+
className: "text-xs text-text-secondary",
|
|
430
|
+
children: i(e.status)
|
|
431
|
+
}) : /* @__PURE__ */ N(F, {
|
|
432
|
+
variant: "outline",
|
|
433
|
+
size: "sm",
|
|
434
|
+
onClick: () => t.mutate({
|
|
435
|
+
id: e.id,
|
|
436
|
+
fileId: e.file?.id ?? null
|
|
437
|
+
}),
|
|
438
|
+
disabled: t.isPending,
|
|
439
|
+
children: "Publish"
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
function Z() {
|
|
443
|
+
let [e, t] = C("ALL"), { data: n, isLoading: u, error: d, refetch: f } = p(e === "ALL" ? void 0 : e, { limit: 100 }), m = S(() => [
|
|
444
|
+
{
|
|
445
|
+
key: "title",
|
|
446
|
+
header: "Report",
|
|
447
|
+
render: (e) => /* @__PURE__ */ N("p", {
|
|
448
|
+
className: "font-medium text-text-primary truncate",
|
|
449
|
+
children: e.title
|
|
450
|
+
}),
|
|
451
|
+
sortValue: (e) => e.title.toLowerCase()
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
key: "framework",
|
|
455
|
+
header: "Framework",
|
|
456
|
+
render: (e) => i(e.framework)
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
key: "period",
|
|
460
|
+
header: "Period",
|
|
461
|
+
render: (e) => `${r(e.periodStart)} – ${r(e.periodEnd)}`,
|
|
462
|
+
hideOnMobile: !0
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
key: "status",
|
|
466
|
+
header: "Status",
|
|
467
|
+
render: (e) => /* @__PURE__ */ N(a, { status: e.status })
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
key: "published",
|
|
471
|
+
header: "Published",
|
|
472
|
+
render: (e) => e.publishedAt ? r(e.publishedAt) : "—",
|
|
473
|
+
sortValue: (e) => e.publishedAt ? new Date(e.publishedAt).getTime() : 0,
|
|
474
|
+
hideOnMobile: !0
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
key: "actions",
|
|
478
|
+
header: "Actions",
|
|
479
|
+
align: "right",
|
|
480
|
+
render: (e) => /* @__PURE__ */ N(X, { report: e })
|
|
481
|
+
}
|
|
482
|
+
], []);
|
|
483
|
+
if (u) return /* @__PURE__ */ N(s, { label: "Loading reports…" });
|
|
484
|
+
if (d) return /* @__PURE__ */ N(o, {
|
|
485
|
+
title: "Could not load reports",
|
|
486
|
+
message: d.message,
|
|
487
|
+
onRetry: f
|
|
488
|
+
});
|
|
489
|
+
let h = n?.items ?? [];
|
|
490
|
+
return /* @__PURE__ */ P(c, {
|
|
491
|
+
title: "Sustainability reports",
|
|
492
|
+
description: "Publish reports once their line items are complete.",
|
|
493
|
+
children: [/* @__PURE__ */ N("div", {
|
|
494
|
+
className: "mb-4",
|
|
495
|
+
children: /* @__PURE__ */ N(x, {
|
|
496
|
+
options: H,
|
|
497
|
+
value: e,
|
|
498
|
+
onChange: t
|
|
499
|
+
})
|
|
500
|
+
}), h.length === 0 ? /* @__PURE__ */ N(l, {
|
|
501
|
+
icon: /* @__PURE__ */ N(O, { size: 40 }),
|
|
502
|
+
title: "No reports found",
|
|
503
|
+
description: `There are no ${e === "ALL" ? "" : e.toLowerCase()} reports in this workspace.`
|
|
504
|
+
}) : /* @__PURE__ */ N(y, {
|
|
505
|
+
columns: m,
|
|
506
|
+
rows: h,
|
|
507
|
+
rowKey: (e) => e.id,
|
|
508
|
+
defaultSort: {
|
|
509
|
+
key: "period",
|
|
510
|
+
dir: "desc"
|
|
511
|
+
}
|
|
512
|
+
})]
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function Q() {
|
|
516
|
+
let [e, n] = C("sites"), r = S(() => [
|
|
517
|
+
{
|
|
518
|
+
value: "sites",
|
|
519
|
+
label: "Sites",
|
|
520
|
+
icon: /* @__PURE__ */ N(k, { size: 18 })
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
value: "sensors",
|
|
524
|
+
label: "Sensors",
|
|
525
|
+
icon: /* @__PURE__ */ N(A, { size: 18 })
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
value: "carbon",
|
|
529
|
+
label: "Carbon Ledger",
|
|
530
|
+
icon: /* @__PURE__ */ N(D, { size: 18 })
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
value: "reports",
|
|
534
|
+
label: "Reports",
|
|
535
|
+
icon: /* @__PURE__ */ N(O, { size: 18 })
|
|
536
|
+
}
|
|
537
|
+
], []);
|
|
538
|
+
return /* @__PURE__ */ P(t, {
|
|
539
|
+
title: "EcoImpactHub Admin",
|
|
540
|
+
description: "Site, sensor, carbon-ledger and report governance.",
|
|
541
|
+
actions: /* @__PURE__ */ P("span", {
|
|
542
|
+
className: "inline-flex items-center gap-2 text-sm text-text-secondary",
|
|
543
|
+
children: [/* @__PURE__ */ N(j, { size: 18 }), "Workspace-scoped"]
|
|
544
|
+
}),
|
|
545
|
+
children: [/* @__PURE__ */ N(v, {
|
|
546
|
+
items: r,
|
|
547
|
+
value: e,
|
|
548
|
+
onChange: n
|
|
549
|
+
}), /* @__PURE__ */ P("div", {
|
|
550
|
+
className: "mt-6",
|
|
551
|
+
children: [
|
|
552
|
+
e === "sites" && /* @__PURE__ */ N(W, {}),
|
|
553
|
+
e === "sensors" && /* @__PURE__ */ N(q, {}),
|
|
554
|
+
e === "carbon" && /* @__PURE__ */ N(Y, {}),
|
|
555
|
+
e === "reports" && /* @__PURE__ */ N(Z, {})
|
|
556
|
+
]
|
|
557
|
+
})]
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
var $ = (t) => /* @__PURE__ */ N(T, {
|
|
561
|
+
client: L,
|
|
562
|
+
children: /* @__PURE__ */ N(E, {
|
|
563
|
+
workspaceId: t.workspaceId ?? null,
|
|
564
|
+
gateway: "global",
|
|
565
|
+
defaultEnabled: !0,
|
|
566
|
+
children: /* @__PURE__ */ N(I, {
|
|
567
|
+
scopeId: t.workspaceId ?? null,
|
|
568
|
+
gateway: "workspace",
|
|
569
|
+
children: /* @__PURE__ */ N(e, {
|
|
570
|
+
...t,
|
|
571
|
+
children: /* @__PURE__ */ N(Q, {})
|
|
572
|
+
})
|
|
573
|
+
})
|
|
574
|
+
})
|
|
575
|
+
});
|
|
576
|
+
//#endregion
|
|
577
|
+
export { $ as EcoImpactHubAdminRoot };
|
|
578
|
+
|
|
579
|
+
//# sourceMappingURL=EcoImpactHubAdminRoot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EcoImpactHubAdminRoot.js","names":[],"sources":["../../src/ecoimpacthub/EcoImpactHubAdminRoot.tsx"],"sourcesContent":["/**\n * EcoImpactHub Admin Root\n * @module ecoimpacthub\n *\n * Product-specific admin surface mounted inside `admin-app` under\n * `/admin/ecoimpacthub` (BOFF-3118). Per fleet-wide policy the ONLY valid\n * admin surface is the shared `admin.burdenoff.com` app — this is a\n * microfrontend mounted there, not a new subdomain. It covers three\n * governance operations product owners need outside the day-to-day\n * monitoring UI:\n *\n * 1. Site / sensor governance — pause monitoring, retire hardware, archive\n * decommissioned sites.\n * 2. Carbon-ledger oversight — inspect recorded carbon entries across all\n * sites/scopes and verify DRAFT/RECORDED entries.\n * 3. Report sign-off — publish sustainability reports once their line items\n * are complete.\n *\n * Reuses the real `wspace-ecoimpacthub-svc` GraphQL operations already\n * consumed by the workspace-facing pages (`ecoListSites`, `ecoArchiveSite`,\n * `ecoListSensors`, `ecoSetSensorStatus`, `ecoListCarbonEntries`,\n * `ecoVerifyCarbonEntry`, `ecoListReports`, `ecoPublishReport`) — no new\n * backend surface. Every mutation still carries its own `@rbac` directive at\n * the gateway; this panel does not re-implement authorization, it is a\n * governance-focused view over the same RBAC-enforced API.\n *\n * Remaining gap (documented, not built here): report-approval workflow\n * routing through wspace-workflow-svc (depends on the C2 event/workflow\n * wiring landing first) — today \"publish\" is a direct status transition,\n * not a multi-step approval chain.\n */\n\nimport type { FC } from 'react';\nimport { useMemo, useState } from 'react';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { PermissionProvider } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { MapPin, Radio, Factory, FileText, ShieldCheck } from 'lucide-react';\nimport { EcoImpactHubProvider } from './context/EcoImpactHubContext';\nimport { PageLayout } from './components/PageLayout';\nimport { Tabs, type TabItem } from './components/Tabs';\nimport { DataTable, type Column } from './components/DataTable';\nimport { StatusBadge } from './components/StatusBadge';\nimport { LoadingView, ErrorView, Section } from './components/StateViews';\nimport { EmptyState } from './components/EmptyState';\nimport { Pagination } from './components/Pagination';\nimport { FilterTabs, type FilterOption } from './components/FilterTabs';\nimport {\n useEcoSites,\n useEcoArchiveSite,\n useEcoSensors,\n useEcoSetSensorStatus,\n useEcoCarbonEntries,\n useEcoVerifyCarbonEntry,\n useEcoReports,\n useEcoPublishReport,\n} from './hooks/useEcoImpactHubApi';\nimport { formatDate, formatCo2e, formatEnumLabel } from './utils';\nimport type {\n EcoImpactHubRootProps,\n EcoSite,\n EcoSiteStatus,\n EcoSensor,\n EcoSensorStatus,\n EcoCarbonEntry,\n EcoCarbonEntryStatus,\n EcoReport,\n EcoReportStatus,\n} from './types';\n\nexport interface EcoImpactHubAdminRootProps extends EcoImpactHubRootProps {\n /** Workspace token is supplied by admin-app for workspace-scoped MFEs. */\n workspaceToken?: string;\n}\n\ntype AdminTab = 'sites' | 'sensors' | 'carbon' | 'reports';\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n staleTime: 30 * 1000,\n retry: 1,\n refetchOnWindowFocus: false,\n },\n },\n});\n\nconst PAGE_SIZE = 12;\n\nconst SITE_STATUS_OPTIONS: FilterOption<'ALL' | EcoSiteStatus>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'MONITORING_PAUSED', label: 'Paused' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nconst SENSOR_STATUS_OPTIONS: FilterOption<'ALL' | EcoSensorStatus>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'ONLINE', label: 'Online' },\n { value: 'OFFLINE', label: 'Offline' },\n { value: 'DEGRADED', label: 'Degraded' },\n { value: 'MAINTENANCE', label: 'Maintenance' },\n { value: 'RETIRED', label: 'Retired' },\n];\n\nconst CARBON_STATUS_OPTIONS: FilterOption<'ALL' | EcoCarbonEntryStatus>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'RECORDED', label: 'Recorded' },\n { value: 'VERIFIED', label: 'Verified' },\n { value: 'ADJUSTED', label: 'Adjusted' },\n];\n\nconst REPORT_STATUS_OPTIONS: FilterOption<'ALL' | EcoReportStatus>[] = [\n { value: 'ALL', label: 'All' },\n { value: 'DRAFT', label: 'Draft' },\n { value: 'IN_REVIEW', label: 'In Review' },\n { value: 'PUBLISHED', label: 'Published' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\n// ============================================================================\n// Sites governance\n// ============================================================================\n\nfunction SiteActions({ site }: { site: EcoSite }) {\n const archive = useEcoArchiveSite();\n if (site.status === 'ARCHIVED') {\n return <span className=\"text-xs text-text-secondary\">Archived</span>;\n }\n return (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => archive.mutate(site.id)}\n disabled={archive.isPending}\n >\n Archive\n </Button>\n );\n}\n\nfunction SitesPanel() {\n const [status, setStatus] = useState<'ALL' | EcoSiteStatus>('ALL');\n const { data, isLoading, error, refetch } = useEcoSites({\n status: status === 'ALL' ? undefined : status,\n pagination: { limit: 100 },\n });\n\n const columns = useMemo<Column<EcoSite>[]>(\n () => [\n {\n key: 'name',\n header: 'Site',\n render: (s) => (\n <div className=\"min-w-0\">\n <p className=\"font-medium text-text-primary truncate\">{s.name}</p>\n {s.code && <p className=\"text-xs text-text-secondary\">{s.code}</p>}\n </div>\n ),\n sortValue: (s) => s.name.toLowerCase(),\n },\n {\n key: 'type',\n header: 'Type',\n render: (s) => formatEnumLabel(s.type),\n },\n {\n key: 'region',\n header: 'Region',\n render: (s) => s.region ?? '—',\n hideOnMobile: true,\n },\n {\n key: 'status',\n header: 'Status',\n render: (s) => <StatusBadge status={s.status} />,\n },\n {\n key: 'created',\n header: 'Created',\n render: (s) => formatDate(s.createdAt),\n sortValue: (s) => new Date(s.createdAt).getTime(),\n hideOnMobile: true,\n },\n {\n key: 'actions',\n header: 'Actions',\n align: 'right',\n render: (s) => <SiteActions site={s} />,\n },\n ],\n []\n );\n\n if (isLoading) return <LoadingView label=\"Loading sites…\" />;\n if (error)\n return <ErrorView title=\"Could not load sites\" message={error.message} onRetry={refetch} />;\n\n const rows = data?.items ?? [];\n\n return (\n <Section title=\"Site registry\" description=\"Pause monitoring or archive decommissioned sites.\">\n <div className=\"mb-4\">\n <FilterTabs options={SITE_STATUS_OPTIONS} value={status} onChange={setStatus} />\n </div>\n {rows.length === 0 ? (\n <EmptyState\n icon={<MapPin size={40} />}\n title=\"No sites found\"\n description={`There are no ${status === 'ALL' ? '' : status.toLowerCase()} sites in this workspace.`}\n />\n ) : (\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(s) => s.id}\n defaultSort={{ key: 'created', dir: 'desc' }}\n />\n )}\n </Section>\n );\n}\n\n// ============================================================================\n// Sensor governance\n// ============================================================================\n\nconst SENSOR_STATUS_TRANSITIONS: Record<EcoSensorStatus, EcoSensorStatus | null> = {\n ONLINE: 'MAINTENANCE',\n OFFLINE: 'MAINTENANCE',\n DEGRADED: 'MAINTENANCE',\n MAINTENANCE: 'ONLINE',\n RETIRED: null,\n};\n\nfunction SensorActions({ sensor }: { sensor: EcoSensor }) {\n const setStatus = useEcoSetSensorStatus();\n const nextStatus = SENSOR_STATUS_TRANSITIONS[sensor.status];\n\n return (\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n {nextStatus && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setStatus.mutate({ id: sensor.id, status: nextStatus })}\n disabled={setStatus.isPending}\n >\n {nextStatus === 'MAINTENANCE' ? 'Send to maintenance' : 'Bring online'}\n </Button>\n )}\n {sensor.status !== 'RETIRED' && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setStatus.mutate({ id: sensor.id, status: 'RETIRED' })}\n disabled={setStatus.isPending}\n >\n Retire\n </Button>\n )}\n </div>\n );\n}\n\nfunction SensorsPanel() {\n const [status, setStatus] = useState<'ALL' | EcoSensorStatus>('ALL');\n const { data, isLoading, error, refetch } = useEcoSensors({\n status: status === 'ALL' ? undefined : status,\n });\n\n const columns = useMemo<Column<EcoSensor>[]>(\n () => [\n {\n key: 'name',\n header: 'Sensor',\n render: (s) => (\n <div className=\"min-w-0\">\n <p className=\"font-medium text-text-primary truncate\">{s.name}</p>\n {s.hardwareId && (\n <p className=\"font-mono text-xs text-text-secondary\">{s.hardwareId}</p>\n )}\n </div>\n ),\n sortValue: (s) => s.name.toLowerCase(),\n },\n {\n key: 'kind',\n header: 'Kind',\n render: (s) => formatEnumLabel(s.kind),\n },\n {\n key: 'site',\n header: 'Site ID',\n render: (s) => <span className=\"font-mono text-xs text-text-secondary\">{s.siteId}</span>,\n hideOnMobile: true,\n },\n {\n key: 'status',\n header: 'Status',\n render: (s) => <StatusBadge status={s.status} />,\n },\n {\n key: 'lastReading',\n header: 'Last Reading',\n render: (s) => (s.lastReadingAt ? formatDate(s.lastReadingAt) : '—'),\n sortValue: (s) => (s.lastReadingAt ? new Date(s.lastReadingAt).getTime() : 0),\n hideOnMobile: true,\n },\n {\n key: 'actions',\n header: 'Actions',\n align: 'right',\n render: (s) => <SensorActions sensor={s} />,\n },\n ],\n []\n );\n\n if (isLoading) return <LoadingView label=\"Loading sensors…\" />;\n if (error)\n return <ErrorView title=\"Could not load sensors\" message={error.message} onRetry={refetch} />;\n\n const rows = data?.items ?? [];\n\n return (\n <Section title=\"Sensor fleet\" description=\"Retire hardware or move sensors into maintenance.\">\n <div className=\"mb-4\">\n <FilterTabs options={SENSOR_STATUS_OPTIONS} value={status} onChange={setStatus} />\n </div>\n {rows.length === 0 ? (\n <EmptyState\n icon={<Radio size={40} />}\n title=\"No sensors found\"\n description={`There are no ${status === 'ALL' ? '' : status.toLowerCase()} sensors in this workspace.`}\n />\n ) : (\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(s) => s.id}\n defaultSort={{ key: 'lastReading', dir: 'desc' }}\n />\n )}\n </Section>\n );\n}\n\n// ============================================================================\n// Carbon-ledger oversight\n// ============================================================================\n\nfunction CarbonEntryActions({ entry }: { entry: EcoCarbonEntry }) {\n const verify = useEcoVerifyCarbonEntry();\n if (entry.status === 'VERIFIED') {\n return <span className=\"text-xs text-text-secondary\">Verified</span>;\n }\n return (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => verify.mutate(entry.id)}\n disabled={verify.isPending}\n >\n Verify\n </Button>\n );\n}\n\nfunction CarbonLedgerPanel() {\n const [status, setStatus] = useState<'ALL' | EcoCarbonEntryStatus>('ALL');\n const [page, setPage] = useState(0);\n const [cursors, setCursors] = useState<string[]>([]);\n\n const cursor = page > 0 ? cursors[page - 1] : undefined;\n const { data, isLoading, error, refetch } = useEcoCarbonEntries({\n status: status === 'ALL' ? undefined : status,\n pagination: { limit: PAGE_SIZE, cursor },\n });\n\n const columns = useMemo<Column<EcoCarbonEntry>[]>(\n () => [\n {\n key: 'category',\n header: 'Category',\n render: (c) => (\n <div className=\"min-w-0\">\n <p className=\"font-medium text-text-primary truncate\">{c.category}</p>\n {c.factor && <p className=\"text-xs text-text-secondary\">{c.factor.name}</p>}\n </div>\n ),\n },\n {\n key: 'scope',\n header: 'Scope',\n render: (c) => formatEnumLabel(c.scope),\n },\n {\n key: 'co2e',\n header: 'CO₂e',\n align: 'right',\n render: (c) => formatCo2e(c.co2eKg),\n sortValue: (c) => c.co2eKg,\n },\n {\n key: 'period',\n header: 'Period',\n render: (c) => formatDate(c.periodStart),\n sortValue: (c) => new Date(c.periodStart).getTime(),\n hideOnMobile: true,\n },\n {\n key: 'status',\n header: 'Status',\n render: (c) => <StatusBadge status={c.status} />,\n },\n {\n key: 'actions',\n header: 'Actions',\n align: 'right',\n render: (c) => <CarbonEntryActions entry={c} />,\n },\n ],\n []\n );\n\n const handlePageChange = (nextPage: number) => {\n if (nextPage > page && data?.pageInfo.cursor) {\n setCursors((prev) => [...prev, data.pageInfo.cursor as string]);\n } else if (nextPage < page) {\n setCursors((prev) => prev.slice(0, -1));\n }\n setPage(nextPage);\n };\n\n if (isLoading) return <LoadingView label=\"Loading carbon entries…\" />;\n if (error)\n return (\n <ErrorView title=\"Could not load carbon entries\" message={error.message} onRetry={refetch} />\n );\n\n const rows = data?.items ?? [];\n\n return (\n <Section\n title=\"Carbon ledger\"\n description=\"Verify DRAFT/RECORDED entries across all sites and scopes.\"\n >\n <div className=\"mb-4\">\n <FilterTabs\n options={CARBON_STATUS_OPTIONS}\n value={status}\n onChange={(v) => {\n setStatus(v);\n setPage(0);\n setCursors([]);\n }}\n />\n </div>\n {rows.length === 0 ? (\n <EmptyState\n icon={<Factory size={40} />}\n title=\"No carbon entries found\"\n description={`There are no ${status === 'ALL' ? '' : status.toLowerCase()} entries in this workspace.`}\n />\n ) : (\n <>\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(c) => c.id}\n defaultSort={{ key: 'period', dir: 'desc' }}\n />\n <Pagination\n page={page}\n pageSize={PAGE_SIZE}\n itemCount={rows.length}\n hasMore={data?.pageInfo.hasMore ?? false}\n onPageChange={handlePageChange}\n />\n </>\n )}\n </Section>\n );\n}\n\n// ============================================================================\n// Report sign-off\n// ============================================================================\n\nfunction ReportActions({ report }: { report: EcoReport }) {\n const publish = useEcoPublishReport();\n if (report.status === 'PUBLISHED' || report.status === 'ARCHIVED') {\n return <span className=\"text-xs text-text-secondary\">{formatEnumLabel(report.status)}</span>;\n }\n return (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => publish.mutate({ id: report.id, fileId: report.file?.id ?? null })}\n disabled={publish.isPending}\n >\n Publish\n </Button>\n );\n}\n\nfunction ReportsPanel() {\n const [status, setStatus] = useState<'ALL' | EcoReportStatus>('ALL');\n const { data, isLoading, error, refetch } = useEcoReports(status === 'ALL' ? undefined : status, {\n limit: 100,\n });\n\n const columns = useMemo<Column<EcoReport>[]>(\n () => [\n {\n key: 'title',\n header: 'Report',\n render: (r) => <p className=\"font-medium text-text-primary truncate\">{r.title}</p>,\n sortValue: (r) => r.title.toLowerCase(),\n },\n {\n key: 'framework',\n header: 'Framework',\n render: (r) => formatEnumLabel(r.framework),\n },\n {\n key: 'period',\n header: 'Period',\n render: (r) => `${formatDate(r.periodStart)} – ${formatDate(r.periodEnd)}`,\n hideOnMobile: true,\n },\n {\n key: 'status',\n header: 'Status',\n render: (r) => <StatusBadge status={r.status} />,\n },\n {\n key: 'published',\n header: 'Published',\n render: (r) => (r.publishedAt ? formatDate(r.publishedAt) : '—'),\n sortValue: (r) => (r.publishedAt ? new Date(r.publishedAt).getTime() : 0),\n hideOnMobile: true,\n },\n {\n key: 'actions',\n header: 'Actions',\n align: 'right',\n render: (r) => <ReportActions report={r} />,\n },\n ],\n []\n );\n\n if (isLoading) return <LoadingView label=\"Loading reports…\" />;\n if (error)\n return <ErrorView title=\"Could not load reports\" message={error.message} onRetry={refetch} />;\n\n const rows = data?.items ?? [];\n\n return (\n <Section\n title=\"Sustainability reports\"\n description=\"Publish reports once their line items are complete.\"\n >\n <div className=\"mb-4\">\n <FilterTabs options={REPORT_STATUS_OPTIONS} value={status} onChange={setStatus} />\n </div>\n {rows.length === 0 ? (\n <EmptyState\n icon={<FileText size={40} />}\n title=\"No reports found\"\n description={`There are no ${status === 'ALL' ? '' : status.toLowerCase()} reports in this workspace.`}\n />\n ) : (\n <DataTable\n columns={columns}\n rows={rows}\n rowKey={(r) => r.id}\n defaultSort={{ key: 'period', dir: 'desc' }}\n />\n )}\n </Section>\n );\n}\n\n// ============================================================================\n// Root\n// ============================================================================\n\nfunction EcoImpactHubAdminDashboard() {\n const [activeTab, setActiveTab] = useState<AdminTab>('sites');\n\n const tabs = useMemo<TabItem<AdminTab>[]>(\n () => [\n { value: 'sites', label: 'Sites', icon: <MapPin size={18} /> },\n { value: 'sensors', label: 'Sensors', icon: <Radio size={18} /> },\n { value: 'carbon', label: 'Carbon Ledger', icon: <Factory size={18} /> },\n { value: 'reports', label: 'Reports', icon: <FileText size={18} /> },\n ],\n []\n );\n\n return (\n <PageLayout\n title=\"EcoImpactHub Admin\"\n description=\"Site, sensor, carbon-ledger and report governance.\"\n actions={\n <span className=\"inline-flex items-center gap-2 text-sm text-text-secondary\">\n <ShieldCheck size={18} />\n Workspace-scoped\n </span>\n }\n >\n <Tabs items={tabs} value={activeTab} onChange={setActiveTab} />\n <div className=\"mt-6\">\n {activeTab === 'sites' && <SitesPanel />}\n {activeTab === 'sensors' && <SensorsPanel />}\n {activeTab === 'carbon' && <CarbonLedgerPanel />}\n {activeTab === 'reports' && <ReportsPanel />}\n </div>\n </PageLayout>\n );\n}\n\nexport const EcoImpactHubAdminRoot: FC<EcoImpactHubAdminRootProps> = (props) => {\n return (\n <QueryClientProvider client={queryClient}>\n <FeatureFlagProvider\n workspaceId={props.workspaceId ?? null}\n gateway=\"global\"\n defaultEnabled={true}\n >\n {/* Workspace-scoped RBAC so the admin panel's archive/verify/publish\n controls are gated client-side too. Gateway @rbac remains\n authoritative — this is a UX nicety, not a security control. */}\n <PermissionProvider scopeId={props.workspaceId ?? null} gateway=\"workspace\">\n <EcoImpactHubProvider {...props}>\n <EcoImpactHubAdminDashboard />\n </EcoImpactHubProvider>\n </PermissionProvider>\n </FeatureFlagProvider>\n </QueryClientProvider>\n );\n};\n\nexport { EcoImpactHubAdminRoot as AdminRoot };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { DashboardWidgetId, UseDashboardLayoutResult } from '../hooks/useDashboardLayout';
|
|
3
|
+
|
|
4
|
+
interface DashboardCustomizerDialogProps {
|
|
5
|
+
open: boolean;
|
|
6
|
+
onOpenChange: (open: boolean) => void;
|
|
7
|
+
layout: UseDashboardLayoutResult;
|
|
8
|
+
}
|
|
9
|
+
export declare const DashboardCustomizerDialog: FC<DashboardCustomizerDialogProps>;
|
|
10
|
+
export type { DashboardWidgetId };
|
|
11
|
+
//# sourceMappingURL=DashboardCustomizerDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DashboardCustomizerDialog.d.ts","sourceRoot":"","sources":["../../../src/ecoimpacthub/components/DashboardCustomizerDialog.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,KAAK,EAAE,EAAY,MAAM,OAAO,CAAC;AAe1C,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC9B,MAAM,6BAA6B,CAAC;AAErC,UAAU,8BAA8B;IACtC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,MAAM,EAAE,wBAAwB,CAAC;CAClC;AAED,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAwMxE,CAAC;AAEF,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
|