@fonderie/react-admin-screens 1.0.2 → 1.1.0
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/index.cjs +1464 -564
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +1467 -567
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/screens/AdminShell.tsx
|
|
2
2
|
import { ConfigEditorScreen, ConfigListScreen } from "@fonderie/react-config-admin-screens";
|
|
3
3
|
import { TemplateEditorScreen, TemplateListScreen } from "@fonderie/react-courier-admin-screens";
|
|
4
|
-
import { useState as
|
|
4
|
+
import { useEffect, useState as useState6 } from "react";
|
|
5
5
|
|
|
6
6
|
// src/styles.ts
|
|
7
7
|
var t = {
|
|
@@ -23,6 +23,31 @@ var t = {
|
|
|
23
23
|
trackingDisplay: "var(--fonderie-tracking-display,-0.05em)",
|
|
24
24
|
shadowCard: "var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))"
|
|
25
25
|
};
|
|
26
|
+
var tint = (token, pct) => `color-mix(in srgb, ${token} ${pct}%, transparent)`;
|
|
27
|
+
var toneColor = {
|
|
28
|
+
ok: t.accentStrong,
|
|
29
|
+
bad: t.danger,
|
|
30
|
+
// Amber on white fails contrast; mixing in the text colour darkens it in
|
|
31
|
+
// light mode and lightens it in dark, from the same two tokens.
|
|
32
|
+
warn: `color-mix(in srgb, ${t.warning} 70%, ${t.text})`,
|
|
33
|
+
neutral: t.muted,
|
|
34
|
+
info: t.text
|
|
35
|
+
};
|
|
36
|
+
var control = {
|
|
37
|
+
display: "inline-flex",
|
|
38
|
+
alignItems: "center",
|
|
39
|
+
justifyContent: "center",
|
|
40
|
+
gap: 6,
|
|
41
|
+
height: 32,
|
|
42
|
+
boxSizing: "border-box",
|
|
43
|
+
borderRadius: 6,
|
|
44
|
+
padding: "0 12px",
|
|
45
|
+
fontSize: 13,
|
|
46
|
+
fontWeight: 500,
|
|
47
|
+
fontFamily: "inherit",
|
|
48
|
+
lineHeight: 1,
|
|
49
|
+
whiteSpace: "nowrap"
|
|
50
|
+
};
|
|
26
51
|
var styles = {
|
|
27
52
|
shell: {
|
|
28
53
|
display: "flex",
|
|
@@ -31,155 +56,578 @@ var styles = {
|
|
|
31
56
|
color: t.text,
|
|
32
57
|
background: t.bg
|
|
33
58
|
},
|
|
34
|
-
//
|
|
35
|
-
//
|
|
59
|
+
// Sticky, full height, scrolls on its own: the nav never scrolls away with
|
|
60
|
+
// a long table, and the footer (session controls) stays in reach.
|
|
36
61
|
nav: {
|
|
37
|
-
width:
|
|
38
|
-
borderRight: `1px solid ${t.border}`,
|
|
39
|
-
padding: 16,
|
|
62
|
+
width: 248,
|
|
40
63
|
flexShrink: 0,
|
|
41
|
-
|
|
64
|
+
boxSizing: "border-box",
|
|
65
|
+
borderRight: `1px solid ${t.border}`,
|
|
66
|
+
background: t.surface,
|
|
67
|
+
position: "sticky",
|
|
68
|
+
top: 0,
|
|
69
|
+
height: "100vh",
|
|
70
|
+
display: "flex",
|
|
71
|
+
flexDirection: "column"
|
|
72
|
+
},
|
|
73
|
+
navBrand: {
|
|
74
|
+
display: "flex",
|
|
75
|
+
alignItems: "center",
|
|
76
|
+
gap: 10,
|
|
77
|
+
padding: "18px 16px 14px",
|
|
78
|
+
borderBottom: `1px solid ${t.borderLight}`
|
|
79
|
+
},
|
|
80
|
+
navMark: {
|
|
81
|
+
width: 28,
|
|
82
|
+
height: 28,
|
|
83
|
+
borderRadius: 7,
|
|
84
|
+
background: t.text,
|
|
85
|
+
color: t.surface,
|
|
86
|
+
display: "grid",
|
|
87
|
+
placeItems: "center",
|
|
88
|
+
flexShrink: 0
|
|
89
|
+
},
|
|
90
|
+
navBrandTitle: {
|
|
91
|
+
fontSize: 14,
|
|
92
|
+
fontWeight: 600,
|
|
93
|
+
letterSpacing: t.trackingDisplay,
|
|
94
|
+
lineHeight: 1.2,
|
|
95
|
+
overflow: "hidden",
|
|
96
|
+
textOverflow: "ellipsis",
|
|
97
|
+
whiteSpace: "nowrap"
|
|
42
98
|
},
|
|
99
|
+
navScroll: { flex: 1, overflowY: "auto", padding: "8px 10px 16px" },
|
|
43
100
|
navGroup: {
|
|
44
101
|
fontSize: 11,
|
|
45
102
|
textTransform: "uppercase",
|
|
46
103
|
letterSpacing: 0.6,
|
|
47
104
|
color: t.muted,
|
|
48
|
-
margin: "16px
|
|
105
|
+
margin: "16px 8px 4px",
|
|
49
106
|
fontWeight: 600
|
|
50
107
|
},
|
|
51
108
|
navItem: {
|
|
52
|
-
display: "
|
|
109
|
+
display: "flex",
|
|
110
|
+
alignItems: "center",
|
|
111
|
+
gap: 10,
|
|
53
112
|
width: "100%",
|
|
54
113
|
textAlign: "left",
|
|
55
114
|
background: "none",
|
|
56
115
|
border: "none",
|
|
57
|
-
borderRadius:
|
|
58
|
-
padding: "
|
|
116
|
+
borderRadius: 6,
|
|
117
|
+
padding: "7px 8px",
|
|
59
118
|
cursor: "pointer",
|
|
60
|
-
fontSize:
|
|
61
|
-
|
|
62
|
-
|
|
119
|
+
fontSize: 13.5,
|
|
120
|
+
fontWeight: 500,
|
|
121
|
+
color: t.muted,
|
|
122
|
+
fontFamily: "inherit",
|
|
123
|
+
position: "relative"
|
|
124
|
+
},
|
|
125
|
+
navItemActive: { background: tint(t.accent, 12), color: t.text, fontWeight: 600 },
|
|
126
|
+
navIconActive: { color: t.accentStrong },
|
|
127
|
+
navFooter: {
|
|
128
|
+
borderTop: `1px solid ${t.borderLight}`,
|
|
129
|
+
padding: 12,
|
|
130
|
+
display: "flex",
|
|
131
|
+
flexDirection: "column",
|
|
132
|
+
gap: 10
|
|
133
|
+
},
|
|
134
|
+
// Phone layout: a top bar with the menu button replaces the sidebar, which
|
|
135
|
+
// opens as a drawer over the content.
|
|
136
|
+
topbar: {
|
|
137
|
+
position: "sticky",
|
|
138
|
+
top: 0,
|
|
139
|
+
zIndex: 20,
|
|
140
|
+
display: "flex",
|
|
141
|
+
alignItems: "center",
|
|
142
|
+
gap: 10,
|
|
143
|
+
padding: "10px 16px",
|
|
144
|
+
background: t.surface,
|
|
145
|
+
borderBottom: `1px solid ${t.border}`
|
|
146
|
+
},
|
|
147
|
+
drawer: {
|
|
148
|
+
position: "fixed",
|
|
149
|
+
inset: 0,
|
|
150
|
+
zIndex: 30,
|
|
151
|
+
display: "flex"
|
|
152
|
+
},
|
|
153
|
+
scrim: { flex: 1, background: "rgba(0,0,0,.35)" },
|
|
154
|
+
main: { flex: 1, minWidth: 0 },
|
|
155
|
+
container: { padding: "32px 40px 64px", maxWidth: 1160, boxSizing: "border-box" },
|
|
156
|
+
// ── page header ──
|
|
157
|
+
header: {
|
|
158
|
+
display: "flex",
|
|
159
|
+
alignItems: "flex-start",
|
|
160
|
+
justifyContent: "space-between",
|
|
161
|
+
gap: 16,
|
|
162
|
+
marginBottom: 24,
|
|
163
|
+
flexWrap: "wrap"
|
|
63
164
|
},
|
|
64
|
-
navItemActive: { background: t.surfaceAlt, fontWeight: 600, color: t.accentStrong },
|
|
65
|
-
main: { flex: 1, padding: 24, maxWidth: 960 },
|
|
66
|
-
container: { padding: 24, maxWidth: 960 },
|
|
67
165
|
title: {
|
|
68
|
-
fontSize:
|
|
166
|
+
fontSize: 22,
|
|
69
167
|
fontWeight: 600,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
168
|
+
margin: 0,
|
|
169
|
+
letterSpacing: t.trackingDisplay,
|
|
170
|
+
lineHeight: 1.25
|
|
73
171
|
},
|
|
172
|
+
lead: { color: t.muted, fontSize: 13.5, margin: "4px 0 0", lineHeight: 1.5 },
|
|
173
|
+
actions: { display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" },
|
|
74
174
|
subtitle: {
|
|
75
175
|
fontSize: 15,
|
|
76
176
|
fontWeight: 600,
|
|
77
|
-
marginTop:
|
|
78
|
-
marginBottom:
|
|
79
|
-
letterSpacing: t.trackingDisplay
|
|
177
|
+
marginTop: 32,
|
|
178
|
+
marginBottom: 10,
|
|
179
|
+
letterSpacing: t.trackingDisplay,
|
|
180
|
+
display: "flex",
|
|
181
|
+
alignItems: "center",
|
|
182
|
+
gap: 8
|
|
183
|
+
},
|
|
184
|
+
// ── feedback ──
|
|
185
|
+
status: { padding: "24px 0", color: t.muted, fontSize: 13.5 },
|
|
186
|
+
error: {
|
|
187
|
+
color: t.danger,
|
|
188
|
+
background: tint(t.danger, 8),
|
|
189
|
+
border: `1px solid ${tint(t.danger, 25)}`,
|
|
190
|
+
borderRadius: t.radiusLg,
|
|
191
|
+
padding: "10px 14px",
|
|
192
|
+
marginBottom: 16,
|
|
193
|
+
fontSize: 13.5
|
|
194
|
+
},
|
|
195
|
+
notice: {
|
|
196
|
+
color: t.text,
|
|
197
|
+
background: tint(t.warning, 10),
|
|
198
|
+
border: `1px solid ${tint(t.warning, 35)}`,
|
|
199
|
+
borderRadius: t.radiusLg,
|
|
200
|
+
padding: "10px 14px",
|
|
201
|
+
marginBottom: 16,
|
|
202
|
+
fontSize: 13.5
|
|
80
203
|
},
|
|
81
|
-
status: { padding: 12, color: t.muted },
|
|
82
|
-
error: { color: t.danger, marginBottom: 12, fontSize: 14 },
|
|
83
204
|
ok: { color: t.accentStrong, fontWeight: 600 },
|
|
84
205
|
bad: { color: t.danger, fontWeight: 600 },
|
|
85
206
|
advice: { color: t.warning },
|
|
86
207
|
muted: { color: t.muted, fontSize: 13 },
|
|
87
|
-
mono: { fontFamily: t.mono, fontSize:
|
|
88
|
-
|
|
208
|
+
mono: { fontFamily: t.mono, fontSize: 12.5 },
|
|
209
|
+
code: {
|
|
210
|
+
fontFamily: t.mono,
|
|
211
|
+
fontSize: 12,
|
|
212
|
+
background: t.surfaceAlt,
|
|
213
|
+
border: `1px solid ${t.borderLight}`,
|
|
214
|
+
borderRadius: 4,
|
|
215
|
+
padding: "1px 5px"
|
|
216
|
+
},
|
|
217
|
+
// ── surfaces ──
|
|
218
|
+
// Tables and lists are cards themselves, so every screen gets the framed,
|
|
219
|
+
// rounded look without wrapping each one. The last row's rule is removed in
|
|
220
|
+
// the shell stylesheet (a pseudo-selector); embedded without the shell it
|
|
221
|
+
// simply doubles against the frame.
|
|
222
|
+
table: {
|
|
223
|
+
width: "100%",
|
|
224
|
+
borderCollapse: "separate",
|
|
225
|
+
borderSpacing: 0,
|
|
226
|
+
fontSize: 13.5,
|
|
227
|
+
background: t.surface,
|
|
228
|
+
border: `1px solid ${t.border}`,
|
|
229
|
+
borderRadius: t.radiusLg,
|
|
230
|
+
overflow: "hidden",
|
|
231
|
+
boxShadow: t.shadowCard
|
|
232
|
+
},
|
|
89
233
|
th: {
|
|
90
234
|
textAlign: "left",
|
|
91
235
|
borderBottom: `1px solid ${t.border}`,
|
|
92
|
-
padding: "
|
|
236
|
+
padding: "9px 14px",
|
|
237
|
+
fontWeight: 600,
|
|
238
|
+
fontSize: 11.5,
|
|
239
|
+
textTransform: "uppercase",
|
|
240
|
+
letterSpacing: 0.4,
|
|
241
|
+
color: t.muted,
|
|
242
|
+
background: t.surfaceAlt,
|
|
243
|
+
whiteSpace: "nowrap"
|
|
244
|
+
},
|
|
245
|
+
td: {
|
|
246
|
+
borderBottom: `1px solid ${t.borderLight}`,
|
|
247
|
+
padding: "11px 14px",
|
|
248
|
+
verticalAlign: "top"
|
|
249
|
+
},
|
|
250
|
+
list: {
|
|
251
|
+
listStyle: "none",
|
|
252
|
+
padding: 0,
|
|
253
|
+
margin: 0,
|
|
254
|
+
background: t.surface,
|
|
255
|
+
border: `1px solid ${t.border}`,
|
|
256
|
+
borderRadius: t.radiusLg,
|
|
257
|
+
overflow: "hidden",
|
|
258
|
+
boxShadow: t.shadowCard
|
|
259
|
+
},
|
|
260
|
+
row: { borderBottom: `1px solid ${t.borderLight}`, padding: "12px 16px" },
|
|
261
|
+
card: {
|
|
262
|
+
background: t.surface,
|
|
263
|
+
border: `1px solid ${t.border}`,
|
|
264
|
+
borderRadius: t.radiusLg,
|
|
265
|
+
padding: 16,
|
|
266
|
+
boxShadow: t.shadowCard
|
|
267
|
+
},
|
|
268
|
+
grid: {
|
|
269
|
+
display: "grid",
|
|
270
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))",
|
|
271
|
+
gap: 12,
|
|
272
|
+
marginBottom: 24
|
|
273
|
+
},
|
|
274
|
+
statLabel: { fontSize: 12, color: t.muted, fontWeight: 500 },
|
|
275
|
+
statValue: {
|
|
276
|
+
fontSize: 26,
|
|
93
277
|
fontWeight: 600,
|
|
94
|
-
|
|
278
|
+
letterSpacing: t.trackingDisplay,
|
|
279
|
+
lineHeight: 1.2,
|
|
280
|
+
marginTop: 6
|
|
281
|
+
},
|
|
282
|
+
statHint: { fontSize: 12, color: t.muted, marginTop: 2 },
|
|
283
|
+
empty: {
|
|
284
|
+
background: t.surface,
|
|
285
|
+
border: `1px dashed ${t.border}`,
|
|
286
|
+
borderRadius: t.radiusLg,
|
|
287
|
+
padding: "40px 24px",
|
|
288
|
+
textAlign: "center",
|
|
289
|
+
color: t.muted,
|
|
290
|
+
fontSize: 13.5
|
|
291
|
+
},
|
|
292
|
+
emptyTitle: { color: t.text, fontWeight: 600, fontSize: 14.5, margin: "10px 0 4px" },
|
|
293
|
+
dl: { display: "grid", gridTemplateColumns: "160px 1fr", margin: 0 },
|
|
294
|
+
dt: {
|
|
295
|
+
color: t.muted,
|
|
296
|
+
fontSize: 13,
|
|
297
|
+
padding: "10px 16px",
|
|
298
|
+
borderBottom: `1px solid ${t.borderLight}`
|
|
299
|
+
},
|
|
300
|
+
dd: {
|
|
301
|
+
margin: 0,
|
|
302
|
+
padding: "10px 16px",
|
|
303
|
+
borderBottom: `1px solid ${t.borderLight}`,
|
|
304
|
+
fontSize: 13.5,
|
|
305
|
+
minWidth: 0
|
|
95
306
|
},
|
|
96
|
-
td: { borderBottom: `1px solid ${t.borderLight}`, padding: "6px 8px", verticalAlign: "top" },
|
|
97
|
-
list: { listStyle: "none", padding: 0, margin: 0 },
|
|
98
|
-
row: { borderBottom: `1px solid ${t.borderLight}`, padding: "8px 0" },
|
|
99
307
|
badge: {
|
|
100
|
-
display: "inline-
|
|
308
|
+
display: "inline-flex",
|
|
309
|
+
alignItems: "center",
|
|
310
|
+
gap: 5,
|
|
101
311
|
borderRadius: 999,
|
|
102
|
-
padding: "
|
|
103
|
-
fontSize:
|
|
312
|
+
padding: "2px 8px",
|
|
313
|
+
fontSize: 11.5,
|
|
314
|
+
fontWeight: 500,
|
|
315
|
+
lineHeight: 1.5,
|
|
104
316
|
background: t.surfaceAlt,
|
|
105
317
|
border: `1px solid ${t.border}`,
|
|
106
|
-
color: t.muted
|
|
318
|
+
color: t.muted,
|
|
319
|
+
whiteSpace: "nowrap"
|
|
107
320
|
},
|
|
321
|
+
pill: {
|
|
322
|
+
display: "inline-flex",
|
|
323
|
+
alignItems: "center",
|
|
324
|
+
gap: 6,
|
|
325
|
+
borderRadius: 999,
|
|
326
|
+
padding: "2px 9px 2px 8px",
|
|
327
|
+
fontSize: 12,
|
|
328
|
+
fontWeight: 600,
|
|
329
|
+
lineHeight: 1.5,
|
|
330
|
+
whiteSpace: "nowrap",
|
|
331
|
+
verticalAlign: "baseline"
|
|
332
|
+
},
|
|
333
|
+
dot: { width: 6, height: 6, borderRadius: 999, flexShrink: 0, background: "currentColor" },
|
|
334
|
+
// ── controls ──
|
|
108
335
|
button: {
|
|
336
|
+
...control,
|
|
109
337
|
background: t.surface,
|
|
110
338
|
border: `1px solid ${t.border}`,
|
|
111
|
-
borderRadius: t.radius,
|
|
112
|
-
padding: "4px 10px",
|
|
113
|
-
cursor: "pointer",
|
|
114
|
-
fontSize: 13,
|
|
115
339
|
color: t.text,
|
|
116
|
-
|
|
340
|
+
cursor: "pointer",
|
|
117
341
|
boxShadow: t.shadowCard
|
|
118
342
|
},
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
343
|
+
buttonPrimary: {
|
|
344
|
+
...control,
|
|
345
|
+
background: t.text,
|
|
346
|
+
border: `1px solid ${t.text}`,
|
|
347
|
+
color: t.surface,
|
|
348
|
+
cursor: "pointer"
|
|
349
|
+
},
|
|
350
|
+
buttonDanger: {
|
|
351
|
+
...control,
|
|
123
352
|
background: t.surface,
|
|
353
|
+
border: `1px solid ${tint(t.danger, 40)}`,
|
|
354
|
+
color: t.danger,
|
|
355
|
+
cursor: "pointer"
|
|
356
|
+
},
|
|
357
|
+
buttonGhost: {
|
|
358
|
+
...control,
|
|
359
|
+
background: "none",
|
|
360
|
+
border: "1px solid transparent",
|
|
361
|
+
color: t.muted,
|
|
362
|
+
cursor: "pointer",
|
|
363
|
+
padding: "0 8px"
|
|
364
|
+
},
|
|
365
|
+
link: {
|
|
366
|
+
background: "none",
|
|
367
|
+
border: "none",
|
|
368
|
+
padding: 0,
|
|
369
|
+
color: t.text,
|
|
370
|
+
fontFamily: "inherit",
|
|
371
|
+
fontSize: "inherit",
|
|
372
|
+
fontWeight: 500,
|
|
373
|
+
cursor: "pointer",
|
|
374
|
+
textAlign: "left"
|
|
375
|
+
},
|
|
376
|
+
input: {
|
|
377
|
+
height: 32,
|
|
378
|
+
boxSizing: "border-box",
|
|
124
379
|
border: `1px solid ${t.border}`,
|
|
125
|
-
borderRadius:
|
|
126
|
-
padding:
|
|
127
|
-
|
|
380
|
+
borderRadius: 6,
|
|
381
|
+
padding: "0 10px",
|
|
382
|
+
fontSize: 13.5,
|
|
383
|
+
fontFamily: "inherit",
|
|
384
|
+
background: t.surface,
|
|
385
|
+
color: t.text,
|
|
386
|
+
minWidth: 0
|
|
128
387
|
},
|
|
388
|
+
toolbar: { display: "flex", gap: 8, alignItems: "center", marginBottom: 16, flexWrap: "wrap" },
|
|
129
389
|
accent: { color: t.accent }
|
|
130
390
|
};
|
|
131
391
|
|
|
392
|
+
// src/icons.ts
|
|
393
|
+
var ICONS = {
|
|
394
|
+
attention: ["M22 12h-4l-3 9L9 3l-3 9H2"],
|
|
395
|
+
modules: [
|
|
396
|
+
"M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z",
|
|
397
|
+
"M3.3 7 12 12l8.7-5",
|
|
398
|
+
"M12 22V12"
|
|
399
|
+
],
|
|
400
|
+
environment: [
|
|
401
|
+
"M4 21v-7",
|
|
402
|
+
"M4 10V3",
|
|
403
|
+
"M12 21v-9",
|
|
404
|
+
"M12 8V3",
|
|
405
|
+
"M20 21v-5",
|
|
406
|
+
"M20 12V3",
|
|
407
|
+
"M1 14h6",
|
|
408
|
+
"M9 8h6",
|
|
409
|
+
"M17 16h6"
|
|
410
|
+
],
|
|
411
|
+
doctor: [
|
|
412
|
+
"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"
|
|
413
|
+
],
|
|
414
|
+
routes: [
|
|
415
|
+
"M6 3v12",
|
|
416
|
+
"M18 9a3 3 0 1 0 0-6 3 3 0 0 0 0 6z",
|
|
417
|
+
"M6 21a3 3 0 1 0 0-6 3 3 0 0 0 0 6z",
|
|
418
|
+
"M18 9a9 9 0 0 1-9 9"
|
|
419
|
+
],
|
|
420
|
+
users: [
|
|
421
|
+
"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",
|
|
422
|
+
"M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z",
|
|
423
|
+
"M22 21v-2a4 4 0 0 0-3-3.87",
|
|
424
|
+
"M16 3.13a4 4 0 0 1 0 7.75"
|
|
425
|
+
],
|
|
426
|
+
catalog: [
|
|
427
|
+
"M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z",
|
|
428
|
+
"M7.5 8a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1z"
|
|
429
|
+
],
|
|
430
|
+
subscriber: ["M2 7h20v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2z", "M2 11h20", "M6 15h4"],
|
|
431
|
+
settings: [
|
|
432
|
+
"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",
|
|
433
|
+
"M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z"
|
|
434
|
+
],
|
|
435
|
+
templates: [
|
|
436
|
+
"M22 7l-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7",
|
|
437
|
+
"M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z"
|
|
438
|
+
],
|
|
439
|
+
audit: ["M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z", "M9 12l2 2 4-4"],
|
|
440
|
+
log: ["M12 8v4l3 3", "M3.05 11a9 9 0 1 1 .5 4m-.5 5v-5h5"],
|
|
441
|
+
tokens: [
|
|
442
|
+
"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",
|
|
443
|
+
"M16.5 8a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1z"
|
|
444
|
+
],
|
|
445
|
+
migrations: [
|
|
446
|
+
"M12 22c4.97 0 9-1.79 9-4V6",
|
|
447
|
+
"M3 6v12c0 2.21 4.03 4 9 4",
|
|
448
|
+
"M12 10c4.97 0 9-1.79 9-4s-4.03-4-9-4-9 1.79-9 4 4.03 4 9 4z",
|
|
449
|
+
"M3 12c0 2.21 4.03 4 9 4s9-1.79 9-4"
|
|
450
|
+
],
|
|
451
|
+
menu: ["M4 6h16", "M4 12h16", "M4 18h16"],
|
|
452
|
+
close: ["M18 6 6 18", "m6 6 12 12"],
|
|
453
|
+
refresh: [
|
|
454
|
+
"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",
|
|
455
|
+
"M21 3v5h-5",
|
|
456
|
+
"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",
|
|
457
|
+
"M8 16H3v5"
|
|
458
|
+
],
|
|
459
|
+
check: ["M20 6 9 17l-5-5"],
|
|
460
|
+
alert: [
|
|
461
|
+
"M12 9v4",
|
|
462
|
+
"M12 17h.01",
|
|
463
|
+
"M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"
|
|
464
|
+
],
|
|
465
|
+
search: ["M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z", "m21 21-4.3-4.3"],
|
|
466
|
+
back: ["m12 19-7-7 7-7", "M19 12H5"],
|
|
467
|
+
logout: ["M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4", "m16 17 5-5-5-5", "M21 12H9"],
|
|
468
|
+
lock: [
|
|
469
|
+
"M5 11h14a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2z",
|
|
470
|
+
"M7 11V7a5 5 0 0 1 10 0v4"
|
|
471
|
+
],
|
|
472
|
+
plus: ["M12 5v14", "M5 12h14"],
|
|
473
|
+
mark: [
|
|
474
|
+
"M4 3h5a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z",
|
|
475
|
+
"M15 3h5a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z",
|
|
476
|
+
"M15 14h5a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z",
|
|
477
|
+
"M4 14h5a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-5a1 1 0 0 1 1-1z"
|
|
478
|
+
]
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
// src/ui.tsx
|
|
482
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
483
|
+
function Icon({
|
|
484
|
+
name,
|
|
485
|
+
size = 16,
|
|
486
|
+
style
|
|
487
|
+
}) {
|
|
488
|
+
return /* @__PURE__ */ jsx(
|
|
489
|
+
"svg",
|
|
490
|
+
{
|
|
491
|
+
width: size,
|
|
492
|
+
height: size,
|
|
493
|
+
viewBox: "0 0 24 24",
|
|
494
|
+
fill: "none",
|
|
495
|
+
stroke: "currentColor",
|
|
496
|
+
strokeWidth: 2,
|
|
497
|
+
strokeLinecap: "round",
|
|
498
|
+
strokeLinejoin: "round",
|
|
499
|
+
"aria-hidden": "true",
|
|
500
|
+
style: { flexShrink: 0, ...style },
|
|
501
|
+
children: ICONS[name].map((d) => /* @__PURE__ */ jsx("path", { d }, d))
|
|
502
|
+
}
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
function PageHeader({
|
|
506
|
+
title,
|
|
507
|
+
lead,
|
|
508
|
+
actions
|
|
509
|
+
}) {
|
|
510
|
+
return /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
|
|
511
|
+
/* @__PURE__ */ jsxs("div", { style: { minWidth: 0 }, children: [
|
|
512
|
+
/* @__PURE__ */ jsx("h1", { style: styles.title, children: title }),
|
|
513
|
+
lead ? /* @__PURE__ */ jsx("p", { style: styles.lead, children: lead }) : null
|
|
514
|
+
] }),
|
|
515
|
+
actions ? /* @__PURE__ */ jsx("div", { style: styles.actions, children: actions }) : null
|
|
516
|
+
] });
|
|
517
|
+
}
|
|
518
|
+
function Pill({
|
|
519
|
+
tone,
|
|
520
|
+
children,
|
|
521
|
+
dot = true
|
|
522
|
+
}) {
|
|
523
|
+
const color = toneColor[tone];
|
|
524
|
+
return /* @__PURE__ */ jsxs("span", { style: { ...styles.pill, color, background: tint(color, tone === "neutral" ? 10 : 13) }, children: [
|
|
525
|
+
dot ? /* @__PURE__ */ jsx("span", { style: styles.dot }) : null,
|
|
526
|
+
children
|
|
527
|
+
] });
|
|
528
|
+
}
|
|
529
|
+
function Stat({
|
|
530
|
+
label,
|
|
531
|
+
value,
|
|
532
|
+
hint,
|
|
533
|
+
tone
|
|
534
|
+
}) {
|
|
535
|
+
return /* @__PURE__ */ jsxs("div", { style: styles.card, children: [
|
|
536
|
+
/* @__PURE__ */ jsx("div", { style: styles.statLabel, children: label }),
|
|
537
|
+
/* @__PURE__ */ jsx("div", { style: { ...styles.statValue, ...tone ? { color: toneColor[tone] } : {} }, children: value }),
|
|
538
|
+
hint ? /* @__PURE__ */ jsx("div", { style: styles.statHint, children: hint }) : null
|
|
539
|
+
] });
|
|
540
|
+
}
|
|
541
|
+
function Empty({
|
|
542
|
+
icon = "check",
|
|
543
|
+
title,
|
|
544
|
+
children
|
|
545
|
+
}) {
|
|
546
|
+
return /* @__PURE__ */ jsxs("div", { style: styles.empty, children: [
|
|
547
|
+
/* @__PURE__ */ jsx(Icon, { name: icon, size: 22 }),
|
|
548
|
+
/* @__PURE__ */ jsx("div", { style: styles.emptyTitle, children: title }),
|
|
549
|
+
children ? /* @__PURE__ */ jsx("div", { children }) : null
|
|
550
|
+
] });
|
|
551
|
+
}
|
|
552
|
+
function RefreshButton({
|
|
553
|
+
onClick,
|
|
554
|
+
busy,
|
|
555
|
+
label = "Refresh"
|
|
556
|
+
}) {
|
|
557
|
+
return /* @__PURE__ */ jsxs("button", { type: "button", style: styles.button, onClick, disabled: busy, children: [
|
|
558
|
+
/* @__PURE__ */ jsx(Icon, { name: "refresh", size: 14 }),
|
|
559
|
+
busy ? "Working\u2026" : label
|
|
560
|
+
] });
|
|
561
|
+
}
|
|
562
|
+
function MethodChip({ method }) {
|
|
563
|
+
const tone = method === "GET" ? "ok" : method === "DELETE" ? "bad" : method === "POST" ? "info" : "warn";
|
|
564
|
+
const color = toneColor[tone];
|
|
565
|
+
return /* @__PURE__ */ jsx(
|
|
566
|
+
"span",
|
|
567
|
+
{
|
|
568
|
+
style: {
|
|
569
|
+
...styles.mono,
|
|
570
|
+
fontSize: 11,
|
|
571
|
+
fontWeight: 700,
|
|
572
|
+
color,
|
|
573
|
+
background: tint(color, 12),
|
|
574
|
+
borderRadius: 4,
|
|
575
|
+
padding: "2px 6px",
|
|
576
|
+
display: "inline-block",
|
|
577
|
+
minWidth: 44,
|
|
578
|
+
textAlign: "center"
|
|
579
|
+
},
|
|
580
|
+
children: method
|
|
581
|
+
}
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
|
|
132
585
|
// src/screens/AdminLogScreen.tsx
|
|
133
586
|
import { useAdminLog } from "@fonderie/react-admin";
|
|
134
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
587
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
135
588
|
function AdminLogScreen({ client, pageSize = 50 }) {
|
|
136
589
|
const { entries, hasMore, isLoading, error, refresh, loadMore } = useAdminLog(client, {
|
|
137
590
|
limit: pageSize
|
|
138
591
|
});
|
|
139
|
-
return /* @__PURE__ */
|
|
140
|
-
/* @__PURE__ */
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
"
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
/* @__PURE__ */ jsx("th", { style: styles.th, children: "When" }),
|
|
157
|
-
/* @__PURE__ */ jsx("th", { style: styles.th, children: "Actor" }),
|
|
158
|
-
/* @__PURE__ */ jsx("th", { style: styles.th, children: "Request" }),
|
|
159
|
-
/* @__PURE__ */ jsx("th", { style: styles.th, children: "Status" }),
|
|
160
|
-
/* @__PURE__ */ jsx("th", { style: styles.th, children: "Module" })
|
|
592
|
+
return /* @__PURE__ */ jsxs2("div", { style: styles.container, children: [
|
|
593
|
+
/* @__PURE__ */ jsx2(
|
|
594
|
+
PageHeader,
|
|
595
|
+
{
|
|
596
|
+
title: "Admin log",
|
|
597
|
+
lead: "Every request made through this surface, newest first \u2014 refused ones included.",
|
|
598
|
+
actions: /* @__PURE__ */ jsx2(RefreshButton, { onClick: () => void refresh(), busy: isLoading })
|
|
599
|
+
}
|
|
600
|
+
),
|
|
601
|
+
error ? /* @__PURE__ */ jsx2("p", { style: styles.error, role: "alert", children: error.status === 404 ? "The admin log is off \u2014 give AdminModule a store." : error.explanation }) : entries.length === 0 && !isLoading ? /* @__PURE__ */ jsx2(Empty, { icon: "log", title: "No requests yet" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
602
|
+
/* @__PURE__ */ jsxs2("table", { style: styles.table, children: [
|
|
603
|
+
/* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
|
|
604
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "When" }),
|
|
605
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "Actor" }),
|
|
606
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "Request" }),
|
|
607
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "Status" }),
|
|
608
|
+
/* @__PURE__ */ jsx2("th", { style: styles.th, children: "Module" })
|
|
161
609
|
] }) }),
|
|
162
|
-
/* @__PURE__ */
|
|
163
|
-
/* @__PURE__ */
|
|
164
|
-
/* @__PURE__ */
|
|
165
|
-
/* @__PURE__ */
|
|
166
|
-
e.method,
|
|
610
|
+
/* @__PURE__ */ jsx2("tbody", { children: entries.map((e) => /* @__PURE__ */ jsxs2("tr", { children: [
|
|
611
|
+
/* @__PURE__ */ jsx2("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children: new Date(e.at).toLocaleString() }),
|
|
612
|
+
/* @__PURE__ */ jsx2("td", { style: styles.td, children: e.actor }),
|
|
613
|
+
/* @__PURE__ */ jsxs2("td", { style: styles.td, children: [
|
|
614
|
+
/* @__PURE__ */ jsx2(MethodChip, { method: e.method }),
|
|
167
615
|
" ",
|
|
168
|
-
e.path
|
|
616
|
+
/* @__PURE__ */ jsx2("span", { style: { ...styles.mono, wordBreak: "break-all" }, children: e.path })
|
|
169
617
|
] }),
|
|
170
|
-
/* @__PURE__ */
|
|
171
|
-
/* @__PURE__ */
|
|
618
|
+
/* @__PURE__ */ jsxs2("td", { style: { ...styles.td, whiteSpace: "nowrap" }, children: [
|
|
619
|
+
/* @__PURE__ */ jsx2(Pill, { tone: e.status >= 500 ? "bad" : e.status >= 400 ? "warn" : "ok", children: e.status }),
|
|
172
620
|
" ",
|
|
173
|
-
/* @__PURE__ */
|
|
621
|
+
/* @__PURE__ */ jsxs2("span", { style: styles.muted, children: [
|
|
174
622
|
e.durationMs,
|
|
175
623
|
" ms"
|
|
176
624
|
] })
|
|
177
625
|
] }),
|
|
178
|
-
/* @__PURE__ */
|
|
626
|
+
/* @__PURE__ */ jsx2("td", { style: { ...styles.td, ...styles.muted }, children: e.module })
|
|
179
627
|
] }, e.id)) })
|
|
180
628
|
] }),
|
|
181
|
-
isLoading ? /* @__PURE__ */
|
|
182
|
-
hasMore && !isLoading ? /* @__PURE__ */
|
|
629
|
+
isLoading ? /* @__PURE__ */ jsx2("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
630
|
+
hasMore && !isLoading ? /* @__PURE__ */ jsx2(
|
|
183
631
|
"button",
|
|
184
632
|
{
|
|
185
633
|
type: "button",
|
|
@@ -193,180 +641,373 @@ function AdminLogScreen({ client, pageSize = 50 }) {
|
|
|
193
641
|
}
|
|
194
642
|
|
|
195
643
|
// src/screens/AttentionScreen.tsx
|
|
196
|
-
import { useAttention } from "@fonderie/react-admin";
|
|
197
|
-
import { jsx as
|
|
644
|
+
import { useAttention, useManifest } from "@fonderie/react-admin";
|
|
645
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
198
646
|
function AttentionScreen({ client }) {
|
|
199
647
|
const { attention, isLoading, error, refresh } = useAttention(client);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
648
|
+
const { manifest } = useManifest(client);
|
|
649
|
+
const errors = attention?.items.filter((i) => i.severity === "error") ?? [];
|
|
650
|
+
const advice = attention?.items.filter((i) => i.severity !== "error") ?? [];
|
|
651
|
+
const ready = manifest?.modules.filter((m) => m.readiness.ok).length ?? 0;
|
|
652
|
+
const total = manifest?.modules.length ?? 0;
|
|
653
|
+
return /* @__PURE__ */ jsxs3("div", { style: styles.container, children: [
|
|
654
|
+
/* @__PURE__ */ jsx3(
|
|
655
|
+
PageHeader,
|
|
656
|
+
{
|
|
657
|
+
title: "Attention",
|
|
658
|
+
lead: attention ? `What needs you on this deployment \xB7 checked ${new Date(attention.generatedAt).toLocaleTimeString()}` : "What needs you on this deployment",
|
|
659
|
+
actions: /* @__PURE__ */ jsx3(RefreshButton, { onClick: () => void refresh(), busy: isLoading })
|
|
660
|
+
}
|
|
661
|
+
),
|
|
662
|
+
error ? /* @__PURE__ */ jsx3("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
663
|
+
/* @__PURE__ */ jsxs3("div", { style: styles.grid, children: [
|
|
664
|
+
/* @__PURE__ */ jsx3(
|
|
665
|
+
Stat,
|
|
205
666
|
{
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
667
|
+
label: "Needs action",
|
|
668
|
+
value: attention ? errors.length : "\u2014",
|
|
669
|
+
tone: errors.length ? "bad" : attention ? "ok" : void 0,
|
|
670
|
+
hint: "errors to fix"
|
|
671
|
+
}
|
|
672
|
+
),
|
|
673
|
+
/* @__PURE__ */ jsx3(
|
|
674
|
+
Stat,
|
|
675
|
+
{
|
|
676
|
+
label: "Advice",
|
|
677
|
+
value: attention ? advice.length : "\u2014",
|
|
678
|
+
tone: advice.length ? "warn" : void 0,
|
|
679
|
+
hint: "worth a look"
|
|
680
|
+
}
|
|
681
|
+
),
|
|
682
|
+
/* @__PURE__ */ jsx3(
|
|
683
|
+
Stat,
|
|
684
|
+
{
|
|
685
|
+
label: "Modules ready",
|
|
686
|
+
value: manifest ? `${ready}/${total}` : "\u2014",
|
|
687
|
+
tone: manifest && ready < total ? "warn" : manifest ? "ok" : void 0,
|
|
688
|
+
hint: manifest ? `admin ${manifest.admin.version}` : void 0
|
|
689
|
+
}
|
|
690
|
+
),
|
|
691
|
+
/* @__PURE__ */ jsx3(
|
|
692
|
+
Stat,
|
|
693
|
+
{
|
|
694
|
+
label: "Routes",
|
|
695
|
+
value: manifest ? manifest.routes.length : "\u2014",
|
|
696
|
+
hint: manifest ? manifest.env : void 0
|
|
211
697
|
}
|
|
212
698
|
)
|
|
213
699
|
] }),
|
|
214
|
-
isLoading && !attention ? /* @__PURE__ */
|
|
215
|
-
"
|
|
700
|
+
isLoading && !attention ? /* @__PURE__ */ jsx3("p", { style: styles.status, children: "Running the checks\u2026" }) : attention && attention.items.length === 0 ? /* @__PURE__ */ jsxs3(Empty, { title: "Nothing needs you", children: [
|
|
701
|
+
"Every check passes. Checked ",
|
|
216
702
|
new Date(attention.generatedAt).toLocaleString(),
|
|
217
703
|
"."
|
|
218
|
-
] }) : /* @__PURE__ */
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
704
|
+
] }) : /* @__PURE__ */ jsx3("ul", { style: styles.list, children: [...errors, ...advice].map((item) => /* @__PURE__ */ jsxs3(
|
|
705
|
+
"li",
|
|
706
|
+
{
|
|
707
|
+
style: { ...styles.row, display: "flex", gap: 12, alignItems: "flex-start" },
|
|
708
|
+
children: [
|
|
709
|
+
/* @__PURE__ */ jsx3(
|
|
710
|
+
Icon,
|
|
711
|
+
{
|
|
712
|
+
name: "alert",
|
|
713
|
+
size: 16,
|
|
714
|
+
style: {
|
|
715
|
+
marginTop: 3,
|
|
716
|
+
color: item.severity === "error" ? "var(--fonderie-danger,#e00)" : "var(--fonderie-warning,#f5a623)"
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
),
|
|
720
|
+
/* @__PURE__ */ jsxs3("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
721
|
+
/* @__PURE__ */ jsxs3(
|
|
722
|
+
"div",
|
|
723
|
+
{
|
|
724
|
+
style: {
|
|
725
|
+
display: "flex",
|
|
726
|
+
gap: 8,
|
|
727
|
+
alignItems: "center",
|
|
728
|
+
flexWrap: "wrap",
|
|
729
|
+
marginBottom: 2
|
|
730
|
+
},
|
|
731
|
+
children: [
|
|
732
|
+
/* @__PURE__ */ jsx3(Pill, { tone: item.severity === "error" ? "bad" : "warn", children: item.severity === "error" ? "error" : "advice" }),
|
|
733
|
+
/* @__PURE__ */ jsx3("span", { style: styles.mono, children: item.source })
|
|
734
|
+
]
|
|
735
|
+
}
|
|
736
|
+
),
|
|
737
|
+
/* @__PURE__ */ jsx3("div", { style: { lineHeight: 1.55 }, children: item.message })
|
|
738
|
+
] })
|
|
739
|
+
]
|
|
740
|
+
},
|
|
741
|
+
`${item.source}:${item.message}`
|
|
742
|
+
)) })
|
|
225
743
|
] });
|
|
226
744
|
}
|
|
227
745
|
|
|
228
746
|
// src/screens/EnvironmentScreen.tsx
|
|
229
747
|
import { useAdminEnvironment } from "@fonderie/react-admin";
|
|
230
|
-
import { Fragment as Fragment2, jsx as
|
|
748
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
231
749
|
function EnvironmentScreen({ client }) {
|
|
232
750
|
const { report, isLoading, error } = useAdminEnvironment(client);
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
" ",
|
|
240
|
-
|
|
751
|
+
const missing = report?.env.filter((e) => !e.set).length ?? 0;
|
|
752
|
+
return /* @__PURE__ */ jsxs4("div", { style: styles.container, children: [
|
|
753
|
+
/* @__PURE__ */ jsx4(
|
|
754
|
+
PageHeader,
|
|
755
|
+
{
|
|
756
|
+
title: "Environment",
|
|
757
|
+
lead: "Whether each module is configured and each variable the app reads is set. Values are never shown.",
|
|
758
|
+
actions: report && report.env.length > 0 ? /* @__PURE__ */ jsx4(Pill, { tone: missing ? "bad" : "ok", children: missing ? `${missing} missing` : "all set" }) : null
|
|
759
|
+
}
|
|
760
|
+
),
|
|
761
|
+
isLoading ? /* @__PURE__ */ jsx4("p", { style: styles.status, children: "Loading\u2026" }) : error ? /* @__PURE__ */ jsx4("p", { style: styles.error, role: "alert", children: error.explanation }) : report ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
762
|
+
/* @__PURE__ */ jsx4("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Variables" }),
|
|
763
|
+
report.env.length === 0 ? /* @__PURE__ */ jsx4("p", { style: styles.muted, children: "No variables declared \u2014 pass `env` to AdminModule." }) : /* @__PURE__ */ jsx4(
|
|
764
|
+
"div",
|
|
765
|
+
{
|
|
766
|
+
style: {
|
|
767
|
+
...styles.grid,
|
|
768
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(260px, 1fr))",
|
|
769
|
+
gap: 8
|
|
770
|
+
},
|
|
771
|
+
children: report.env.map((e) => /* @__PURE__ */ jsxs4(
|
|
772
|
+
"div",
|
|
773
|
+
{
|
|
774
|
+
style: {
|
|
775
|
+
...styles.card,
|
|
776
|
+
padding: "10px 12px",
|
|
777
|
+
display: "flex",
|
|
778
|
+
alignItems: "center",
|
|
779
|
+
justifyContent: "space-between",
|
|
780
|
+
gap: 8
|
|
781
|
+
},
|
|
782
|
+
children: [
|
|
783
|
+
/* @__PURE__ */ jsx4("span", { style: { ...styles.mono, wordBreak: "break-all" }, children: e.name }),
|
|
784
|
+
/* @__PURE__ */ jsx4(Pill, { tone: e.set ? "ok" : "bad", children: e.set ? "set" : "missing" })
|
|
785
|
+
]
|
|
786
|
+
},
|
|
787
|
+
e.name
|
|
788
|
+
))
|
|
789
|
+
}
|
|
790
|
+
),
|
|
791
|
+
/* @__PURE__ */ jsx4("h2", { style: styles.subtitle, children: "Module readiness" }),
|
|
792
|
+
/* @__PURE__ */ jsx4("ul", { style: styles.list, children: report.modules.map((m) => /* @__PURE__ */ jsxs4("li", { style: styles.row, children: [
|
|
793
|
+
/* @__PURE__ */ jsxs4(
|
|
241
794
|
"div",
|
|
242
795
|
{
|
|
243
|
-
style:
|
|
796
|
+
style: {
|
|
797
|
+
display: "flex",
|
|
798
|
+
justifyContent: "space-between",
|
|
799
|
+
gap: 12,
|
|
800
|
+
alignItems: "center"
|
|
801
|
+
},
|
|
802
|
+
children: [
|
|
803
|
+
/* @__PURE__ */ jsx4("span", { style: { ...styles.mono, fontWeight: 600 }, children: m.name }),
|
|
804
|
+
/* @__PURE__ */ jsx4(
|
|
805
|
+
Pill,
|
|
806
|
+
{
|
|
807
|
+
tone: m.problems.length === 0 ? "ok" : m.problems.some((p) => p.severity === "error") ? "bad" : "warn",
|
|
808
|
+
children: m.problems.length === 0 ? "ready" : `${m.problems.length} problem${m.problems.length === 1 ? "" : "s"}`
|
|
809
|
+
}
|
|
810
|
+
)
|
|
811
|
+
]
|
|
812
|
+
}
|
|
813
|
+
),
|
|
814
|
+
m.problems.map((p) => /* @__PURE__ */ jsx4(
|
|
815
|
+
"div",
|
|
816
|
+
{
|
|
817
|
+
style: {
|
|
818
|
+
marginTop: 6,
|
|
819
|
+
fontSize: 13,
|
|
820
|
+
color: p.severity === "error" ? "var(--fonderie-danger,#e00)" : "var(--fonderie-text-muted,#5c5c5c)"
|
|
821
|
+
},
|
|
244
822
|
children: p.message
|
|
245
823
|
},
|
|
246
824
|
p.message
|
|
247
825
|
))
|
|
248
|
-
] }, m.name)) })
|
|
249
|
-
/* @__PURE__ */ jsx3("h2", { style: styles.subtitle, children: "Environment" }),
|
|
250
|
-
report.env.length === 0 ? /* @__PURE__ */ jsx3("p", { style: styles.muted, children: "No variables declared \u2014 pass `env` to AdminModule." }) : /* @__PURE__ */ jsx3("ul", { style: styles.list, children: report.env.map((e) => /* @__PURE__ */ jsxs3("li", { style: styles.row, children: [
|
|
251
|
-
/* @__PURE__ */ jsx3("span", { style: styles.mono, children: e.name }),
|
|
252
|
-
" ",
|
|
253
|
-
e.set ? /* @__PURE__ */ jsx3("span", { style: styles.ok, children: "set" }) : /* @__PURE__ */ jsx3("span", { style: styles.bad, children: "missing" })
|
|
254
|
-
] }, e.name)) })
|
|
826
|
+
] }, m.name)) })
|
|
255
827
|
] }) : null
|
|
256
828
|
] });
|
|
257
829
|
}
|
|
258
830
|
|
|
259
831
|
// src/screens/DoctorScreen.tsx
|
|
260
832
|
import { useDoctor } from "@fonderie/react-admin";
|
|
261
|
-
import { jsx as
|
|
833
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
262
834
|
function DoctorScreen({ client }) {
|
|
263
835
|
const { report, isLoading, error, refresh } = useDoctor(client);
|
|
264
|
-
return /* @__PURE__ */
|
|
265
|
-
/* @__PURE__ */
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
"
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
onClick: () => void refresh(),
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
/* @__PURE__ */
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
836
|
+
return /* @__PURE__ */ jsxs5("div", { style: styles.container, children: [
|
|
837
|
+
/* @__PURE__ */ jsx5(
|
|
838
|
+
PageHeader,
|
|
839
|
+
{
|
|
840
|
+
title: "Doctor",
|
|
841
|
+
lead: "Every reconciliation check across the installed modules, run on demand.",
|
|
842
|
+
actions: /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
843
|
+
report && !isLoading ? /* @__PURE__ */ jsx5(Pill, { tone: report.ok ? "ok" : "bad", children: report.ok ? "all checks pass" : "a check failed" }) : null,
|
|
844
|
+
/* @__PURE__ */ jsx5(RefreshButton, { onClick: () => void refresh(), busy: isLoading, label: "Run again" })
|
|
845
|
+
] })
|
|
846
|
+
}
|
|
847
|
+
),
|
|
848
|
+
isLoading && !report ? /* @__PURE__ */ jsx5("p", { style: styles.status, children: "Running the checks\u2026" }) : error ? /* @__PURE__ */ jsx5("p", { style: styles.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ jsxs5("table", { style: styles.table, children: [
|
|
849
|
+
/* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs5("tr", { children: [
|
|
850
|
+
/* @__PURE__ */ jsx5("th", { style: { ...styles.th, width: 110 }, children: "Result" }),
|
|
851
|
+
/* @__PURE__ */ jsx5("th", { style: styles.th, children: "Check" }),
|
|
852
|
+
/* @__PURE__ */ jsx5("th", { style: { ...styles.th, textAlign: "right", width: 90 }, children: "Time" })
|
|
853
|
+
] }) }),
|
|
854
|
+
/* @__PURE__ */ jsx5("tbody", { children: report?.checks.map((c) => /* @__PURE__ */ jsxs5("tr", { children: [
|
|
855
|
+
/* @__PURE__ */ jsx5("td", { style: styles.td, children: /* @__PURE__ */ jsx5(
|
|
856
|
+
Pill,
|
|
857
|
+
{
|
|
858
|
+
tone: c.skipped ? "neutral" : c.ok ? c.findings.length ? "warn" : "ok" : "bad",
|
|
859
|
+
children: c.skipped ? "skipped" : c.ok ? c.findings.length ? "advice" : "ok" : "failed"
|
|
860
|
+
}
|
|
861
|
+
) }),
|
|
862
|
+
/* @__PURE__ */ jsxs5("td", { style: styles.td, children: [
|
|
863
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
864
|
+
/* @__PURE__ */ jsx5("span", { style: { ...styles.mono, fontWeight: 600 }, children: c.name }),
|
|
865
|
+
" ",
|
|
866
|
+
/* @__PURE__ */ jsx5("span", { style: styles.muted, children: c.module })
|
|
867
|
+
] }),
|
|
868
|
+
c.skipped ? /* @__PURE__ */ jsx5("div", { style: { ...styles.muted, marginTop: 4 }, children: c.skipped }) : null,
|
|
869
|
+
c.findings.map((f) => /* @__PURE__ */ jsx5(
|
|
870
|
+
"div",
|
|
871
|
+
{
|
|
872
|
+
style: {
|
|
873
|
+
marginTop: 4,
|
|
874
|
+
fontSize: 13,
|
|
875
|
+
lineHeight: 1.55,
|
|
876
|
+
color: c.ok ? "var(--fonderie-text,#171717)" : "var(--fonderie-danger,#e00)"
|
|
877
|
+
},
|
|
878
|
+
children: f
|
|
879
|
+
},
|
|
880
|
+
f
|
|
881
|
+
))
|
|
882
|
+
] }),
|
|
883
|
+
/* @__PURE__ */ jsxs5(
|
|
884
|
+
"td",
|
|
885
|
+
{
|
|
886
|
+
style: {
|
|
887
|
+
...styles.td,
|
|
888
|
+
...styles.muted,
|
|
889
|
+
textAlign: "right",
|
|
890
|
+
whiteSpace: "nowrap"
|
|
891
|
+
},
|
|
892
|
+
children: [
|
|
893
|
+
c.durationMs,
|
|
894
|
+
" ms"
|
|
895
|
+
]
|
|
896
|
+
}
|
|
897
|
+
)
|
|
898
|
+
] }, c.name)) })
|
|
899
|
+
] })
|
|
293
900
|
] });
|
|
294
901
|
}
|
|
295
902
|
|
|
296
903
|
// src/screens/ModulesScreen.tsx
|
|
297
|
-
import { useManifest } from "@fonderie/react-admin";
|
|
298
|
-
import {
|
|
904
|
+
import { useManifest as useManifest2 } from "@fonderie/react-admin";
|
|
905
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
299
906
|
function ModulesScreen({ client }) {
|
|
300
|
-
const { manifest, isLoading, error } =
|
|
301
|
-
return /* @__PURE__ */
|
|
302
|
-
/* @__PURE__ */
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
"
|
|
312
|
-
|
|
313
|
-
"
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
/* @__PURE__ */
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
"div",
|
|
329
|
-
{
|
|
330
|
-
style: p.severity === "error" ? styles.bad : styles.advice,
|
|
331
|
-
children: p.message
|
|
907
|
+
const { manifest, isLoading, error } = useManifest2(client);
|
|
908
|
+
return /* @__PURE__ */ jsxs6("div", { style: styles.container, children: [
|
|
909
|
+
/* @__PURE__ */ jsx6(
|
|
910
|
+
PageHeader,
|
|
911
|
+
{
|
|
912
|
+
title: "Modules",
|
|
913
|
+
lead: manifest ? `${manifest.env} \xB7 admin ${manifest.admin.version} \xB7 admin log ${manifest.admin.log ? "on" : "off"} \xB7 ${manifest.routes.length} routes` : "Every installed module, its version and whether it is ready."
|
|
914
|
+
}
|
|
915
|
+
),
|
|
916
|
+
isLoading ? /* @__PURE__ */ jsx6("p", { style: styles.status, children: "Loading\u2026" }) : error ? /* @__PURE__ */ jsx6("p", { style: styles.error, role: "alert", children: error.explanation }) : manifest ? /* @__PURE__ */ jsxs6("table", { style: styles.table, children: [
|
|
917
|
+
/* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsxs6("tr", { children: [
|
|
918
|
+
/* @__PURE__ */ jsx6("th", { style: styles.th, children: "Module" }),
|
|
919
|
+
/* @__PURE__ */ jsx6("th", { style: styles.th, children: "Version" }),
|
|
920
|
+
/* @__PURE__ */ jsx6("th", { style: styles.th, children: "Readiness" }),
|
|
921
|
+
/* @__PURE__ */ jsx6("th", { style: styles.th, children: "Admin" })
|
|
922
|
+
] }) }),
|
|
923
|
+
/* @__PURE__ */ jsx6("tbody", { children: manifest.modules.map((m) => /* @__PURE__ */ jsxs6("tr", { children: [
|
|
924
|
+
/* @__PURE__ */ jsx6("td", { style: { ...styles.td, ...styles.mono, fontWeight: 600 }, children: m.name }),
|
|
925
|
+
/* @__PURE__ */ jsx6("td", { style: { ...styles.td, ...styles.mono }, children: m.version ?? /* @__PURE__ */ jsx6("span", { style: styles.muted, children: "not reported" }) }),
|
|
926
|
+
/* @__PURE__ */ jsxs6("td", { style: styles.td, children: [
|
|
927
|
+
/* @__PURE__ */ jsx6(Pill, { tone: m.readiness.ok ? "ok" : "bad", children: m.readiness.ok ? "ready" : "error" }),
|
|
928
|
+
m.readiness.problems.map((p) => /* @__PURE__ */ jsx6(
|
|
929
|
+
"div",
|
|
930
|
+
{
|
|
931
|
+
style: {
|
|
932
|
+
marginTop: 6,
|
|
933
|
+
fontSize: 13,
|
|
934
|
+
color: p.severity === "error" ? "var(--fonderie-danger,#e00)" : "var(--fonderie-text-muted,#5c5c5c)"
|
|
332
935
|
},
|
|
333
|
-
p.message
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
] },
|
|
338
|
-
|
|
936
|
+
children: p.message
|
|
937
|
+
},
|
|
938
|
+
p.message
|
|
939
|
+
))
|
|
940
|
+
] }),
|
|
941
|
+
/* @__PURE__ */ jsx6("td", { style: styles.td, children: m.describesAdmin ? /* @__PURE__ */ jsx6("span", { style: styles.badge, children: "describes admin" }) : /* @__PURE__ */ jsx6("span", { style: styles.muted, children: "\u2014" }) })
|
|
942
|
+
] }, m.name)) })
|
|
339
943
|
] }) : null
|
|
340
944
|
] });
|
|
341
945
|
}
|
|
342
946
|
|
|
343
947
|
// src/screens/RoutesScreen.tsx
|
|
344
948
|
import { useAdminRoutes } from "@fonderie/react-admin";
|
|
345
|
-
import {
|
|
949
|
+
import { useState } from "react";
|
|
950
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
346
951
|
function RoutesScreen({ client }) {
|
|
347
952
|
const { report, isLoading, error } = useAdminRoutes(client);
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
953
|
+
const [q, setQ] = useState("");
|
|
954
|
+
const needle = q.trim().toLowerCase();
|
|
955
|
+
const routes = (report?.routes ?? []).filter(
|
|
956
|
+
(r) => !needle || `${r.method} ${r.path} ${r.module ?? "application"} ${r.guard}`.toLowerCase().includes(needle)
|
|
957
|
+
);
|
|
958
|
+
return /* @__PURE__ */ jsxs7("div", { style: styles.container, children: [
|
|
959
|
+
/* @__PURE__ */ jsx7(
|
|
960
|
+
PageHeader,
|
|
961
|
+
{
|
|
962
|
+
title: "Routes",
|
|
963
|
+
lead: report ? `${report.routes.length} routes exposed by this deployment, with the guard in front of each.` : "Every exposed route, with its guard.",
|
|
964
|
+
actions: /* @__PURE__ */ jsx7(
|
|
965
|
+
"input",
|
|
966
|
+
{
|
|
967
|
+
type: "search",
|
|
968
|
+
value: q,
|
|
969
|
+
onChange: (e) => setQ(e.target.value),
|
|
970
|
+
placeholder: "Filter by path, method, module\u2026",
|
|
971
|
+
style: { ...styles.input, width: 280 },
|
|
972
|
+
"aria-label": "Filter routes"
|
|
973
|
+
}
|
|
974
|
+
)
|
|
975
|
+
}
|
|
976
|
+
),
|
|
977
|
+
isLoading ? /* @__PURE__ */ jsx7("p", { style: styles.status, children: "Loading\u2026" }) : error ? /* @__PURE__ */ jsx7("p", { style: styles.error, role: "alert", children: error.explanation }) : /* @__PURE__ */ jsxs7("table", { style: styles.table, children: [
|
|
978
|
+
/* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsxs7("tr", { children: [
|
|
979
|
+
/* @__PURE__ */ jsx7("th", { style: { ...styles.th, width: 80 }, children: "Method" }),
|
|
980
|
+
/* @__PURE__ */ jsx7("th", { style: styles.th, children: "Path" }),
|
|
981
|
+
/* @__PURE__ */ jsx7("th", { style: styles.th, children: "Guard" }),
|
|
982
|
+
/* @__PURE__ */ jsx7("th", { style: styles.th, children: "Module" })
|
|
356
983
|
] }) }),
|
|
357
|
-
/* @__PURE__ */
|
|
358
|
-
/* @__PURE__ */
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
984
|
+
/* @__PURE__ */ jsxs7("tbody", { children: [
|
|
985
|
+
routes.map((r) => /* @__PURE__ */ jsxs7("tr", { children: [
|
|
986
|
+
/* @__PURE__ */ jsx7("td", { style: styles.td, children: /* @__PURE__ */ jsx7(MethodChip, { method: r.method }) }),
|
|
987
|
+
/* @__PURE__ */ jsx7("td", { style: { ...styles.td, ...styles.mono, wordBreak: "break-all" }, children: r.path }),
|
|
988
|
+
/* @__PURE__ */ jsx7("td", { style: styles.td, children: /* @__PURE__ */ jsx7(
|
|
989
|
+
Pill,
|
|
990
|
+
{
|
|
991
|
+
tone: r.guard === "admin" ? "ok" : r.guard === "probe" ? "neutral" : "info",
|
|
992
|
+
dot: false,
|
|
993
|
+
children: r.guard
|
|
994
|
+
}
|
|
995
|
+
) }),
|
|
996
|
+
/* @__PURE__ */ jsx7("td", { style: { ...styles.td, ...styles.muted }, children: r.module ?? "application" })
|
|
997
|
+
] }, `${r.method} ${r.path}`)),
|
|
998
|
+
routes.length === 0 ? /* @__PURE__ */ jsx7("tr", { children: /* @__PURE__ */ jsxs7("td", { style: { ...styles.td, ...styles.muted }, colSpan: 4, children: [
|
|
999
|
+
"No route matches \u201C",
|
|
1000
|
+
q,
|
|
1001
|
+
"\u201D."
|
|
1002
|
+
] }) }) : null
|
|
1003
|
+
] })
|
|
363
1004
|
] })
|
|
364
1005
|
] });
|
|
365
1006
|
}
|
|
366
1007
|
|
|
367
1008
|
// src/screens/MigrationsScreen.tsx
|
|
368
1009
|
import { useAdminMigrations } from "@fonderie/react-admin";
|
|
369
|
-
import { jsx as
|
|
1010
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
370
1011
|
function why(m, everApplied) {
|
|
371
1012
|
if (m.pending.length === 0) return null;
|
|
372
1013
|
if (m.blockedBy) return `Apply "${m.blockedBy}" first \u2014 it runs before this one and is behind.`;
|
|
@@ -377,36 +1018,40 @@ function why(m, everApplied) {
|
|
|
377
1018
|
function MigrationsScreen({ client }) {
|
|
378
1019
|
const { report, isLoading, error, refresh, apply } = useAdminMigrations(client);
|
|
379
1020
|
const behind = report?.modules.filter((m) => m.pending.length > 0) ?? [];
|
|
380
|
-
return /* @__PURE__ */
|
|
381
|
-
/* @__PURE__ */
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
1021
|
+
return /* @__PURE__ */ jsxs8("div", { style: styles.container, children: [
|
|
1022
|
+
/* @__PURE__ */ jsx8(
|
|
1023
|
+
PageHeader,
|
|
1024
|
+
{
|
|
1025
|
+
title: "Migrations",
|
|
1026
|
+
lead: "Schema changes each module ships, and whether this database has them.",
|
|
1027
|
+
actions: /* @__PURE__ */ jsx8(RefreshButton, { onClick: () => void refresh(), busy: isLoading })
|
|
1028
|
+
}
|
|
1029
|
+
),
|
|
1030
|
+
error ? /* @__PURE__ */ jsx8("p", { style: styles.error, role: "alert", children: error.status === 403 ? "Applying migrations needs a token with the write scope." : error.explanation }) : null,
|
|
1031
|
+
report && !report.everApplied ? /* @__PURE__ */ jsx8("p", { style: styles.notice, children: "This database has never been migrated \u2014 treating it as a first install, so nothing is held back." }) : null,
|
|
1032
|
+
report && behind.length === 0 ? /* @__PURE__ */ jsx8(Empty, { icon: "migrations", title: "Every module is up to date", children: "No pending migrations." }) : null,
|
|
389
1033
|
behind.map((m) => {
|
|
390
1034
|
const blocked = why(m, report?.everApplied ?? false);
|
|
391
1035
|
const files = m.pending.map((p) => p.file);
|
|
392
|
-
return /* @__PURE__ */
|
|
393
|
-
/* @__PURE__ */
|
|
394
|
-
m.name,
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
1036
|
+
return /* @__PURE__ */ jsxs8("section", { style: { ...styles.card, marginBottom: 16 }, children: [
|
|
1037
|
+
/* @__PURE__ */ jsxs8("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: [
|
|
1038
|
+
/* @__PURE__ */ jsx8("span", { style: styles.mono, children: m.name }),
|
|
1039
|
+
/* @__PURE__ */ jsxs8(Pill, { tone: "warn", children: [
|
|
1040
|
+
m.pending.length,
|
|
1041
|
+
" pending"
|
|
1042
|
+
] })
|
|
398
1043
|
] }),
|
|
399
|
-
/* @__PURE__ */
|
|
400
|
-
/* @__PURE__ */
|
|
1044
|
+
/* @__PURE__ */ jsx8("ul", { style: { margin: "0 0 12px", paddingLeft: 18, lineHeight: 1.9 }, children: m.pending.map((p) => /* @__PURE__ */ jsxs8("li", { children: [
|
|
1045
|
+
/* @__PURE__ */ jsx8("code", { style: styles.code, children: p.file }),
|
|
401
1046
|
" ",
|
|
402
|
-
p.impact === "destructive" ? /* @__PURE__ */
|
|
403
|
-
p.destructive.length > 0 ? /* @__PURE__ */
|
|
1047
|
+
p.impact === "destructive" ? /* @__PURE__ */ jsx8(Pill, { tone: "bad", children: "destructive" }) : /* @__PURE__ */ jsx8(Pill, { tone: "neutral", children: "additive" }),
|
|
1048
|
+
p.destructive.length > 0 ? /* @__PURE__ */ jsx8("ul", { children: p.destructive.map((s) => /* @__PURE__ */ jsx8("li", { children: /* @__PURE__ */ jsx8("code", { children: s.slice(0, 120) }) }, s)) }) : null
|
|
404
1049
|
] }, p.file)) }),
|
|
405
|
-
blocked ? /* @__PURE__ */
|
|
1050
|
+
blocked ? /* @__PURE__ */ jsx8("p", { style: { ...styles.notice, marginBottom: 0 }, children: blocked }) : /* @__PURE__ */ jsxs8(
|
|
406
1051
|
"button",
|
|
407
1052
|
{
|
|
408
1053
|
type: "button",
|
|
409
|
-
style: styles.
|
|
1054
|
+
style: styles.buttonPrimary,
|
|
410
1055
|
disabled: isLoading || !m.appliable,
|
|
411
1056
|
onClick: () => {
|
|
412
1057
|
if (window.confirm(
|
|
@@ -430,35 +1075,72 @@ function MigrationsScreen({ client }) {
|
|
|
430
1075
|
|
|
431
1076
|
// src/screens/TokensScreen.tsx
|
|
432
1077
|
import { useAdminTokens } from "@fonderie/react-admin";
|
|
433
|
-
import { useState } from "react";
|
|
434
|
-
import { Fragment as Fragment4, jsx as
|
|
1078
|
+
import { useState as useState2 } from "react";
|
|
1079
|
+
import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
435
1080
|
var ALL = ["read", "write", "secrets"];
|
|
436
1081
|
function TokensScreen({ client }) {
|
|
437
1082
|
const { report, isLoading, error, issue, revoke } = useAdminTokens(client);
|
|
438
|
-
const [name, setName] =
|
|
439
|
-
const [scopes, setScopes] =
|
|
440
|
-
const [days, setDays] =
|
|
441
|
-
const [minted, setMinted] =
|
|
1083
|
+
const [name, setName] = useState2("");
|
|
1084
|
+
const [scopes, setScopes] = useState2(["read"]);
|
|
1085
|
+
const [days, setDays] = useState2("");
|
|
1086
|
+
const [minted, setMinted] = useState2(null);
|
|
442
1087
|
const toggle = (s) => setScopes((prev) => prev.includes(s) ? prev.filter((x) => x !== s) : [...prev, s]);
|
|
443
|
-
return /* @__PURE__ */
|
|
444
|
-
/* @__PURE__ */
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
1088
|
+
return /* @__PURE__ */ jsxs9("div", { style: styles.container, children: [
|
|
1089
|
+
/* @__PURE__ */ jsx9(
|
|
1090
|
+
PageHeader,
|
|
1091
|
+
{
|
|
1092
|
+
title: "Access",
|
|
1093
|
+
lead: "Who can open this surface: the root token's strength, scoped tokens you have issued, and any legacy per-module tokens."
|
|
1094
|
+
}
|
|
1095
|
+
),
|
|
1096
|
+
error ? /* @__PURE__ */ jsx9("p", { style: styles.error, role: "alert", children: error.status === 401 ? "Issuing and revoking need the root token (the one in your deployment config)." : error.explanation }) : null,
|
|
1097
|
+
/* @__PURE__ */ jsx9("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Root token" }),
|
|
1098
|
+
report ? /* @__PURE__ */ jsxs9("div", { style: { ...styles.card, display: "flex", gap: 12, alignItems: "flex-start" }, children: [
|
|
1099
|
+
/* @__PURE__ */ jsx9(Icon, { name: "lock", size: 18, style: { marginTop: 2 } }),
|
|
1100
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
1101
|
+
/* @__PURE__ */ jsx9(Pill, { tone: report.admin.ok ? "ok" : "bad", children: report.admin.ok ? "strong" : "weak" }),
|
|
1102
|
+
report.admin.problems.map((p) => /* @__PURE__ */ jsx9(
|
|
1103
|
+
"div",
|
|
1104
|
+
{
|
|
1105
|
+
style: { marginTop: 6, color: "var(--fonderie-danger,#e00)", fontSize: 13 },
|
|
1106
|
+
children: p.message
|
|
1107
|
+
},
|
|
1108
|
+
p.message
|
|
1109
|
+
))
|
|
1110
|
+
] })
|
|
450
1111
|
] }) : null,
|
|
451
|
-
/* @__PURE__ */
|
|
452
|
-
report?.issued === null ? /* @__PURE__ */
|
|
453
|
-
minted ? /* @__PURE__ */
|
|
454
|
-
"
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
1112
|
+
/* @__PURE__ */ jsx9("h2", { style: styles.subtitle, children: "Issued tokens" }),
|
|
1113
|
+
report?.issued === null ? /* @__PURE__ */ jsx9("p", { style: styles.muted, children: "Issuing is off \u2014 give AdminModule a store and run its migrations." }) : /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1114
|
+
minted ? /* @__PURE__ */ jsxs9(
|
|
1115
|
+
"div",
|
|
1116
|
+
{
|
|
1117
|
+
style: {
|
|
1118
|
+
...styles.notice,
|
|
1119
|
+
background: "color-mix(in srgb, var(--fonderie-accent,#00d294) 10%, transparent)",
|
|
1120
|
+
borderColor: "color-mix(in srgb, var(--fonderie-accent,#00d294) 35%, transparent)"
|
|
1121
|
+
},
|
|
1122
|
+
children: [
|
|
1123
|
+
/* @__PURE__ */ jsx9("strong", { children: "Copy this now \u2014 it is never shown again." }),
|
|
1124
|
+
" (",
|
|
1125
|
+
minted.name,
|
|
1126
|
+
")",
|
|
1127
|
+
/* @__PURE__ */ jsx9(
|
|
1128
|
+
"div",
|
|
1129
|
+
{
|
|
1130
|
+
style: {
|
|
1131
|
+
...styles.code,
|
|
1132
|
+
display: "block",
|
|
1133
|
+
marginTop: 8,
|
|
1134
|
+
padding: "8px 10px",
|
|
1135
|
+
wordBreak: "break-all"
|
|
1136
|
+
},
|
|
1137
|
+
children: minted.token
|
|
1138
|
+
}
|
|
1139
|
+
)
|
|
1140
|
+
]
|
|
1141
|
+
}
|
|
1142
|
+
) : null,
|
|
1143
|
+
/* @__PURE__ */ jsxs9(
|
|
462
1144
|
"form",
|
|
463
1145
|
{
|
|
464
1146
|
style: styles.toolbar,
|
|
@@ -477,70 +1159,90 @@ function TokensScreen({ client }) {
|
|
|
477
1159
|
});
|
|
478
1160
|
},
|
|
479
1161
|
children: [
|
|
480
|
-
/* @__PURE__ */
|
|
1162
|
+
/* @__PURE__ */ jsx9(
|
|
481
1163
|
"input",
|
|
482
1164
|
{
|
|
483
1165
|
value: name,
|
|
484
1166
|
onChange: (e) => setName(e.target.value),
|
|
485
1167
|
placeholder: "name",
|
|
486
|
-
style:
|
|
1168
|
+
style: styles.input,
|
|
487
1169
|
"aria-label": "Name"
|
|
488
1170
|
}
|
|
489
1171
|
),
|
|
490
|
-
ALL.map((s) => /* @__PURE__ */
|
|
491
|
-
|
|
492
|
-
|
|
1172
|
+
ALL.map((s) => /* @__PURE__ */ jsxs9(
|
|
1173
|
+
"label",
|
|
1174
|
+
{
|
|
1175
|
+
style: {
|
|
1176
|
+
...styles.badge,
|
|
1177
|
+
cursor: "pointer",
|
|
1178
|
+
height: 32,
|
|
1179
|
+
boxSizing: "border-box",
|
|
1180
|
+
padding: "0 10px",
|
|
1181
|
+
fontSize: 13
|
|
1182
|
+
},
|
|
1183
|
+
children: [
|
|
1184
|
+
/* @__PURE__ */ jsx9("input", { type: "checkbox", checked: scopes.includes(s), onChange: () => toggle(s) }),
|
|
1185
|
+
" ",
|
|
1186
|
+
s
|
|
1187
|
+
]
|
|
1188
|
+
},
|
|
493
1189
|
s
|
|
494
|
-
|
|
495
|
-
/* @__PURE__ */
|
|
1190
|
+
)),
|
|
1191
|
+
/* @__PURE__ */ jsx9(
|
|
496
1192
|
"input",
|
|
497
1193
|
{
|
|
498
1194
|
value: days,
|
|
499
1195
|
onChange: (e) => setDays(e.target.value),
|
|
500
1196
|
placeholder: "days (optional)",
|
|
501
|
-
style: { ...styles.
|
|
1197
|
+
style: { ...styles.input, width: 140 },
|
|
502
1198
|
"aria-label": "Days"
|
|
503
1199
|
}
|
|
504
1200
|
),
|
|
505
|
-
/* @__PURE__ */
|
|
1201
|
+
/* @__PURE__ */ jsxs9(
|
|
506
1202
|
"button",
|
|
507
1203
|
{
|
|
508
1204
|
type: "submit",
|
|
509
|
-
style: styles.
|
|
1205
|
+
style: styles.buttonPrimary,
|
|
510
1206
|
disabled: !name.trim() || scopes.length === 0 || isLoading,
|
|
511
|
-
children:
|
|
1207
|
+
children: [
|
|
1208
|
+
/* @__PURE__ */ jsx9(Icon, { name: "plus", size: 14 }),
|
|
1209
|
+
"Issue token"
|
|
1210
|
+
]
|
|
512
1211
|
}
|
|
513
1212
|
)
|
|
514
1213
|
]
|
|
515
1214
|
}
|
|
516
1215
|
),
|
|
517
|
-
report?.issued && report.issued.length > 0 ? /* @__PURE__ */
|
|
518
|
-
/* @__PURE__ */
|
|
519
|
-
/* @__PURE__ */
|
|
520
|
-
/* @__PURE__ */
|
|
521
|
-
/* @__PURE__ */
|
|
522
|
-
/* @__PURE__ */
|
|
523
|
-
/* @__PURE__ */
|
|
524
|
-
/* @__PURE__ */
|
|
1216
|
+
report?.issued && report.issued.length > 0 ? /* @__PURE__ */ jsxs9("table", { style: styles.table, children: [
|
|
1217
|
+
/* @__PURE__ */ jsx9("thead", { children: /* @__PURE__ */ jsxs9("tr", { children: [
|
|
1218
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "Name" }),
|
|
1219
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "Scopes" }),
|
|
1220
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "Created" }),
|
|
1221
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "Expires" }),
|
|
1222
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th, children: "Last used" }),
|
|
1223
|
+
/* @__PURE__ */ jsx9("th", { style: styles.th })
|
|
525
1224
|
] }) }),
|
|
526
|
-
/* @__PURE__ */
|
|
527
|
-
/* @__PURE__ */
|
|
1225
|
+
/* @__PURE__ */ jsx9("tbody", { children: report.issued.map((t2) => /* @__PURE__ */ jsxs9("tr", { children: [
|
|
1226
|
+
/* @__PURE__ */ jsxs9("td", { style: styles.td, children: [
|
|
528
1227
|
t2.name,
|
|
529
|
-
t2.revokedAt ? /* @__PURE__ */
|
|
1228
|
+
t2.revokedAt ? /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1229
|
+
" ",
|
|
1230
|
+
/* @__PURE__ */ jsx9(Pill, { tone: "neutral", children: "revoked" })
|
|
1231
|
+
] }) : null
|
|
530
1232
|
] }),
|
|
531
|
-
/* @__PURE__ */
|
|
532
|
-
/* @__PURE__ */
|
|
1233
|
+
/* @__PURE__ */ jsx9("td", { style: { ...styles.td, ...styles.mono }, children: t2.scopes.join(", ") }),
|
|
1234
|
+
/* @__PURE__ */ jsxs9("td", { style: { ...styles.td, ...styles.muted }, children: [
|
|
533
1235
|
new Date(t2.createdAt).toLocaleDateString(),
|
|
534
1236
|
" \xB7 ",
|
|
535
1237
|
t2.createdBy
|
|
536
1238
|
] }),
|
|
537
|
-
/* @__PURE__ */
|
|
538
|
-
/* @__PURE__ */
|
|
539
|
-
/* @__PURE__ */
|
|
1239
|
+
/* @__PURE__ */ jsx9("td", { style: { ...styles.td, ...styles.muted }, children: t2.expiresAt ? new Date(t2.expiresAt).toLocaleDateString() : "never" }),
|
|
1240
|
+
/* @__PURE__ */ jsx9("td", { style: { ...styles.td, ...styles.muted }, children: t2.lastUsedAt ? new Date(t2.lastUsedAt).toLocaleString() : "never" }),
|
|
1241
|
+
/* @__PURE__ */ jsx9("td", { style: styles.td, children: t2.revokedAt ? null : /* @__PURE__ */ jsx9(
|
|
540
1242
|
"button",
|
|
541
1243
|
{
|
|
542
1244
|
type: "button",
|
|
543
|
-
style: styles.
|
|
1245
|
+
style: styles.buttonDanger,
|
|
544
1246
|
onClick: () => {
|
|
545
1247
|
if (window.confirm(
|
|
546
1248
|
`Revoke "${t2.name}"? Anything using it stops working immediately.`
|
|
@@ -552,13 +1254,13 @@ function TokensScreen({ client }) {
|
|
|
552
1254
|
}
|
|
553
1255
|
) })
|
|
554
1256
|
] }, t2.id)) })
|
|
555
|
-
] }) : /* @__PURE__ */
|
|
1257
|
+
] }) : /* @__PURE__ */ jsx9(Empty, { icon: "tokens", title: "No scoped tokens yet", children: "Issue a read-only token for a dashboard or a teammate instead of sharing the root." })
|
|
556
1258
|
] }),
|
|
557
|
-
/* @__PURE__ */
|
|
558
|
-
report && report.legacy.length === 0 ? /* @__PURE__ */
|
|
559
|
-
/* @__PURE__ */
|
|
1259
|
+
/* @__PURE__ */ jsx9("h2", { style: styles.subtitle, children: "Legacy per-brick tokens" }),
|
|
1260
|
+
report && report.legacy.length === 0 ? /* @__PURE__ */ jsx9("p", { style: styles.muted, children: "None \u2014 every brick's admin surface goes through this token." }) : /* @__PURE__ */ jsx9("ul", { style: styles.list, children: report?.legacy.map((l) => /* @__PURE__ */ jsxs9("li", { style: styles.row, children: [
|
|
1261
|
+
/* @__PURE__ */ jsx9("span", { style: styles.mono, children: l.module }),
|
|
560
1262
|
" ",
|
|
561
|
-
/* @__PURE__ */
|
|
1263
|
+
/* @__PURE__ */ jsx9("span", { style: styles.muted, children: "still registers its standalone routes with its own token (deprecated)" })
|
|
562
1264
|
] }, l.module)) })
|
|
563
1265
|
] });
|
|
564
1266
|
}
|
|
@@ -571,11 +1273,11 @@ import {
|
|
|
571
1273
|
useAdminUserSessions,
|
|
572
1274
|
useAdminUsers
|
|
573
1275
|
} from "@fonderie/react-admin";
|
|
574
|
-
import { useState as
|
|
575
|
-
import { Fragment as Fragment5, jsx as
|
|
1276
|
+
import { useState as useState3 } from "react";
|
|
1277
|
+
import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
576
1278
|
function UsersScreen({ client, pageSize = 50 }) {
|
|
577
|
-
const [input, setInput] =
|
|
578
|
-
const [selected, setSelected] =
|
|
1279
|
+
const [input, setInput] = useState3("");
|
|
1280
|
+
const [selected, setSelected] = useState3(null);
|
|
579
1281
|
const list = useAdminUsers(client, { limit: pageSize });
|
|
580
1282
|
const { user, isLoading, error, suspend, unsuspend, revokeSessions } = useAdminUser(
|
|
581
1283
|
client,
|
|
@@ -584,14 +1286,20 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
584
1286
|
const userId = user?.id ?? null;
|
|
585
1287
|
const sessions = useAdminUserSessions(client, userId);
|
|
586
1288
|
const history = useAdminLoginHistory(client, userId, { limit: 20 });
|
|
587
|
-
const yesNo = (v) => v ? /* @__PURE__ */
|
|
1289
|
+
const yesNo = (v) => v ? /* @__PURE__ */ jsx10(Pill, { tone: "ok", children: "yes" }) : /* @__PURE__ */ jsx10(Pill, { tone: "neutral", children: "no" });
|
|
588
1290
|
const clear = () => {
|
|
589
1291
|
setSelected(null);
|
|
590
1292
|
setInput("");
|
|
591
1293
|
};
|
|
592
|
-
return /* @__PURE__ */
|
|
593
|
-
/* @__PURE__ */
|
|
594
|
-
|
|
1294
|
+
return /* @__PURE__ */ jsxs10("div", { style: styles.container, children: [
|
|
1295
|
+
/* @__PURE__ */ jsx10(
|
|
1296
|
+
PageHeader,
|
|
1297
|
+
{
|
|
1298
|
+
title: "Users",
|
|
1299
|
+
lead: "Everyone signed up. Open an account for its sessions, sign-ins and the suspend and sign-out controls."
|
|
1300
|
+
}
|
|
1301
|
+
),
|
|
1302
|
+
/* @__PURE__ */ jsxs10(
|
|
595
1303
|
"form",
|
|
596
1304
|
{
|
|
597
1305
|
style: styles.toolbar,
|
|
@@ -601,19 +1309,25 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
601
1309
|
setSelected(email ? { email } : null);
|
|
602
1310
|
},
|
|
603
1311
|
children: [
|
|
604
|
-
/* @__PURE__ */
|
|
1312
|
+
/* @__PURE__ */ jsx10(
|
|
605
1313
|
"input",
|
|
606
1314
|
{
|
|
607
1315
|
type: "email",
|
|
608
1316
|
value: input,
|
|
609
1317
|
onChange: (e) => setInput(e.target.value),
|
|
610
1318
|
placeholder: "email address",
|
|
611
|
-
style: { ...styles.
|
|
1319
|
+
style: { ...styles.input, minWidth: 280 },
|
|
612
1320
|
"aria-label": "Email"
|
|
613
1321
|
}
|
|
614
1322
|
),
|
|
615
|
-
/* @__PURE__ */
|
|
616
|
-
|
|
1323
|
+
/* @__PURE__ */ jsxs10("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
|
|
1324
|
+
/* @__PURE__ */ jsx10(Icon, { name: "search", size: 14 }),
|
|
1325
|
+
"Look up"
|
|
1326
|
+
] }),
|
|
1327
|
+
selected ? /* @__PURE__ */ jsxs10("button", { type: "button", style: styles.buttonGhost, onClick: clear, children: [
|
|
1328
|
+
/* @__PURE__ */ jsx10(Icon, { name: "back", size: 14 }),
|
|
1329
|
+
"All users"
|
|
1330
|
+
] }) : /* @__PURE__ */ jsx10(
|
|
617
1331
|
"button",
|
|
618
1332
|
{
|
|
619
1333
|
type: "button",
|
|
@@ -626,37 +1340,37 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
626
1340
|
]
|
|
627
1341
|
}
|
|
628
1342
|
),
|
|
629
|
-
error ? /* @__PURE__ */
|
|
630
|
-
!selected ? /* @__PURE__ */
|
|
631
|
-
list.error ? /* @__PURE__ */
|
|
632
|
-
list.users.length === 0 && !list.isLoading ? /* @__PURE__ */
|
|
633
|
-
/* @__PURE__ */
|
|
634
|
-
/* @__PURE__ */
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */
|
|
637
|
-
/* @__PURE__ */
|
|
1343
|
+
error ? /* @__PURE__ */ jsx10("p", { style: styles.error, role: "alert", children: error.status === 404 ? "No user with that email." : error.explanation }) : null,
|
|
1344
|
+
!selected ? /* @__PURE__ */ jsxs10(Fragment5, { children: [
|
|
1345
|
+
list.error ? /* @__PURE__ */ jsx10("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
|
|
1346
|
+
list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx10(Empty, { icon: "users", title: "No users yet", children: "Sign-ups appear here as they happen." }) : /* @__PURE__ */ jsxs10("table", { style: styles.table, children: [
|
|
1347
|
+
/* @__PURE__ */ jsx10("thead", { children: /* @__PURE__ */ jsxs10("tr", { children: [
|
|
1348
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Email" }),
|
|
1349
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Name" }),
|
|
1350
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Created" }),
|
|
1351
|
+
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Status" })
|
|
638
1352
|
] }) }),
|
|
639
|
-
/* @__PURE__ */
|
|
640
|
-
/* @__PURE__ */
|
|
1353
|
+
/* @__PURE__ */ jsx10("tbody", { children: list.users.map((u) => /* @__PURE__ */ jsxs10("tr", { children: [
|
|
1354
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: /* @__PURE__ */ jsx10(
|
|
641
1355
|
"button",
|
|
642
1356
|
{
|
|
643
1357
|
type: "button",
|
|
644
|
-
style:
|
|
1358
|
+
style: styles.link,
|
|
645
1359
|
onClick: () => setSelected({ id: u.id }),
|
|
646
1360
|
children: u.email
|
|
647
1361
|
}
|
|
648
1362
|
) }),
|
|
649
|
-
/* @__PURE__ */
|
|
650
|
-
/* @__PURE__ */
|
|
651
|
-
/* @__PURE__ */
|
|
652
|
-
u.suspended ? /* @__PURE__ */
|
|
653
|
-
u.deletedAt ? /* @__PURE__ */
|
|
654
|
-
!u.suspended && !u.deletedAt ? /* @__PURE__ */
|
|
1363
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: `${u.firstName ?? ""} ${u.lastName ?? ""}`.trim() || /* @__PURE__ */ jsx10("span", { style: styles.muted, children: "\u2014" }) }),
|
|
1364
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: new Date(u.createdAt).toLocaleDateString() }),
|
|
1365
|
+
/* @__PURE__ */ jsxs10("td", { style: styles.td, children: [
|
|
1366
|
+
u.suspended ? /* @__PURE__ */ jsx10(Pill, { tone: "warn", children: "suspended" }) : null,
|
|
1367
|
+
u.deletedAt ? /* @__PURE__ */ jsx10(Pill, { tone: "neutral", children: "deleted" }) : null,
|
|
1368
|
+
!u.suspended && !u.deletedAt ? /* @__PURE__ */ jsx10(Pill, { tone: "ok", children: "active" }) : null
|
|
655
1369
|
] })
|
|
656
1370
|
] }, u.id)) })
|
|
657
1371
|
] }),
|
|
658
|
-
list.isLoading ? /* @__PURE__ */
|
|
659
|
-
list.hasMore && !list.isLoading ? /* @__PURE__ */
|
|
1372
|
+
list.isLoading ? /* @__PURE__ */ jsx10("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
1373
|
+
list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx10(
|
|
660
1374
|
"button",
|
|
661
1375
|
{
|
|
662
1376
|
type: "button",
|
|
@@ -666,48 +1380,48 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
666
1380
|
}
|
|
667
1381
|
) : null
|
|
668
1382
|
] }) : null,
|
|
669
|
-
user ? /* @__PURE__ */
|
|
670
|
-
/* @__PURE__ */
|
|
1383
|
+
user ? /* @__PURE__ */ jsxs10(Fragment5, { children: [
|
|
1384
|
+
/* @__PURE__ */ jsxs10("h2", { style: styles.subtitle, children: [
|
|
671
1385
|
user.firstName || user.lastName ? `${user.firstName} ${user.lastName}`.trim() : user.email,
|
|
672
1386
|
" ",
|
|
673
|
-
user.suspended ? /* @__PURE__ */
|
|
674
|
-
user.deletedAt ? /* @__PURE__ */
|
|
1387
|
+
user.suspended ? /* @__PURE__ */ jsx10(Pill, { tone: "warn", children: "suspended" }) : null,
|
|
1388
|
+
user.deletedAt ? /* @__PURE__ */ jsx10(Pill, { tone: "neutral", children: "deleted" }) : null
|
|
675
1389
|
] }),
|
|
676
|
-
/* @__PURE__ */
|
|
677
|
-
/* @__PURE__ */
|
|
678
|
-
/* @__PURE__ */
|
|
679
|
-
/* @__PURE__ */
|
|
1390
|
+
/* @__PURE__ */ jsx10("table", { style: styles.table, children: /* @__PURE__ */ jsxs10("tbody", { children: [
|
|
1391
|
+
/* @__PURE__ */ jsxs10("tr", { children: [
|
|
1392
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: "id" }),
|
|
1393
|
+
/* @__PURE__ */ jsx10("td", { style: { ...styles.td, ...styles.mono }, children: user.id })
|
|
680
1394
|
] }),
|
|
681
|
-
/* @__PURE__ */
|
|
682
|
-
/* @__PURE__ */
|
|
683
|
-
/* @__PURE__ */
|
|
1395
|
+
/* @__PURE__ */ jsxs10("tr", { children: [
|
|
1396
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: "email" }),
|
|
1397
|
+
/* @__PURE__ */ jsxs10("td", { style: styles.td, children: [
|
|
684
1398
|
user.email,
|
|
685
1399
|
" \xB7 verified ",
|
|
686
1400
|
yesNo(user.isEmailVerified)
|
|
687
1401
|
] })
|
|
688
1402
|
] }),
|
|
689
|
-
/* @__PURE__ */
|
|
690
|
-
/* @__PURE__ */
|
|
691
|
-
/* @__PURE__ */
|
|
1403
|
+
/* @__PURE__ */ jsxs10("tr", { children: [
|
|
1404
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: "MFA" }),
|
|
1405
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: yesNo(user.mfaEnabled) })
|
|
692
1406
|
] }),
|
|
693
|
-
/* @__PURE__ */
|
|
694
|
-
/* @__PURE__ */
|
|
695
|
-
/* @__PURE__ */
|
|
1407
|
+
/* @__PURE__ */ jsxs10("tr", { children: [
|
|
1408
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: "provider" }),
|
|
1409
|
+
/* @__PURE__ */ jsxs10("td", { style: styles.td, children: [
|
|
696
1410
|
user.provider || "password",
|
|
697
1411
|
user.hasPassword ? "" : " \xB7 no password set"
|
|
698
1412
|
] })
|
|
699
1413
|
] }),
|
|
700
|
-
/* @__PURE__ */
|
|
701
|
-
/* @__PURE__ */
|
|
702
|
-
/* @__PURE__ */
|
|
1414
|
+
/* @__PURE__ */ jsxs10("tr", { children: [
|
|
1415
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: "last login" }),
|
|
1416
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: user.lastLogin ? new Date(user.lastLogin).toLocaleString() : /* @__PURE__ */ jsx10("span", { style: styles.muted, children: "never" }) })
|
|
703
1417
|
] }),
|
|
704
|
-
/* @__PURE__ */
|
|
705
|
-
/* @__PURE__ */
|
|
706
|
-
/* @__PURE__ */
|
|
1418
|
+
/* @__PURE__ */ jsxs10("tr", { children: [
|
|
1419
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: "created" }),
|
|
1420
|
+
/* @__PURE__ */ jsx10("td", { style: styles.td, children: new Date(user.createdAt).toLocaleString() })
|
|
707
1421
|
] })
|
|
708
1422
|
] }) }),
|
|
709
|
-
/* @__PURE__ */
|
|
710
|
-
user.suspended ? /* @__PURE__ */
|
|
1423
|
+
/* @__PURE__ */ jsxs10("div", { style: { ...styles.toolbar, marginTop: 12 }, children: [
|
|
1424
|
+
user.suspended ? /* @__PURE__ */ jsx10(
|
|
711
1425
|
"button",
|
|
712
1426
|
{
|
|
713
1427
|
type: "button",
|
|
@@ -716,17 +1430,17 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
716
1430
|
disabled: isLoading,
|
|
717
1431
|
children: "Unsuspend"
|
|
718
1432
|
}
|
|
719
|
-
) : /* @__PURE__ */
|
|
1433
|
+
) : /* @__PURE__ */ jsx10(
|
|
720
1434
|
"button",
|
|
721
1435
|
{
|
|
722
1436
|
type: "button",
|
|
723
|
-
style: styles.
|
|
1437
|
+
style: styles.buttonDanger,
|
|
724
1438
|
onClick: () => void suspend(),
|
|
725
1439
|
disabled: isLoading,
|
|
726
1440
|
children: "Suspend"
|
|
727
1441
|
}
|
|
728
1442
|
),
|
|
729
|
-
/* @__PURE__ */
|
|
1443
|
+
/* @__PURE__ */ jsx10(
|
|
730
1444
|
"button",
|
|
731
1445
|
{
|
|
732
1446
|
type: "button",
|
|
@@ -737,38 +1451,38 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
737
1451
|
}
|
|
738
1452
|
)
|
|
739
1453
|
] }),
|
|
740
|
-
/* @__PURE__ */
|
|
741
|
-
sessions.sessions.length === 0 ? /* @__PURE__ */
|
|
742
|
-
/* @__PURE__ */
|
|
1454
|
+
/* @__PURE__ */ jsx10("h2", { style: styles.subtitle, children: "Live sessions" }),
|
|
1455
|
+
sessions.sessions.length === 0 ? /* @__PURE__ */ jsx10("p", { style: styles.muted, children: "None." }) : /* @__PURE__ */ jsx10("ul", { style: styles.list, children: sessions.sessions.map((s) => /* @__PURE__ */ jsxs10("li", { style: styles.row, children: [
|
|
1456
|
+
/* @__PURE__ */ jsx10("span", { style: styles.mono, children: s.ipAddress ?? "\u2014" }),
|
|
743
1457
|
" ",
|
|
744
|
-
describeLocation(s.location) ? /* @__PURE__ */
|
|
1458
|
+
describeLocation(s.location) ? /* @__PURE__ */ jsxs10("span", { style: styles.muted, children: [
|
|
745
1459
|
describeLocation(s.location),
|
|
746
1460
|
" "
|
|
747
1461
|
] }) : null,
|
|
748
|
-
/* @__PURE__ */
|
|
1462
|
+
/* @__PURE__ */ jsx10("span", { style: styles.muted, children: s.userAgent ?? "" }),
|
|
749
1463
|
" ",
|
|
750
|
-
/* @__PURE__ */
|
|
1464
|
+
/* @__PURE__ */ jsxs10("span", { style: styles.muted, children: [
|
|
751
1465
|
"since ",
|
|
752
1466
|
new Date(s.createdAt).toLocaleString()
|
|
753
1467
|
] })
|
|
754
1468
|
] }, s.id)) }),
|
|
755
|
-
/* @__PURE__ */
|
|
756
|
-
history.events.length === 0 && !history.isLoading ? /* @__PURE__ */
|
|
757
|
-
/* @__PURE__ */
|
|
1469
|
+
/* @__PURE__ */ jsx10("h2", { style: styles.subtitle, children: "Recent sign-ins" }),
|
|
1470
|
+
history.events.length === 0 && !history.isLoading ? /* @__PURE__ */ jsx10("p", { style: styles.muted, children: "None recorded." }) : /* @__PURE__ */ jsx10("ul", { style: styles.list, children: history.events.map((e) => /* @__PURE__ */ jsxs10("li", { style: styles.row, children: [
|
|
1471
|
+
/* @__PURE__ */ jsx10(Pill, { tone: e.outcome === "success" ? "ok" : "bad", children: e.outcome }),
|
|
758
1472
|
" ",
|
|
759
|
-
/* @__PURE__ */
|
|
1473
|
+
/* @__PURE__ */ jsx10("span", { style: styles.muted, children: e.method }),
|
|
760
1474
|
" ",
|
|
761
|
-
/* @__PURE__ */
|
|
1475
|
+
/* @__PURE__ */ jsx10("span", { style: styles.mono, children: e.ipAddress ?? "\u2014" }),
|
|
762
1476
|
" ",
|
|
763
|
-
describeLocation(e.location) ? /* @__PURE__ */
|
|
764
|
-
e.location?.proxy || e.location?.hosting ? /* @__PURE__ */
|
|
1477
|
+
describeLocation(e.location) ? /* @__PURE__ */ jsx10("span", { style: styles.muted, children: describeLocation(e.location) }) : null,
|
|
1478
|
+
e.location?.proxy || e.location?.hosting ? /* @__PURE__ */ jsxs10(Fragment5, { children: [
|
|
765
1479
|
" ",
|
|
766
|
-
e.location.proxy ? "proxy/VPN" : "hosting"
|
|
1480
|
+
/* @__PURE__ */ jsx10(Pill, { tone: "warn", children: e.location.proxy ? "proxy/VPN" : "hosting" })
|
|
767
1481
|
] }) : null,
|
|
768
1482
|
" ",
|
|
769
|
-
/* @__PURE__ */
|
|
1483
|
+
/* @__PURE__ */ jsx10("span", { style: styles.muted, children: new Date(e.createdAt).toLocaleString() })
|
|
770
1484
|
] }, e.id)) }),
|
|
771
|
-
history.hasMore && !history.isLoading ? /* @__PURE__ */
|
|
1485
|
+
history.hasMore && !history.isLoading ? /* @__PURE__ */ jsx10(
|
|
772
1486
|
"button",
|
|
773
1487
|
{
|
|
774
1488
|
type: "button",
|
|
@@ -783,59 +1497,67 @@ function UsersScreen({ client, pageSize = 50 }) {
|
|
|
783
1497
|
|
|
784
1498
|
// src/screens/CatalogScreen.tsx
|
|
785
1499
|
import { useAdminCatalog } from "@fonderie/react-admin";
|
|
786
|
-
import { Fragment as Fragment6, jsx as
|
|
1500
|
+
import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
787
1501
|
function CatalogScreen({ client }) {
|
|
788
1502
|
const { catalog, isLoading, error, refresh, deletePlan } = useAdminCatalog(client);
|
|
789
1503
|
const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
|
|
790
|
-
return /* @__PURE__ */
|
|
791
|
-
/* @__PURE__ */
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
"
|
|
1504
|
+
return /* @__PURE__ */ jsxs11("div", { style: styles.container, children: [
|
|
1505
|
+
/* @__PURE__ */ jsx11(
|
|
1506
|
+
PageHeader,
|
|
1507
|
+
{
|
|
1508
|
+
title: "Catalog",
|
|
1509
|
+
lead: "What you sell: plans as configured in code, and as stored in the database, side by side.",
|
|
1510
|
+
actions: /* @__PURE__ */ jsx11(RefreshButton, { onClick: () => void refresh(), busy: isLoading })
|
|
1511
|
+
}
|
|
1512
|
+
),
|
|
1513
|
+
error ? /* @__PURE__ */ jsx11("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
1514
|
+
isLoading && !catalog ? /* @__PURE__ */ jsx11("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
1515
|
+
catalog ? /* @__PURE__ */ jsxs11(Fragment6, { children: [
|
|
1516
|
+
/* @__PURE__ */ jsx11("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Configured (code)" }),
|
|
1517
|
+
/* @__PURE__ */ jsx11(
|
|
1518
|
+
"pre",
|
|
795
1519
|
{
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1520
|
+
style: {
|
|
1521
|
+
...styles.card,
|
|
1522
|
+
...styles.mono,
|
|
1523
|
+
margin: 0,
|
|
1524
|
+
overflowX: "auto",
|
|
1525
|
+
maxHeight: 360,
|
|
1526
|
+
lineHeight: 1.6
|
|
1527
|
+
},
|
|
1528
|
+
children: JSON.stringify(catalog.configured, null, 2)
|
|
801
1529
|
}
|
|
802
|
-
)
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
/* @__PURE__ */
|
|
813
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Tier" }),
|
|
814
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Seats" }),
|
|
815
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Monthly" }),
|
|
816
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Yearly" }),
|
|
817
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th, children: "Trial" }),
|
|
818
|
-
/* @__PURE__ */ jsx10("th", { style: styles.th })
|
|
1530
|
+
),
|
|
1531
|
+
/* @__PURE__ */ jsx11("h2", { style: styles.subtitle, children: "Stored (database)" }),
|
|
1532
|
+
catalog.stored.length === 0 ? /* @__PURE__ */ jsx11(Empty, { icon: "catalog", title: "No stored plans", children: "Plans are configured in code; nothing has been written to the database." }) : /* @__PURE__ */ jsxs11("table", { style: styles.table, children: [
|
|
1533
|
+
/* @__PURE__ */ jsx11("thead", { children: /* @__PURE__ */ jsxs11("tr", { children: [
|
|
1534
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Plan" }),
|
|
1535
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Tier" }),
|
|
1536
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Seats" }),
|
|
1537
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Monthly" }),
|
|
1538
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Yearly" }),
|
|
1539
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th, children: "Trial" }),
|
|
1540
|
+
/* @__PURE__ */ jsx11("th", { style: styles.th })
|
|
819
1541
|
] }) }),
|
|
820
|
-
/* @__PURE__ */
|
|
821
|
-
/* @__PURE__ */
|
|
822
|
-
/* @__PURE__ */
|
|
823
|
-
p.description ? /* @__PURE__ */
|
|
1542
|
+
/* @__PURE__ */ jsx11("tbody", { children: catalog.stored.map((p) => /* @__PURE__ */ jsxs11("tr", { children: [
|
|
1543
|
+
/* @__PURE__ */ jsxs11("td", { style: styles.td, children: [
|
|
1544
|
+
/* @__PURE__ */ jsx11("strong", { children: p.name }),
|
|
1545
|
+
p.description ? /* @__PURE__ */ jsx11("div", { style: styles.muted, children: p.description }) : null
|
|
824
1546
|
] }),
|
|
825
|
-
/* @__PURE__ */
|
|
826
|
-
/* @__PURE__ */
|
|
827
|
-
/* @__PURE__ */
|
|
1547
|
+
/* @__PURE__ */ jsx11("td", { style: styles.td, children: p.tier }),
|
|
1548
|
+
/* @__PURE__ */ jsx11("td", { style: styles.td, children: p.seats ?? "\u221E" }),
|
|
1549
|
+
/* @__PURE__ */ jsxs11("td", { style: styles.td, children: [
|
|
828
1550
|
money(p.pricing?.monthly),
|
|
829
1551
|
" ",
|
|
830
1552
|
p.pricing?.currency ?? ""
|
|
831
1553
|
] }),
|
|
832
|
-
/* @__PURE__ */
|
|
833
|
-
/* @__PURE__ */
|
|
834
|
-
/* @__PURE__ */
|
|
1554
|
+
/* @__PURE__ */ jsx11("td", { style: styles.td, children: money(p.pricing?.yearly) }),
|
|
1555
|
+
/* @__PURE__ */ jsx11("td", { style: styles.td, children: p.trialDays ? `${p.trialDays} d` : "\u2014" }),
|
|
1556
|
+
/* @__PURE__ */ jsx11("td", { style: styles.td, children: /* @__PURE__ */ jsx11(
|
|
835
1557
|
"button",
|
|
836
1558
|
{
|
|
837
1559
|
type: "button",
|
|
838
|
-
style: styles.
|
|
1560
|
+
style: styles.buttonDanger,
|
|
839
1561
|
onClick: () => {
|
|
840
1562
|
if (window.confirm(`Delete stored plan "${p.name}"?`))
|
|
841
1563
|
void deletePlan(p.id).catch(() => {
|
|
@@ -852,26 +1574,32 @@ function CatalogScreen({ client }) {
|
|
|
852
1574
|
|
|
853
1575
|
// src/screens/SubscriberScreen.tsx
|
|
854
1576
|
import { useAdminSubscriber, useAdminSubscribers } from "@fonderie/react-admin";
|
|
855
|
-
import { useState as
|
|
856
|
-
import { Fragment as Fragment7, jsx as
|
|
1577
|
+
import { useState as useState4 } from "react";
|
|
1578
|
+
import { Fragment as Fragment7, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
857
1579
|
function SubscriberScreen({ client, pageSize = 50 }) {
|
|
858
|
-
const [type, setType] =
|
|
859
|
-
const [idInput, setIdInput] =
|
|
860
|
-
const [subscriber, setSubscriber] =
|
|
1580
|
+
const [type, setType] = useState4("user");
|
|
1581
|
+
const [idInput, setIdInput] = useState4("");
|
|
1582
|
+
const [subscriber, setSubscriber] = useState4(null);
|
|
861
1583
|
const list = useAdminSubscribers(client, { limit: pageSize });
|
|
862
1584
|
const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = useAdminSubscriber(client, subscriber, { limit: 20 });
|
|
863
|
-
const [amount, setAmount] =
|
|
864
|
-
const [note, setNote] =
|
|
865
|
-
const [granted, setGranted] =
|
|
1585
|
+
const [amount, setAmount] = useState4("");
|
|
1586
|
+
const [note, setNote] = useState4("");
|
|
1587
|
+
const [granted, setGranted] = useState4(null);
|
|
866
1588
|
const open = (t2, id) => {
|
|
867
1589
|
setGranted(null);
|
|
868
1590
|
setType(t2);
|
|
869
1591
|
setIdInput(id);
|
|
870
1592
|
setSubscriber({ type: t2, id });
|
|
871
1593
|
};
|
|
872
|
-
return /* @__PURE__ */
|
|
873
|
-
/* @__PURE__ */
|
|
874
|
-
|
|
1594
|
+
return /* @__PURE__ */ jsxs12("div", { style: styles.container, children: [
|
|
1595
|
+
/* @__PURE__ */ jsx12(
|
|
1596
|
+
PageHeader,
|
|
1597
|
+
{
|
|
1598
|
+
title: "Subscribers",
|
|
1599
|
+
lead: "Who is subscribed. Open one for their plan, wallet and ledger, and to grant credit."
|
|
1600
|
+
}
|
|
1601
|
+
),
|
|
1602
|
+
/* @__PURE__ */ jsxs12(
|
|
875
1603
|
"form",
|
|
876
1604
|
{
|
|
877
1605
|
style: styles.toolbar,
|
|
@@ -881,31 +1609,34 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
881
1609
|
setSubscriber(idInput.trim() ? { type, id: idInput.trim() } : null);
|
|
882
1610
|
},
|
|
883
1611
|
children: [
|
|
884
|
-
/* @__PURE__ */
|
|
1612
|
+
/* @__PURE__ */ jsxs12(
|
|
885
1613
|
"select",
|
|
886
1614
|
{
|
|
887
1615
|
value: type,
|
|
888
1616
|
onChange: (e) => setType(e.target.value),
|
|
889
|
-
style: styles.
|
|
1617
|
+
style: styles.input,
|
|
890
1618
|
"aria-label": "Type",
|
|
891
1619
|
children: [
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
/* @__PURE__ */
|
|
1620
|
+
/* @__PURE__ */ jsx12("option", { value: "user", children: "user" }),
|
|
1621
|
+
/* @__PURE__ */ jsx12("option", { value: "workspace", children: "workspace" })
|
|
894
1622
|
]
|
|
895
1623
|
}
|
|
896
1624
|
),
|
|
897
|
-
/* @__PURE__ */
|
|
1625
|
+
/* @__PURE__ */ jsx12(
|
|
898
1626
|
"input",
|
|
899
1627
|
{
|
|
900
1628
|
value: idInput,
|
|
901
1629
|
onChange: (e) => setIdInput(e.target.value),
|
|
902
1630
|
placeholder: "subscriber id",
|
|
903
|
-
style: { ...styles.
|
|
1631
|
+
style: { ...styles.input, minWidth: 280 },
|
|
904
1632
|
"aria-label": "Subscriber id"
|
|
905
1633
|
}
|
|
906
1634
|
),
|
|
907
|
-
/* @__PURE__ */
|
|
908
|
-
|
|
1635
|
+
/* @__PURE__ */ jsxs12("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
|
|
1636
|
+
/* @__PURE__ */ jsx12(Icon, { name: "search", size: 14 }),
|
|
1637
|
+
"Look up"
|
|
1638
|
+
] }),
|
|
1639
|
+
subscriber ? /* @__PURE__ */ jsxs12(
|
|
909
1640
|
"button",
|
|
910
1641
|
{
|
|
911
1642
|
type: "button",
|
|
@@ -915,9 +1646,12 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
915
1646
|
setIdInput("");
|
|
916
1647
|
setGranted(null);
|
|
917
1648
|
},
|
|
918
|
-
children:
|
|
1649
|
+
children: [
|
|
1650
|
+
/* @__PURE__ */ jsx12(Icon, { name: "back", size: 14 }),
|
|
1651
|
+
"All subscribers"
|
|
1652
|
+
]
|
|
919
1653
|
}
|
|
920
|
-
) : /* @__PURE__ */
|
|
1654
|
+
) : /* @__PURE__ */ jsx12(
|
|
921
1655
|
"button",
|
|
922
1656
|
{
|
|
923
1657
|
type: "button",
|
|
@@ -930,22 +1664,22 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
930
1664
|
]
|
|
931
1665
|
}
|
|
932
1666
|
),
|
|
933
|
-
error ? /* @__PURE__ */
|
|
934
|
-
!subscriber ? /* @__PURE__ */
|
|
935
|
-
list.error ? /* @__PURE__ */
|
|
936
|
-
list.subscriptions.length === 0 && !list.isLoading ? /* @__PURE__ */
|
|
937
|
-
/* @__PURE__ */
|
|
938
|
-
/* @__PURE__ */
|
|
939
|
-
/* @__PURE__ */
|
|
940
|
-
/* @__PURE__ */
|
|
941
|
-
/* @__PURE__ */
|
|
1667
|
+
error ? /* @__PURE__ */ jsx12("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
1668
|
+
!subscriber ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1669
|
+
list.error ? /* @__PURE__ */ jsx12("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
|
|
1670
|
+
list.subscriptions.length === 0 && !list.isLoading ? /* @__PURE__ */ jsx12(Empty, { icon: "subscriber", title: "No subscribers yet", children: "Subscriptions appear here once someone checks out." }) : /* @__PURE__ */ jsxs12("table", { style: styles.table, children: [
|
|
1671
|
+
/* @__PURE__ */ jsx12("thead", { children: /* @__PURE__ */ jsxs12("tr", { children: [
|
|
1672
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Subscriber" }),
|
|
1673
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Plan" }),
|
|
1674
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Status" }),
|
|
1675
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Renews" })
|
|
942
1676
|
] }) }),
|
|
943
|
-
/* @__PURE__ */
|
|
944
|
-
/* @__PURE__ */
|
|
1677
|
+
/* @__PURE__ */ jsx12("tbody", { children: list.subscriptions.map((s) => /* @__PURE__ */ jsxs12("tr", { children: [
|
|
1678
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: /* @__PURE__ */ jsxs12(
|
|
945
1679
|
"button",
|
|
946
1680
|
{
|
|
947
1681
|
type: "button",
|
|
948
|
-
style: { ...styles.
|
|
1682
|
+
style: { ...styles.link, ...styles.mono },
|
|
949
1683
|
onClick: () => open(s.subscriberType, s.subscriberId),
|
|
950
1684
|
children: [
|
|
951
1685
|
s.subscriberType,
|
|
@@ -954,20 +1688,29 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
954
1688
|
]
|
|
955
1689
|
}
|
|
956
1690
|
) }),
|
|
957
|
-
/* @__PURE__ */
|
|
958
|
-
/* @__PURE__ */
|
|
1691
|
+
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1692
|
+
/* @__PURE__ */ jsx12("strong", { children: s.plan }),
|
|
959
1693
|
" \xB7 ",
|
|
960
1694
|
s.interval
|
|
961
1695
|
] }),
|
|
962
|
-
/* @__PURE__ */
|
|
963
|
-
|
|
964
|
-
|
|
1696
|
+
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1697
|
+
/* @__PURE__ */ jsx12(
|
|
1698
|
+
Pill,
|
|
1699
|
+
{
|
|
1700
|
+
tone: s.status === "active" ? "ok" : s.status === "trialing" ? "info" : s.status === "past_due" ? "warn" : "neutral",
|
|
1701
|
+
children: s.status
|
|
1702
|
+
}
|
|
1703
|
+
),
|
|
1704
|
+
s.cancelAtPeriodEnd ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1705
|
+
" ",
|
|
1706
|
+
/* @__PURE__ */ jsx12(Pill, { tone: "warn", dot: false, children: "cancels" })
|
|
1707
|
+
] }) : null
|
|
965
1708
|
] }),
|
|
966
|
-
/* @__PURE__ */
|
|
1709
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : /* @__PURE__ */ jsx12("span", { style: styles.muted, children: "\u2014" }) })
|
|
967
1710
|
] }, s.id)) })
|
|
968
1711
|
] }),
|
|
969
|
-
list.isLoading ? /* @__PURE__ */
|
|
970
|
-
list.hasMore && !list.isLoading ? /* @__PURE__ */
|
|
1712
|
+
list.isLoading ? /* @__PURE__ */ jsx12("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
1713
|
+
list.hasMore && !list.isLoading ? /* @__PURE__ */ jsx12(
|
|
971
1714
|
"button",
|
|
972
1715
|
{
|
|
973
1716
|
type: "button",
|
|
@@ -977,27 +1720,27 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
977
1720
|
}
|
|
978
1721
|
) : null
|
|
979
1722
|
] }) : null,
|
|
980
|
-
subscriber && !isLoading ? /* @__PURE__ */
|
|
981
|
-
/* @__PURE__ */
|
|
982
|
-
subscription ? /* @__PURE__ */
|
|
983
|
-
/* @__PURE__ */
|
|
984
|
-
/* @__PURE__ */
|
|
985
|
-
/* @__PURE__ */
|
|
986
|
-
/* @__PURE__ */
|
|
1723
|
+
subscriber && !isLoading ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1724
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "Subscription" }),
|
|
1725
|
+
subscription ? /* @__PURE__ */ jsx12("table", { style: styles.table, children: /* @__PURE__ */ jsxs12("tbody", { children: [
|
|
1726
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1727
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "plan" }),
|
|
1728
|
+
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1729
|
+
/* @__PURE__ */ jsx12("strong", { children: subscription.plan }),
|
|
987
1730
|
" \xB7 ",
|
|
988
1731
|
subscription.interval
|
|
989
1732
|
] })
|
|
990
1733
|
] }),
|
|
991
|
-
/* @__PURE__ */
|
|
992
|
-
/* @__PURE__ */
|
|
993
|
-
/* @__PURE__ */
|
|
1734
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1735
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "status" }),
|
|
1736
|
+
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
994
1737
|
subscription.status,
|
|
995
1738
|
subscription.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""
|
|
996
1739
|
] })
|
|
997
1740
|
] }),
|
|
998
|
-
/* @__PURE__ */
|
|
999
|
-
/* @__PURE__ */
|
|
1000
|
-
/* @__PURE__ */
|
|
1741
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1742
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "period" }),
|
|
1743
|
+
/* @__PURE__ */ jsxs12("td", { style: styles.td, children: [
|
|
1001
1744
|
subscription.currentPeriodStart ? new Date(subscription.currentPeriodStart).toLocaleDateString() : "\u2014",
|
|
1002
1745
|
" ",
|
|
1003
1746
|
"\u2192",
|
|
@@ -1005,28 +1748,49 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
1005
1748
|
subscription.currentPeriodEnd ? new Date(subscription.currentPeriodEnd).toLocaleDateString() : "\u2014"
|
|
1006
1749
|
] })
|
|
1007
1750
|
] }),
|
|
1008
|
-
/* @__PURE__ */
|
|
1009
|
-
/* @__PURE__ */
|
|
1010
|
-
/* @__PURE__ */
|
|
1751
|
+
/* @__PURE__ */ jsxs12("tr", { children: [
|
|
1752
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: "provider" }),
|
|
1753
|
+
/* @__PURE__ */ jsx12("td", { style: { ...styles.td, ...styles.mono }, children: subscription.providerSubscriptionId ?? "\u2014" })
|
|
1011
1754
|
] })
|
|
1012
|
-
] }) }) : /* @__PURE__ */
|
|
1013
|
-
/* @__PURE__ */
|
|
1014
|
-
wallet ? /* @__PURE__ */
|
|
1015
|
-
/* @__PURE__ */
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1755
|
+
] }) }) : /* @__PURE__ */ jsx12("p", { style: styles.muted, children: "No subscription." }),
|
|
1756
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "Wallet" }),
|
|
1757
|
+
wallet ? /* @__PURE__ */ jsxs12(Fragment7, { children: [
|
|
1758
|
+
/* @__PURE__ */ jsxs12(
|
|
1759
|
+
"p",
|
|
1760
|
+
{
|
|
1761
|
+
style: {
|
|
1762
|
+
...styles.card,
|
|
1763
|
+
display: "flex",
|
|
1764
|
+
alignItems: "baseline",
|
|
1765
|
+
gap: 8,
|
|
1766
|
+
flexWrap: "wrap"
|
|
1767
|
+
},
|
|
1768
|
+
children: [
|
|
1769
|
+
/* @__PURE__ */ jsx12(
|
|
1770
|
+
"strong",
|
|
1771
|
+
{
|
|
1772
|
+
style: {
|
|
1773
|
+
fontSize: 22,
|
|
1774
|
+
letterSpacing: "var(--fonderie-tracking-display,-0.05em)"
|
|
1775
|
+
},
|
|
1776
|
+
children: wallet.balance
|
|
1777
|
+
}
|
|
1778
|
+
),
|
|
1779
|
+
" ",
|
|
1780
|
+
wallet.currency,
|
|
1781
|
+
" ",
|
|
1782
|
+
/* @__PURE__ */ jsxs12("span", { style: styles.muted, children: [
|
|
1783
|
+
"(granted ",
|
|
1784
|
+
wallet.granted ?? "0",
|
|
1785
|
+
" \xB7 purchased ",
|
|
1786
|
+
wallet.purchased ?? "0",
|
|
1787
|
+
") \xB7 minor units, precision ",
|
|
1788
|
+
wallet.precision
|
|
1789
|
+
] })
|
|
1790
|
+
]
|
|
1791
|
+
}
|
|
1792
|
+
),
|
|
1793
|
+
/* @__PURE__ */ jsxs12(
|
|
1030
1794
|
"form",
|
|
1031
1795
|
{
|
|
1032
1796
|
style: styles.toolbar,
|
|
@@ -1045,47 +1809,58 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
1045
1809
|
});
|
|
1046
1810
|
},
|
|
1047
1811
|
children: [
|
|
1048
|
-
/* @__PURE__ */
|
|
1812
|
+
/* @__PURE__ */ jsx12(
|
|
1049
1813
|
"input",
|
|
1050
1814
|
{
|
|
1051
1815
|
value: amount,
|
|
1052
1816
|
onChange: (e) => setAmount(e.target.value),
|
|
1053
1817
|
placeholder: "amount (minor units)",
|
|
1054
|
-
style:
|
|
1818
|
+
style: styles.input,
|
|
1055
1819
|
"aria-label": "Amount"
|
|
1056
1820
|
}
|
|
1057
1821
|
),
|
|
1058
|
-
/* @__PURE__ */
|
|
1822
|
+
/* @__PURE__ */ jsx12(
|
|
1059
1823
|
"input",
|
|
1060
1824
|
{
|
|
1061
1825
|
value: note,
|
|
1062
1826
|
onChange: (e) => setNote(e.target.value),
|
|
1063
1827
|
placeholder: "reason (optional)",
|
|
1064
|
-
style: { ...styles.
|
|
1828
|
+
style: { ...styles.input, minWidth: 220 },
|
|
1065
1829
|
"aria-label": "Reason"
|
|
1066
1830
|
}
|
|
1067
1831
|
),
|
|
1068
|
-
/* @__PURE__ */
|
|
1069
|
-
|
|
1832
|
+
/* @__PURE__ */ jsxs12(
|
|
1833
|
+
"button",
|
|
1834
|
+
{
|
|
1835
|
+
type: "submit",
|
|
1836
|
+
style: styles.buttonPrimary,
|
|
1837
|
+
disabled: !/^\d+$/.test(amount.trim()),
|
|
1838
|
+
children: [
|
|
1839
|
+
/* @__PURE__ */ jsx12(Icon, { name: "plus", size: 14 }),
|
|
1840
|
+
"Grant"
|
|
1841
|
+
]
|
|
1842
|
+
}
|
|
1843
|
+
),
|
|
1844
|
+
granted ? /* @__PURE__ */ jsx12("span", { style: styles.ok, children: granted }) : null
|
|
1070
1845
|
]
|
|
1071
1846
|
}
|
|
1072
1847
|
),
|
|
1073
|
-
/* @__PURE__ */
|
|
1074
|
-
ledger.length === 0 ? /* @__PURE__ */
|
|
1075
|
-
/* @__PURE__ */
|
|
1076
|
-
/* @__PURE__ */
|
|
1077
|
-
/* @__PURE__ */
|
|
1078
|
-
/* @__PURE__ */
|
|
1079
|
-
/* @__PURE__ */
|
|
1848
|
+
/* @__PURE__ */ jsx12("h2", { style: styles.subtitle, children: "Ledger" }),
|
|
1849
|
+
ledger.length === 0 ? /* @__PURE__ */ jsx12(Empty, { icon: "subscriber", title: "Nothing moved yet" }) : /* @__PURE__ */ jsxs12("table", { style: styles.table, children: [
|
|
1850
|
+
/* @__PURE__ */ jsx12("thead", { children: /* @__PURE__ */ jsxs12("tr", { children: [
|
|
1851
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "When" }),
|
|
1852
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Kind" }),
|
|
1853
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Amount" }),
|
|
1854
|
+
/* @__PURE__ */ jsx12("th", { style: styles.th, children: "Note" })
|
|
1080
1855
|
] }) }),
|
|
1081
|
-
/* @__PURE__ */
|
|
1082
|
-
/* @__PURE__ */
|
|
1083
|
-
/* @__PURE__ */
|
|
1084
|
-
/* @__PURE__ */
|
|
1085
|
-
/* @__PURE__ */
|
|
1856
|
+
/* @__PURE__ */ jsx12("tbody", { children: ledger.map((t2) => /* @__PURE__ */ jsxs12("tr", { children: [
|
|
1857
|
+
/* @__PURE__ */ jsx12("td", { style: { ...styles.td, ...styles.muted }, children: new Date(t2.createdAt).toLocaleString() }),
|
|
1858
|
+
/* @__PURE__ */ jsx12("td", { style: styles.td, children: t2.type }),
|
|
1859
|
+
/* @__PURE__ */ jsx12("td", { style: { ...styles.td, ...styles.mono }, children: t2.amount }),
|
|
1860
|
+
/* @__PURE__ */ jsx12("td", { style: { ...styles.td, ...styles.muted }, children: t2.description ?? "" })
|
|
1086
1861
|
] }, t2.id)) })
|
|
1087
1862
|
] }),
|
|
1088
|
-
hasMoreLedger ? /* @__PURE__ */
|
|
1863
|
+
hasMoreLedger ? /* @__PURE__ */ jsx12(
|
|
1089
1864
|
"button",
|
|
1090
1865
|
{
|
|
1091
1866
|
type: "button",
|
|
@@ -1094,37 +1869,43 @@ function SubscriberScreen({ client, pageSize = 50 }) {
|
|
|
1094
1869
|
children: "Load more"
|
|
1095
1870
|
}
|
|
1096
1871
|
) : null
|
|
1097
|
-
] }) : /* @__PURE__ */
|
|
1872
|
+
] }) : /* @__PURE__ */ jsx12("p", { style: styles.muted, children: "No wallet \u2014 billing has no wallet configuration." })
|
|
1098
1873
|
] }) : null
|
|
1099
1874
|
] });
|
|
1100
1875
|
}
|
|
1101
1876
|
|
|
1102
1877
|
// src/screens/AuditScreen.tsx
|
|
1103
1878
|
import { useAdminAudit } from "@fonderie/react-admin";
|
|
1104
|
-
import { useState as
|
|
1105
|
-
import { jsx as
|
|
1879
|
+
import { useState as useState5 } from "react";
|
|
1880
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1106
1881
|
function AuditScreen({ client, pageSize = 50 }) {
|
|
1107
|
-
const [draft, setDraft] =
|
|
1108
|
-
const [filter, setFilter] =
|
|
1882
|
+
const [draft, setDraft] = useState5({ workspaceId: "", type: "", actorId: "" });
|
|
1883
|
+
const [filter, setFilter] = useState5(
|
|
1109
1884
|
{}
|
|
1110
1885
|
);
|
|
1111
1886
|
const { events, hasMore, isLoading, error, refresh, loadMore } = useAdminAudit(client, {
|
|
1112
1887
|
...filter,
|
|
1113
1888
|
limit: pageSize
|
|
1114
1889
|
});
|
|
1115
|
-
const field = (key, placeholder) => /* @__PURE__ */
|
|
1890
|
+
const field = (key, placeholder) => /* @__PURE__ */ jsx13(
|
|
1116
1891
|
"input",
|
|
1117
1892
|
{
|
|
1118
1893
|
value: draft[key],
|
|
1119
1894
|
onChange: (e) => setDraft({ ...draft, [key]: e.target.value }),
|
|
1120
1895
|
placeholder,
|
|
1121
|
-
style:
|
|
1896
|
+
style: styles.input,
|
|
1122
1897
|
"aria-label": placeholder
|
|
1123
1898
|
}
|
|
1124
1899
|
);
|
|
1125
|
-
return /* @__PURE__ */
|
|
1126
|
-
/* @__PURE__ */
|
|
1127
|
-
|
|
1900
|
+
return /* @__PURE__ */ jsxs13("div", { style: styles.container, children: [
|
|
1901
|
+
/* @__PURE__ */ jsx13(
|
|
1902
|
+
PageHeader,
|
|
1903
|
+
{
|
|
1904
|
+
title: "Audit",
|
|
1905
|
+
lead: "What happened, across every workspace unless you name one. The chain's integrity verdict is on the Doctor page."
|
|
1906
|
+
}
|
|
1907
|
+
),
|
|
1908
|
+
/* @__PURE__ */ jsxs13(
|
|
1128
1909
|
"form",
|
|
1129
1910
|
{
|
|
1130
1911
|
style: styles.toolbar,
|
|
@@ -1140,8 +1921,11 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
1140
1921
|
field("workspaceId", "workspace id (all if empty)"),
|
|
1141
1922
|
field("type", "event type"),
|
|
1142
1923
|
field("actorId", "actor id"),
|
|
1143
|
-
/* @__PURE__ */
|
|
1144
|
-
|
|
1924
|
+
/* @__PURE__ */ jsxs13("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
|
|
1925
|
+
/* @__PURE__ */ jsx13(Icon, { name: "search", size: 14 }),
|
|
1926
|
+
"Filter"
|
|
1927
|
+
] }),
|
|
1928
|
+
/* @__PURE__ */ jsx13(
|
|
1145
1929
|
"button",
|
|
1146
1930
|
{
|
|
1147
1931
|
type: "button",
|
|
@@ -1154,25 +1938,25 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
1154
1938
|
]
|
|
1155
1939
|
}
|
|
1156
1940
|
),
|
|
1157
|
-
error ? /* @__PURE__ */
|
|
1158
|
-
events.length === 0 && !isLoading ? /* @__PURE__ */
|
|
1159
|
-
/* @__PURE__ */
|
|
1160
|
-
/* @__PURE__ */
|
|
1161
|
-
/* @__PURE__ */
|
|
1162
|
-
/* @__PURE__ */
|
|
1163
|
-
/* @__PURE__ */
|
|
1164
|
-
/* @__PURE__ */
|
|
1941
|
+
error ? /* @__PURE__ */ jsx13("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
|
|
1942
|
+
events.length === 0 && !isLoading ? /* @__PURE__ */ jsx13(Empty, { icon: "audit", title: "Nothing recorded for this filter" }) : /* @__PURE__ */ jsxs13("table", { style: styles.table, children: [
|
|
1943
|
+
/* @__PURE__ */ jsx13("thead", { children: /* @__PURE__ */ jsxs13("tr", { children: [
|
|
1944
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "When" }),
|
|
1945
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Type" }),
|
|
1946
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Workspace" }),
|
|
1947
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Actor" }),
|
|
1948
|
+
/* @__PURE__ */ jsx13("th", { style: styles.th, children: "Request" })
|
|
1165
1949
|
] }) }),
|
|
1166
|
-
/* @__PURE__ */
|
|
1167
|
-
/* @__PURE__ */
|
|
1168
|
-
/* @__PURE__ */
|
|
1169
|
-
/* @__PURE__ */
|
|
1170
|
-
/* @__PURE__ */
|
|
1171
|
-
/* @__PURE__ */
|
|
1950
|
+
/* @__PURE__ */ jsx13("tbody", { children: events.map((e) => /* @__PURE__ */ jsxs13("tr", { children: [
|
|
1951
|
+
/* @__PURE__ */ jsx13("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
|
|
1952
|
+
/* @__PURE__ */ jsx13("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
|
|
1953
|
+
/* @__PURE__ */ jsx13("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
|
|
1954
|
+
/* @__PURE__ */ jsx13("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
|
|
1955
|
+
/* @__PURE__ */ jsx13("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
|
|
1172
1956
|
] }, e.id)) })
|
|
1173
1957
|
] }),
|
|
1174
|
-
isLoading ? /* @__PURE__ */
|
|
1175
|
-
hasMore && !isLoading ? /* @__PURE__ */
|
|
1958
|
+
isLoading ? /* @__PURE__ */ jsx13("p", { style: styles.status, children: "Loading\u2026" }) : null,
|
|
1959
|
+
hasMore && !isLoading ? /* @__PURE__ */ jsx13(
|
|
1176
1960
|
"button",
|
|
1177
1961
|
{
|
|
1178
1962
|
type: "button",
|
|
@@ -1185,7 +1969,35 @@ function AuditScreen({ client, pageSize = 50 }) {
|
|
|
1185
1969
|
}
|
|
1186
1970
|
|
|
1187
1971
|
// src/screens/AdminShell.tsx
|
|
1188
|
-
import { Fragment as Fragment8, jsx as
|
|
1972
|
+
import { Fragment as Fragment8, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1973
|
+
var ICON = {
|
|
1974
|
+
attention: "attention",
|
|
1975
|
+
modules: "modules",
|
|
1976
|
+
environment: "environment",
|
|
1977
|
+
doctor: "doctor",
|
|
1978
|
+
routes: "routes",
|
|
1979
|
+
users: "users",
|
|
1980
|
+
catalog: "catalog",
|
|
1981
|
+
subscriber: "subscriber",
|
|
1982
|
+
settings: "settings",
|
|
1983
|
+
templates: "templates",
|
|
1984
|
+
audit: "audit",
|
|
1985
|
+
log: "log",
|
|
1986
|
+
tokens: "tokens",
|
|
1987
|
+
migrations: "migrations"
|
|
1988
|
+
};
|
|
1989
|
+
var NARROW = "(max-width: 820px)";
|
|
1990
|
+
function useNarrow() {
|
|
1991
|
+
const query = typeof window !== "undefined" && window.matchMedia ? window.matchMedia(NARROW) : null;
|
|
1992
|
+
const [narrow, setNarrow] = useState6(() => query?.matches ?? false);
|
|
1993
|
+
useEffect(() => {
|
|
1994
|
+
if (!query) return;
|
|
1995
|
+
const on = (e) => setNarrow(e.matches);
|
|
1996
|
+
query.addEventListener("change", on);
|
|
1997
|
+
return () => query.removeEventListener("change", on);
|
|
1998
|
+
}, [query]);
|
|
1999
|
+
return narrow;
|
|
2000
|
+
}
|
|
1189
2001
|
var NAV = [
|
|
1190
2002
|
{ group: "Today", items: [{ page: "attention", label: "Attention" }] },
|
|
1191
2003
|
{
|
|
@@ -1226,15 +2038,21 @@ function AdminShell({
|
|
|
1226
2038
|
auditClient,
|
|
1227
2039
|
environment,
|
|
1228
2040
|
page,
|
|
1229
|
-
onNavigate
|
|
2041
|
+
onNavigate,
|
|
2042
|
+
appName = "Admin",
|
|
2043
|
+
envLabel,
|
|
2044
|
+
footer
|
|
1230
2045
|
}) {
|
|
1231
|
-
const
|
|
2046
|
+
const narrow = useNarrow();
|
|
2047
|
+
const [drawer, setDrawer] = useState6(false);
|
|
2048
|
+
const [own, setOwn] = useState6("attention");
|
|
1232
2049
|
const current = page ?? own;
|
|
1233
2050
|
const go = (p) => {
|
|
1234
2051
|
if (onNavigate) onNavigate(p);
|
|
1235
2052
|
if (page === void 0) setOwn(p);
|
|
2053
|
+
setDrawer(false);
|
|
1236
2054
|
};
|
|
1237
|
-
const [editing, setEditing] =
|
|
2055
|
+
const [editing, setEditing] = useState6(null);
|
|
1238
2056
|
const has = {
|
|
1239
2057
|
config: Boolean(configClient),
|
|
1240
2058
|
courier: Boolean(courierClient),
|
|
@@ -1245,45 +2063,48 @@ function AdminShell({
|
|
|
1245
2063
|
let body;
|
|
1246
2064
|
switch (current) {
|
|
1247
2065
|
case "attention":
|
|
1248
|
-
body = /* @__PURE__ */
|
|
2066
|
+
body = /* @__PURE__ */ jsx14(AttentionScreen, { client });
|
|
1249
2067
|
break;
|
|
1250
2068
|
case "modules":
|
|
1251
|
-
body = /* @__PURE__ */
|
|
2069
|
+
body = /* @__PURE__ */ jsx14(ModulesScreen, { client });
|
|
1252
2070
|
break;
|
|
1253
2071
|
case "doctor":
|
|
1254
|
-
body = /* @__PURE__ */
|
|
2072
|
+
body = /* @__PURE__ */ jsx14(DoctorScreen, { client });
|
|
1255
2073
|
break;
|
|
1256
2074
|
case "environment":
|
|
1257
|
-
body = /* @__PURE__ */
|
|
2075
|
+
body = /* @__PURE__ */ jsx14(EnvironmentScreen, { client });
|
|
1258
2076
|
break;
|
|
1259
2077
|
case "routes":
|
|
1260
|
-
body = /* @__PURE__ */
|
|
2078
|
+
body = /* @__PURE__ */ jsx14(RoutesScreen, { client });
|
|
1261
2079
|
break;
|
|
1262
2080
|
case "tokens":
|
|
1263
|
-
body = /* @__PURE__ */
|
|
2081
|
+
body = /* @__PURE__ */ jsx14(TokensScreen, { client });
|
|
1264
2082
|
break;
|
|
1265
2083
|
case "migrations":
|
|
1266
|
-
body = /* @__PURE__ */
|
|
2084
|
+
body = /* @__PURE__ */ jsx14(MigrationsScreen, { client });
|
|
1267
2085
|
break;
|
|
1268
2086
|
case "log":
|
|
1269
|
-
body = /* @__PURE__ */
|
|
2087
|
+
body = /* @__PURE__ */ jsx14(AdminLogScreen, { client });
|
|
1270
2088
|
break;
|
|
1271
2089
|
case "catalog":
|
|
1272
|
-
body = billingClient ? /* @__PURE__ */
|
|
2090
|
+
body = billingClient ? /* @__PURE__ */ jsx14(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ jsx14("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a BillingAdminClient to see the catalog here." });
|
|
1273
2091
|
break;
|
|
1274
2092
|
case "subscriber":
|
|
1275
|
-
body = billingClient ? /* @__PURE__ */
|
|
2093
|
+
body = billingClient ? /* @__PURE__ */ jsx14(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ jsx14("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a BillingAdminClient to look up subscribers here." });
|
|
1276
2094
|
break;
|
|
1277
2095
|
case "audit":
|
|
1278
|
-
body = auditClient ? /* @__PURE__ */
|
|
2096
|
+
body = auditClient ? /* @__PURE__ */ jsx14(AuditScreen, { client: auditClient }) : /* @__PURE__ */ jsx14("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass an AuditAdminClient to see the audit trail here." });
|
|
1279
2097
|
break;
|
|
1280
2098
|
case "users":
|
|
1281
|
-
body = authClient ? /* @__PURE__ */
|
|
2099
|
+
body = authClient ? /* @__PURE__ */ jsx14(UsersScreen, { client: authClient }) : /* @__PURE__ */ jsx14("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass an AuthAdminClient to look up users here." });
|
|
1282
2100
|
break;
|
|
1283
2101
|
case "settings":
|
|
1284
|
-
body = !configClient ? /* @__PURE__ */
|
|
1285
|
-
/* @__PURE__ */
|
|
1286
|
-
|
|
2102
|
+
body = !configClient ? /* @__PURE__ */ jsx14("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ jsxs14(Fragment8, { children: [
|
|
2103
|
+
/* @__PURE__ */ jsx14("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ jsxs14("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
|
|
2104
|
+
/* @__PURE__ */ jsx14(Icon, { name: "back", size: 14 }),
|
|
2105
|
+
"Config & secrets"
|
|
2106
|
+
] }) }),
|
|
2107
|
+
/* @__PURE__ */ jsx14(
|
|
1287
2108
|
ConfigEditorScreen,
|
|
1288
2109
|
{
|
|
1289
2110
|
client: configClient,
|
|
@@ -1293,7 +2114,7 @@ function AdminShell({
|
|
|
1293
2114
|
onSaved: () => setEditing(null)
|
|
1294
2115
|
}
|
|
1295
2116
|
)
|
|
1296
|
-
] }) : /* @__PURE__ */
|
|
2117
|
+
] }) : /* @__PURE__ */ jsx14(
|
|
1297
2118
|
ConfigListScreen,
|
|
1298
2119
|
{
|
|
1299
2120
|
client: configClient,
|
|
@@ -1306,9 +2127,12 @@ function AdminShell({
|
|
|
1306
2127
|
);
|
|
1307
2128
|
break;
|
|
1308
2129
|
case "templates":
|
|
1309
|
-
body = !courierClient ? /* @__PURE__ */
|
|
1310
|
-
/* @__PURE__ */
|
|
1311
|
-
|
|
2130
|
+
body = !courierClient ? /* @__PURE__ */ jsx14("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ jsxs14(Fragment8, { children: [
|
|
2131
|
+
/* @__PURE__ */ jsx14("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ jsxs14("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
|
|
2132
|
+
/* @__PURE__ */ jsx14(Icon, { name: "back", size: 14 }),
|
|
2133
|
+
"Templates"
|
|
2134
|
+
] }) }),
|
|
2135
|
+
/* @__PURE__ */ jsx14(
|
|
1312
2136
|
TemplateEditorScreen,
|
|
1313
2137
|
{
|
|
1314
2138
|
client: courierClient,
|
|
@@ -1316,7 +2140,7 @@ function AdminShell({
|
|
|
1316
2140
|
onSaved: () => setEditing(null)
|
|
1317
2141
|
}
|
|
1318
2142
|
)
|
|
1319
|
-
] }) : /* @__PURE__ */
|
|
2143
|
+
] }) : /* @__PURE__ */ jsx14(
|
|
1320
2144
|
TemplateListScreen,
|
|
1321
2145
|
{
|
|
1322
2146
|
client: courierClient,
|
|
@@ -1325,29 +2149,105 @@ function AdminShell({
|
|
|
1325
2149
|
);
|
|
1326
2150
|
break;
|
|
1327
2151
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
2152
|
+
const production = envLabel ? /^prod/i.test(envLabel) : false;
|
|
2153
|
+
const brand = /* @__PURE__ */ jsxs14("div", { style: styles.navBrand, children: [
|
|
2154
|
+
/* @__PURE__ */ jsx14("div", { style: styles.navMark, children: /* @__PURE__ */ jsx14(Icon, { name: "mark", size: 15 }) }),
|
|
2155
|
+
/* @__PURE__ */ jsxs14("div", { style: { minWidth: 0, flex: 1 }, children: [
|
|
2156
|
+
/* @__PURE__ */ jsx14("div", { style: styles.navBrandTitle, children: appName }),
|
|
2157
|
+
envLabel ? /* @__PURE__ */ jsx14(
|
|
2158
|
+
"span",
|
|
2159
|
+
{
|
|
2160
|
+
style: {
|
|
2161
|
+
...styles.badge,
|
|
2162
|
+
marginTop: 3,
|
|
2163
|
+
padding: "0 7px",
|
|
2164
|
+
fontSize: 11,
|
|
2165
|
+
...production ? {
|
|
2166
|
+
color: "var(--fonderie-danger,#e00)",
|
|
2167
|
+
borderColor: "color-mix(in srgb, var(--fonderie-danger,#e00) 35%, transparent)"
|
|
2168
|
+
} : {}
|
|
2169
|
+
},
|
|
2170
|
+
children: envLabel
|
|
2171
|
+
}
|
|
2172
|
+
) : null
|
|
2173
|
+
] }),
|
|
2174
|
+
narrow ? /* @__PURE__ */ jsx14(
|
|
2175
|
+
"button",
|
|
2176
|
+
{
|
|
2177
|
+
type: "button",
|
|
2178
|
+
style: styles.buttonGhost,
|
|
2179
|
+
"aria-label": "Close menu",
|
|
2180
|
+
onClick: () => setDrawer(false),
|
|
2181
|
+
children: /* @__PURE__ */ jsx14(Icon, { name: "close" })
|
|
2182
|
+
}
|
|
2183
|
+
) : null
|
|
2184
|
+
] });
|
|
2185
|
+
const nav = /* @__PURE__ */ jsxs14(
|
|
2186
|
+
"nav",
|
|
2187
|
+
{
|
|
2188
|
+
style: {
|
|
2189
|
+
...styles.nav,
|
|
2190
|
+
...narrow ? { width: 280, maxWidth: "85vw", boxShadow: "0 10px 40px rgba(0,0,0,.25)" } : {}
|
|
2191
|
+
},
|
|
2192
|
+
"aria-label": "Admin",
|
|
2193
|
+
children: [
|
|
2194
|
+
brand,
|
|
2195
|
+
/* @__PURE__ */ jsx14("div", { style: styles.navScroll, children: NAV.map((g) => {
|
|
2196
|
+
const items = g.items.filter((i) => !i.needs || has[i.needs]);
|
|
2197
|
+
if (items.length === 0) return null;
|
|
2198
|
+
return /* @__PURE__ */ jsxs14("div", { children: [
|
|
2199
|
+
/* @__PURE__ */ jsx14("div", { style: styles.navGroup, children: g.group }),
|
|
2200
|
+
items.map((i) => {
|
|
2201
|
+
const active = current === i.page;
|
|
2202
|
+
return /* @__PURE__ */ jsxs14(
|
|
2203
|
+
"button",
|
|
2204
|
+
{
|
|
2205
|
+
type: "button",
|
|
2206
|
+
className: "fonderie-admin-nav-item",
|
|
2207
|
+
style: { ...styles.navItem, ...active ? styles.navItemActive : {} },
|
|
2208
|
+
"aria-current": active ? "page" : void 0,
|
|
2209
|
+
onClick: () => {
|
|
2210
|
+
setEditing(null);
|
|
2211
|
+
go(i.page);
|
|
2212
|
+
},
|
|
2213
|
+
children: [
|
|
2214
|
+
/* @__PURE__ */ jsx14(Icon, { name: ICON[i.page], style: active ? styles.navIconActive : void 0 }),
|
|
2215
|
+
i.label
|
|
2216
|
+
]
|
|
2217
|
+
},
|
|
2218
|
+
i.page
|
|
2219
|
+
);
|
|
2220
|
+
})
|
|
2221
|
+
] }, g.group);
|
|
2222
|
+
}) }),
|
|
2223
|
+
footer ? /* @__PURE__ */ jsx14("div", { style: styles.navFooter, children: footer }) : null
|
|
2224
|
+
]
|
|
2225
|
+
}
|
|
2226
|
+
);
|
|
2227
|
+
const title = NAV.flatMap((g) => g.items).find((i) => i.page === current)?.label ?? "";
|
|
2228
|
+
return /* @__PURE__ */ jsxs14("div", { style: { ...styles.shell, ...narrow ? { flexDirection: "column" } : {} }, children: [
|
|
2229
|
+
narrow ? /* @__PURE__ */ jsxs14(Fragment8, { children: [
|
|
2230
|
+
/* @__PURE__ */ jsxs14("div", { style: styles.topbar, children: [
|
|
2231
|
+
/* @__PURE__ */ jsx14(
|
|
1335
2232
|
"button",
|
|
1336
2233
|
{
|
|
1337
2234
|
type: "button",
|
|
1338
|
-
style:
|
|
1339
|
-
"aria-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
2235
|
+
style: styles.buttonGhost,
|
|
2236
|
+
"aria-label": "Open menu",
|
|
2237
|
+
"aria-expanded": drawer,
|
|
2238
|
+
onClick: () => setDrawer(true),
|
|
2239
|
+
children: /* @__PURE__ */ jsx14(Icon, { name: "menu" })
|
|
2240
|
+
}
|
|
2241
|
+
),
|
|
2242
|
+
/* @__PURE__ */ jsx14("span", { style: { fontWeight: 600, fontSize: 14 }, children: title }),
|
|
2243
|
+
envLabel ? /* @__PURE__ */ jsx14("span", { style: { ...styles.badge, marginLeft: "auto" }, children: envLabel }) : null
|
|
2244
|
+
] }),
|
|
2245
|
+
drawer ? /* @__PURE__ */ jsxs14("div", { style: styles.drawer, children: [
|
|
2246
|
+
nav,
|
|
2247
|
+
/* @__PURE__ */ jsx14("div", { style: styles.scrim, onClick: () => setDrawer(false), "aria-hidden": "true" })
|
|
2248
|
+
] }) : null
|
|
2249
|
+
] }) : nav,
|
|
2250
|
+
/* @__PURE__ */ jsx14("main", { className: "fonderie-admin-main", style: styles.main, children: body })
|
|
1351
2251
|
] });
|
|
1352
2252
|
}
|
|
1353
2253
|
export {
|