@fonderie/vue-admin-screens 1.1.0 → 1.2.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 +494 -203
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -2
- package/dist/index.d.ts +44 -2
- package/dist/index.js +475 -185
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -29,6 +29,7 @@ __export(index_exports, {
|
|
|
29
29
|
EnvironmentScreen: () => EnvironmentScreen,
|
|
30
30
|
MigrationsScreen: () => MigrationsScreen,
|
|
31
31
|
ModulesScreen: () => ModulesScreen,
|
|
32
|
+
OperatorsScreen: () => OperatorsScreen,
|
|
32
33
|
RoutesScreen: () => RoutesScreen,
|
|
33
34
|
SubscriberScreen: () => SubscriberScreen,
|
|
34
35
|
TokensScreen: () => TokensScreen,
|
|
@@ -39,7 +40,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
39
40
|
// src/screens/AdminShell.ts
|
|
40
41
|
var import_vue_config_admin_screens = require("@fonderie/vue-config-admin-screens");
|
|
41
42
|
var import_vue_courier_admin_screens = require("@fonderie/vue-courier-admin-screens");
|
|
42
|
-
var
|
|
43
|
+
var import_vue16 = require("vue");
|
|
43
44
|
|
|
44
45
|
// src/styles.ts
|
|
45
46
|
var t = {
|
|
@@ -1205,42 +1206,319 @@ var MigrationsScreen = (0, import_vue9.defineComponent)({
|
|
|
1205
1206
|
}
|
|
1206
1207
|
});
|
|
1207
1208
|
|
|
1208
|
-
// src/screens/
|
|
1209
|
+
// src/screens/OperatorsScreen.ts
|
|
1209
1210
|
var import_vue_admin8 = require("@fonderie/vue-admin");
|
|
1210
1211
|
var import_vue10 = require("vue");
|
|
1212
|
+
var LEVELS = [
|
|
1213
|
+
{ label: "Read only", scopes: ["read"], hint: "look around, change nothing" },
|
|
1214
|
+
{ label: "Editor", scopes: ["read", "write"], hint: "change config, templates, users" },
|
|
1215
|
+
{
|
|
1216
|
+
label: "Owner",
|
|
1217
|
+
scopes: ["read", "write", "secrets"],
|
|
1218
|
+
hint: "secrets, tokens and operators too"
|
|
1219
|
+
}
|
|
1220
|
+
];
|
|
1221
|
+
var levelOf = (scopes) => scopes.includes("secrets") ? "Owner" : scopes.includes("write") ? "Editor" : "Read only";
|
|
1222
|
+
var scopesFor = (label) => LEVELS.find((l) => l.label === label)?.scopes ?? ["read"];
|
|
1223
|
+
var small = { height: "28px" };
|
|
1224
|
+
var OperatorsScreen = (0, import_vue10.defineComponent)({
|
|
1225
|
+
name: "FonderieOperatorsScreen",
|
|
1226
|
+
props: {
|
|
1227
|
+
client: { type: Object, required: true },
|
|
1228
|
+
// The signed-in operator's email: their own row offers no disable or
|
|
1229
|
+
// recovery (the server refuses both for yourself anyway).
|
|
1230
|
+
me: { type: String, default: void 0 }
|
|
1231
|
+
},
|
|
1232
|
+
setup(props) {
|
|
1233
|
+
const { report, isLoading, error, invite, recover, update, revokeLink } = (0, import_vue_admin8.useAdminOperators)(
|
|
1234
|
+
props.client
|
|
1235
|
+
);
|
|
1236
|
+
const email = (0, import_vue10.ref)("");
|
|
1237
|
+
const level = (0, import_vue10.ref)("Editor");
|
|
1238
|
+
const minted = (0, import_vue10.ref)(null);
|
|
1239
|
+
const copied = (0, import_vue10.ref)(false);
|
|
1240
|
+
const status = (o) => o.disabledAt ? pill("neutral", "disabled") : o.locked ? pill("warn", "locked") : !o.enrolled ? pill("warn", "setting up") : pill("ok", "active");
|
|
1241
|
+
const mintedNotice = (link) => {
|
|
1242
|
+
const url = `${window.location.origin}${link.url}`;
|
|
1243
|
+
return (0, import_vue10.h)(
|
|
1244
|
+
"div",
|
|
1245
|
+
{
|
|
1246
|
+
style: {
|
|
1247
|
+
...styles.notice,
|
|
1248
|
+
background: "color-mix(in srgb, var(--fonderie-accent,#00d294) 10%, transparent)",
|
|
1249
|
+
borderColor: "color-mix(in srgb, var(--fonderie-accent,#00d294) 35%, transparent)"
|
|
1250
|
+
}
|
|
1251
|
+
},
|
|
1252
|
+
[
|
|
1253
|
+
(0, import_vue10.h)("strong", `Send this link to ${link.email}. It is shown once.`),
|
|
1254
|
+
` It works once and expires ${new Date(link.expiresAt).toLocaleString()}.`,
|
|
1255
|
+
(0, import_vue10.h)(
|
|
1256
|
+
"div",
|
|
1257
|
+
{ style: { display: "flex", gap: "8px", marginTop: "8px", alignItems: "center" } },
|
|
1258
|
+
[
|
|
1259
|
+
(0, import_vue10.h)(
|
|
1260
|
+
"code",
|
|
1261
|
+
{ style: { ...styles.code, flex: 1, padding: "7px 10px", wordBreak: "break-all" } },
|
|
1262
|
+
url
|
|
1263
|
+
),
|
|
1264
|
+
(0, import_vue10.h)(
|
|
1265
|
+
"button",
|
|
1266
|
+
{
|
|
1267
|
+
type: "button",
|
|
1268
|
+
style: styles.button,
|
|
1269
|
+
onClick: () => {
|
|
1270
|
+
void navigator.clipboard?.writeText(url);
|
|
1271
|
+
copied.value = true;
|
|
1272
|
+
}
|
|
1273
|
+
},
|
|
1274
|
+
copied.value ? "Copied" : "Copy"
|
|
1275
|
+
),
|
|
1276
|
+
(0, import_vue10.h)(
|
|
1277
|
+
"button",
|
|
1278
|
+
{
|
|
1279
|
+
type: "button",
|
|
1280
|
+
style: styles.buttonGhost,
|
|
1281
|
+
"aria-label": "Dismiss",
|
|
1282
|
+
onClick: () => {
|
|
1283
|
+
minted.value = null;
|
|
1284
|
+
copied.value = false;
|
|
1285
|
+
}
|
|
1286
|
+
},
|
|
1287
|
+
[icon("close", 14)]
|
|
1288
|
+
)
|
|
1289
|
+
]
|
|
1290
|
+
)
|
|
1291
|
+
]
|
|
1292
|
+
);
|
|
1293
|
+
};
|
|
1294
|
+
const setMinted = (l) => {
|
|
1295
|
+
copied.value = false;
|
|
1296
|
+
minted.value = l;
|
|
1297
|
+
};
|
|
1298
|
+
return () => {
|
|
1299
|
+
const r = report.value;
|
|
1300
|
+
const e = error.value;
|
|
1301
|
+
return (0, import_vue10.h)("div", { style: styles.container }, [
|
|
1302
|
+
pageHeader(
|
|
1303
|
+
"Operators",
|
|
1304
|
+
"The people who can sign in to this console. Each one uses a password and an authenticator app; there is no sign-up."
|
|
1305
|
+
),
|
|
1306
|
+
e ? (0, import_vue10.h)(
|
|
1307
|
+
"p",
|
|
1308
|
+
{ style: styles.error, role: "alert" },
|
|
1309
|
+
e.status === 403 && e.reason === "FORBIDDEN" ? "Managing operators needs the Owner level." : e.explanation
|
|
1310
|
+
) : null,
|
|
1311
|
+
minted.value ? mintedNotice(minted.value) : null,
|
|
1312
|
+
(0, import_vue10.h)(
|
|
1313
|
+
"form",
|
|
1314
|
+
{
|
|
1315
|
+
style: {
|
|
1316
|
+
...styles.card,
|
|
1317
|
+
display: "flex",
|
|
1318
|
+
gap: "8px",
|
|
1319
|
+
alignItems: "center",
|
|
1320
|
+
flexWrap: "wrap",
|
|
1321
|
+
marginBottom: "20px"
|
|
1322
|
+
},
|
|
1323
|
+
onSubmit: (ev) => {
|
|
1324
|
+
ev.preventDefault();
|
|
1325
|
+
void invite({ email: email.value.trim(), scopes: scopesFor(level.value) }).then((l) => {
|
|
1326
|
+
setMinted(l);
|
|
1327
|
+
email.value = "";
|
|
1328
|
+
}).catch(() => {
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
},
|
|
1332
|
+
[
|
|
1333
|
+
icon("users", 16),
|
|
1334
|
+
(0, import_vue10.h)("strong", { style: { fontSize: "13.5px", marginRight: "4px" } }, "Invite"),
|
|
1335
|
+
(0, import_vue10.h)("input", {
|
|
1336
|
+
type: "email",
|
|
1337
|
+
required: true,
|
|
1338
|
+
value: email.value,
|
|
1339
|
+
onInput: (ev) => email.value = ev.target.value,
|
|
1340
|
+
placeholder: "teammate@company.com",
|
|
1341
|
+
style: { ...styles.input, flex: 1, minWidth: "220px" },
|
|
1342
|
+
"aria-label": "Email to invite"
|
|
1343
|
+
}),
|
|
1344
|
+
(0, import_vue10.h)(
|
|
1345
|
+
"select",
|
|
1346
|
+
{
|
|
1347
|
+
value: level.value,
|
|
1348
|
+
onChange: (ev) => level.value = ev.target.value,
|
|
1349
|
+
style: styles.input,
|
|
1350
|
+
"aria-label": "Access level"
|
|
1351
|
+
},
|
|
1352
|
+
LEVELS.map(
|
|
1353
|
+
(l) => (0, import_vue10.h)("option", { key: l.label, value: l.label }, `${l.label} \u2014 ${l.hint}`)
|
|
1354
|
+
)
|
|
1355
|
+
),
|
|
1356
|
+
(0, import_vue10.h)(
|
|
1357
|
+
"button",
|
|
1358
|
+
{ type: "submit", style: styles.buttonPrimary, disabled: !email.value.trim() },
|
|
1359
|
+
[icon("plus", 14), "Create invite link"]
|
|
1360
|
+
)
|
|
1361
|
+
]
|
|
1362
|
+
),
|
|
1363
|
+
isLoading.value && !r ? (0, import_vue10.h)("p", { style: styles.status }, "Loading\u2026") : r && r.operators.length === 0 ? empty("No operators yet", void 0, "users") : r ? table(
|
|
1364
|
+
["Operator", "Access", "Status", "Last sign-in", ""],
|
|
1365
|
+
r.operators.map((o) => {
|
|
1366
|
+
const mine = o.email === props.me;
|
|
1367
|
+
return (0, import_vue10.h)("tr", { key: o.id }, [
|
|
1368
|
+
td([
|
|
1369
|
+
(0, import_vue10.h)("div", { style: { fontWeight: 600 } }, o.name || o.email),
|
|
1370
|
+
o.name ? (0, import_vue10.h)("div", { style: styles.muted }, o.email) : null
|
|
1371
|
+
]),
|
|
1372
|
+
td(
|
|
1373
|
+
(0, import_vue10.h)(
|
|
1374
|
+
"select",
|
|
1375
|
+
{
|
|
1376
|
+
value: levelOf(o.scopes),
|
|
1377
|
+
disabled: mine,
|
|
1378
|
+
onChange: (ev) => void update(o.id, {
|
|
1379
|
+
scopes: scopesFor(ev.target.value)
|
|
1380
|
+
}).catch(() => {
|
|
1381
|
+
}),
|
|
1382
|
+
style: { ...styles.input, ...small, fontSize: "12.5px" },
|
|
1383
|
+
"aria-label": `Access level for ${o.email}`
|
|
1384
|
+
},
|
|
1385
|
+
LEVELS.map((l) => (0, import_vue10.h)("option", { key: l.label, value: l.label }, l.label))
|
|
1386
|
+
)
|
|
1387
|
+
),
|
|
1388
|
+
td([
|
|
1389
|
+
status(o),
|
|
1390
|
+
o.enrolled && o.backupCodesLeft <= 2 && !o.disabledAt ? (0, import_vue10.h)(
|
|
1391
|
+
"div",
|
|
1392
|
+
{ style: { ...styles.muted, marginTop: "4px" } },
|
|
1393
|
+
`${o.backupCodesLeft} backup code(s) left`
|
|
1394
|
+
) : null
|
|
1395
|
+
]),
|
|
1396
|
+
td(o.lastLoginAt ? new Date(o.lastLoginAt).toLocaleString() : "never", {
|
|
1397
|
+
...styles.muted,
|
|
1398
|
+
whiteSpace: "nowrap"
|
|
1399
|
+
}),
|
|
1400
|
+
td(
|
|
1401
|
+
mine ? (0, import_vue10.h)("span", { style: styles.muted }, "you") : [
|
|
1402
|
+
(0, import_vue10.h)(
|
|
1403
|
+
"button",
|
|
1404
|
+
{
|
|
1405
|
+
type: "button",
|
|
1406
|
+
style: { ...styles.button, ...small, marginRight: "6px" },
|
|
1407
|
+
onClick: () => {
|
|
1408
|
+
if (window.confirm(
|
|
1409
|
+
`Create a recovery link for ${o.email}? It signs them out everywhere; the link sets a new password and a new authenticator.`
|
|
1410
|
+
))
|
|
1411
|
+
void recover(o.id).then(setMinted).catch(() => {
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
"Recovery link"
|
|
1416
|
+
),
|
|
1417
|
+
(0, import_vue10.h)(
|
|
1418
|
+
"button",
|
|
1419
|
+
{
|
|
1420
|
+
type: "button",
|
|
1421
|
+
style: {
|
|
1422
|
+
...o.disabledAt ? styles.button : styles.buttonDanger,
|
|
1423
|
+
...small
|
|
1424
|
+
},
|
|
1425
|
+
onClick: () => {
|
|
1426
|
+
if (o.disabledAt || window.confirm(
|
|
1427
|
+
`Disable ${o.email}? They are signed out immediately.`
|
|
1428
|
+
))
|
|
1429
|
+
void update(o.id, { disabled: !o.disabledAt }).catch(
|
|
1430
|
+
() => {
|
|
1431
|
+
}
|
|
1432
|
+
);
|
|
1433
|
+
}
|
|
1434
|
+
},
|
|
1435
|
+
o.disabledAt ? "Enable" : "Disable"
|
|
1436
|
+
)
|
|
1437
|
+
],
|
|
1438
|
+
{ textAlign: "right", whiteSpace: "nowrap" }
|
|
1439
|
+
)
|
|
1440
|
+
]);
|
|
1441
|
+
})
|
|
1442
|
+
) : null,
|
|
1443
|
+
r && r.links.length > 0 ? [
|
|
1444
|
+
(0, import_vue10.h)("h2", { style: styles.subtitle }, "Pending links"),
|
|
1445
|
+
(0, import_vue10.h)(
|
|
1446
|
+
"ul",
|
|
1447
|
+
{ style: styles.list },
|
|
1448
|
+
r.links.map(
|
|
1449
|
+
(l) => (0, import_vue10.h)(
|
|
1450
|
+
"li",
|
|
1451
|
+
{
|
|
1452
|
+
key: l.id,
|
|
1453
|
+
style: { ...styles.row, display: "flex", gap: "12px", alignItems: "center" }
|
|
1454
|
+
},
|
|
1455
|
+
[
|
|
1456
|
+
pill(l.kind === "invite" ? "info" : "warn", l.kind, false),
|
|
1457
|
+
(0, import_vue10.h)("span", { style: { flex: 1 } }, [
|
|
1458
|
+
l.email,
|
|
1459
|
+
l.kind === "invite" ? (0, import_vue10.h)("span", { style: styles.muted }, ` \xB7 ${levelOf(l.scopes)}`) : null
|
|
1460
|
+
]),
|
|
1461
|
+
(0, import_vue10.h)(
|
|
1462
|
+
"span",
|
|
1463
|
+
{ style: styles.muted },
|
|
1464
|
+
`expires ${new Date(l.expiresAt).toLocaleString()}`
|
|
1465
|
+
),
|
|
1466
|
+
(0, import_vue10.h)(
|
|
1467
|
+
"button",
|
|
1468
|
+
{
|
|
1469
|
+
type: "button",
|
|
1470
|
+
style: { ...styles.buttonDanger, ...small },
|
|
1471
|
+
onClick: () => void revokeLink(l.id).catch(() => {
|
|
1472
|
+
})
|
|
1473
|
+
},
|
|
1474
|
+
"Revoke"
|
|
1475
|
+
)
|
|
1476
|
+
]
|
|
1477
|
+
)
|
|
1478
|
+
)
|
|
1479
|
+
)
|
|
1480
|
+
] : null
|
|
1481
|
+
]);
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1485
|
+
|
|
1486
|
+
// src/screens/TokensScreen.ts
|
|
1487
|
+
var import_vue_admin9 = require("@fonderie/vue-admin");
|
|
1488
|
+
var import_vue11 = require("vue");
|
|
1211
1489
|
var ALL = ["read", "write", "secrets"];
|
|
1212
|
-
var TokensScreen = (0,
|
|
1490
|
+
var TokensScreen = (0, import_vue11.defineComponent)({
|
|
1213
1491
|
name: "FonderieTokensScreen",
|
|
1214
1492
|
props: { client: { type: Object, required: true } },
|
|
1215
1493
|
setup(props) {
|
|
1216
|
-
const { report, isLoading, error, issue, revoke } = (0,
|
|
1217
|
-
const name = (0,
|
|
1218
|
-
const scopes = (0,
|
|
1219
|
-
const days = (0,
|
|
1220
|
-
const minted = (0,
|
|
1494
|
+
const { report, isLoading, error, issue, revoke } = (0, import_vue_admin9.useAdminTokens)(props.client);
|
|
1495
|
+
const name = (0, import_vue11.ref)("");
|
|
1496
|
+
const scopes = (0, import_vue11.ref)(["read"]);
|
|
1497
|
+
const days = (0, import_vue11.ref)("");
|
|
1498
|
+
const minted = (0, import_vue11.ref)(null);
|
|
1221
1499
|
const toggle = (s) => scopes.value = scopes.value.includes(s) ? scopes.value.filter((x) => x !== s) : [...scopes.value, s];
|
|
1222
1500
|
return () => {
|
|
1223
1501
|
const r = report.value;
|
|
1224
|
-
return (0,
|
|
1502
|
+
return (0, import_vue11.h)("div", { style: styles.container }, [
|
|
1225
1503
|
pageHeader(
|
|
1226
|
-
"
|
|
1227
|
-
"
|
|
1504
|
+
"Tokens",
|
|
1505
|
+
"Credentials for machines: the root token's strength, scoped tokens for the CLI and CI, and any legacy per-module tokens. People sign in as operators."
|
|
1228
1506
|
),
|
|
1229
|
-
error.value ? (0,
|
|
1507
|
+
error.value ? (0, import_vue11.h)(
|
|
1230
1508
|
"p",
|
|
1231
1509
|
{ style: styles.error, role: "alert" },
|
|
1232
1510
|
error.value.status === 401 ? "Issuing and revoking need the root token (the one in your deployment config)." : error.value.explanation
|
|
1233
1511
|
) : null,
|
|
1234
|
-
(0,
|
|
1235
|
-
r ? (0,
|
|
1512
|
+
(0, import_vue11.h)("h2", { style: { ...styles.subtitle, marginTop: 0 } }, "Root token"),
|
|
1513
|
+
r ? (0, import_vue11.h)(
|
|
1236
1514
|
"div",
|
|
1237
1515
|
{ style: { ...styles.card, display: "flex", gap: "12px", alignItems: "flex-start" } },
|
|
1238
1516
|
[
|
|
1239
1517
|
icon("lock", 18, { marginTop: "2px" }),
|
|
1240
|
-
(0,
|
|
1518
|
+
(0, import_vue11.h)("div", [
|
|
1241
1519
|
pill(r.admin.ok ? "ok" : "bad", r.admin.ok ? "strong" : "weak"),
|
|
1242
1520
|
...r.admin.problems.map(
|
|
1243
|
-
(p) => (0,
|
|
1521
|
+
(p) => (0, import_vue11.h)(
|
|
1244
1522
|
"div",
|
|
1245
1523
|
{
|
|
1246
1524
|
key: p.message,
|
|
@@ -1256,13 +1534,13 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1256
1534
|
])
|
|
1257
1535
|
]
|
|
1258
1536
|
) : null,
|
|
1259
|
-
(0,
|
|
1260
|
-
r?.issued === null ? (0,
|
|
1537
|
+
(0, import_vue11.h)("h2", { style: styles.subtitle }, "Issued tokens"),
|
|
1538
|
+
r?.issued === null ? (0, import_vue11.h)(
|
|
1261
1539
|
"p",
|
|
1262
1540
|
{ style: styles.muted },
|
|
1263
1541
|
"Issuing is off \u2014 give AdminModule a store and run its migrations."
|
|
1264
1542
|
) : [
|
|
1265
|
-
minted.value ? (0,
|
|
1543
|
+
minted.value ? (0, import_vue11.h)(
|
|
1266
1544
|
"div",
|
|
1267
1545
|
{
|
|
1268
1546
|
style: {
|
|
@@ -1272,9 +1550,9 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1272
1550
|
}
|
|
1273
1551
|
},
|
|
1274
1552
|
[
|
|
1275
|
-
(0,
|
|
1553
|
+
(0, import_vue11.h)("strong", "Copy this now \u2014 it is never shown again."),
|
|
1276
1554
|
` (${minted.value.name})`,
|
|
1277
|
-
(0,
|
|
1555
|
+
(0, import_vue11.h)(
|
|
1278
1556
|
"div",
|
|
1279
1557
|
{
|
|
1280
1558
|
style: {
|
|
@@ -1289,7 +1567,7 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1289
1567
|
)
|
|
1290
1568
|
]
|
|
1291
1569
|
) : null,
|
|
1292
|
-
(0,
|
|
1570
|
+
(0, import_vue11.h)(
|
|
1293
1571
|
"form",
|
|
1294
1572
|
{
|
|
1295
1573
|
style: styles.toolbar,
|
|
@@ -1309,7 +1587,7 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1309
1587
|
}
|
|
1310
1588
|
},
|
|
1311
1589
|
[
|
|
1312
|
-
(0,
|
|
1590
|
+
(0, import_vue11.h)("input", {
|
|
1313
1591
|
value: name.value,
|
|
1314
1592
|
onInput: (e) => name.value = e.target.value,
|
|
1315
1593
|
placeholder: "name",
|
|
@@ -1317,7 +1595,7 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1317
1595
|
"aria-label": "Name"
|
|
1318
1596
|
}),
|
|
1319
1597
|
...ALL.map(
|
|
1320
|
-
(s) => (0,
|
|
1598
|
+
(s) => (0, import_vue11.h)(
|
|
1321
1599
|
"label",
|
|
1322
1600
|
{
|
|
1323
1601
|
key: s,
|
|
@@ -1331,7 +1609,7 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1331
1609
|
}
|
|
1332
1610
|
},
|
|
1333
1611
|
[
|
|
1334
|
-
(0,
|
|
1612
|
+
(0, import_vue11.h)("input", {
|
|
1335
1613
|
type: "checkbox",
|
|
1336
1614
|
checked: scopes.value.includes(s),
|
|
1337
1615
|
onChange: () => toggle(s)
|
|
@@ -1340,14 +1618,14 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1340
1618
|
]
|
|
1341
1619
|
)
|
|
1342
1620
|
),
|
|
1343
|
-
(0,
|
|
1621
|
+
(0, import_vue11.h)("input", {
|
|
1344
1622
|
value: days.value,
|
|
1345
1623
|
onInput: (e) => days.value = e.target.value,
|
|
1346
1624
|
placeholder: "days (optional)",
|
|
1347
1625
|
style: { ...styles.input, width: "140px" },
|
|
1348
1626
|
"aria-label": "Days"
|
|
1349
1627
|
}),
|
|
1350
|
-
(0,
|
|
1628
|
+
(0, import_vue11.h)(
|
|
1351
1629
|
"button",
|
|
1352
1630
|
{
|
|
1353
1631
|
type: "submit",
|
|
@@ -1361,7 +1639,7 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1361
1639
|
r?.issued && r.issued.length > 0 ? table(
|
|
1362
1640
|
["Name", "Scopes", "Created", "Expires", "Last used", ""],
|
|
1363
1641
|
r.issued.map(
|
|
1364
|
-
(t2) => (0,
|
|
1642
|
+
(t2) => (0, import_vue11.h)("tr", { key: t2.id }, [
|
|
1365
1643
|
td([t2.name, t2.revokedAt ? [" ", pill("neutral", "revoked")] : ""]),
|
|
1366
1644
|
td(t2.scopes.join(", "), styles.mono),
|
|
1367
1645
|
td(
|
|
@@ -1377,7 +1655,7 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1377
1655
|
styles.muted
|
|
1378
1656
|
),
|
|
1379
1657
|
td(
|
|
1380
|
-
t2.revokedAt ? "" : (0,
|
|
1658
|
+
t2.revokedAt ? "" : (0, import_vue11.h)(
|
|
1381
1659
|
"button",
|
|
1382
1660
|
{
|
|
1383
1661
|
type: "button",
|
|
@@ -1401,19 +1679,19 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1401
1679
|
"tokens"
|
|
1402
1680
|
)
|
|
1403
1681
|
],
|
|
1404
|
-
(0,
|
|
1405
|
-
r && r.legacy.length === 0 ? (0,
|
|
1682
|
+
(0, import_vue11.h)("h2", { style: styles.subtitle }, "Legacy per-brick tokens"),
|
|
1683
|
+
r && r.legacy.length === 0 ? (0, import_vue11.h)(
|
|
1406
1684
|
"p",
|
|
1407
1685
|
{ style: styles.muted },
|
|
1408
1686
|
"None \u2014 every brick's admin surface goes through this token."
|
|
1409
|
-
) : (0,
|
|
1687
|
+
) : (0, import_vue11.h)(
|
|
1410
1688
|
"ul",
|
|
1411
1689
|
{ style: styles.list },
|
|
1412
1690
|
(r?.legacy ?? []).map(
|
|
1413
|
-
(l) => (0,
|
|
1414
|
-
(0,
|
|
1691
|
+
(l) => (0, import_vue11.h)("li", { key: l.module, style: styles.row }, [
|
|
1692
|
+
(0, import_vue11.h)("span", { style: styles.mono }, l.module),
|
|
1415
1693
|
" ",
|
|
1416
|
-
(0,
|
|
1694
|
+
(0, import_vue11.h)(
|
|
1417
1695
|
"span",
|
|
1418
1696
|
{ style: styles.muted },
|
|
1419
1697
|
"still registers its standalone routes with its own token (deprecated)"
|
|
@@ -1428,29 +1706,29 @@ var TokensScreen = (0, import_vue10.defineComponent)({
|
|
|
1428
1706
|
|
|
1429
1707
|
// src/screens/UsersScreen.ts
|
|
1430
1708
|
var import_client = require("@fonderie/client");
|
|
1431
|
-
var
|
|
1432
|
-
var
|
|
1433
|
-
var UsersScreen = (0,
|
|
1709
|
+
var import_vue_admin10 = require("@fonderie/vue-admin");
|
|
1710
|
+
var import_vue12 = require("vue");
|
|
1711
|
+
var UsersScreen = (0, import_vue12.defineComponent)({
|
|
1434
1712
|
name: "FonderieUsersScreen",
|
|
1435
1713
|
props: {
|
|
1436
1714
|
client: { type: Object, required: true },
|
|
1437
1715
|
pageSize: { type: Number, default: 50 }
|
|
1438
1716
|
},
|
|
1439
1717
|
setup(props) {
|
|
1440
|
-
const input = (0,
|
|
1441
|
-
const email = (0,
|
|
1442
|
-
const selectedId = (0,
|
|
1443
|
-
const list = (0,
|
|
1444
|
-
const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0,
|
|
1718
|
+
const input = (0, import_vue12.ref)("");
|
|
1719
|
+
const email = (0, import_vue12.ref)("");
|
|
1720
|
+
const selectedId = (0, import_vue12.ref)("");
|
|
1721
|
+
const list = (0, import_vue_admin10.useAdminUsers)(props.client, { limit: props.pageSize });
|
|
1722
|
+
const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0, import_vue_admin10.useAdminUser)(
|
|
1445
1723
|
props.client,
|
|
1446
1724
|
{ email, id: selectedId }
|
|
1447
1725
|
);
|
|
1448
|
-
const userId = (0,
|
|
1449
|
-
const sessions = (0,
|
|
1450
|
-
const history = (0,
|
|
1451
|
-
const showList = (0,
|
|
1726
|
+
const userId = (0, import_vue12.computed)(() => user.value?.id ?? null);
|
|
1727
|
+
const sessions = (0, import_vue_admin10.useAdminUserSessions)(props.client, userId);
|
|
1728
|
+
const history = (0, import_vue_admin10.useAdminLoginHistory)(props.client, userId, { limit: 20 });
|
|
1729
|
+
const showList = (0, import_vue12.computed)(() => !email.value && !selectedId.value);
|
|
1452
1730
|
const yesNo = (v) => v ? pill("ok", "yes") : pill("neutral", "no");
|
|
1453
|
-
const row = (k, v) => (0,
|
|
1731
|
+
const row = (k, v) => (0, import_vue12.h)("tr", [td(k), td(v)]);
|
|
1454
1732
|
const clear = () => {
|
|
1455
1733
|
email.value = "";
|
|
1456
1734
|
selectedId.value = "";
|
|
@@ -1458,12 +1736,12 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1458
1736
|
};
|
|
1459
1737
|
return () => {
|
|
1460
1738
|
const u = user.value;
|
|
1461
|
-
return (0,
|
|
1739
|
+
return (0, import_vue12.h)("div", { style: styles.container }, [
|
|
1462
1740
|
pageHeader(
|
|
1463
1741
|
"Users",
|
|
1464
1742
|
"Everyone signed up. Open an account for its sessions, sign-ins and the suspend and sign-out controls."
|
|
1465
1743
|
),
|
|
1466
|
-
(0,
|
|
1744
|
+
(0, import_vue12.h)(
|
|
1467
1745
|
"form",
|
|
1468
1746
|
{
|
|
1469
1747
|
style: styles.toolbar,
|
|
@@ -1474,7 +1752,7 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1474
1752
|
}
|
|
1475
1753
|
},
|
|
1476
1754
|
[
|
|
1477
|
-
(0,
|
|
1755
|
+
(0, import_vue12.h)("input", {
|
|
1478
1756
|
type: "email",
|
|
1479
1757
|
value: input.value,
|
|
1480
1758
|
onInput: (e) => input.value = e.target.value,
|
|
@@ -1482,7 +1760,7 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1482
1760
|
style: { ...styles.input, minWidth: "280px" },
|
|
1483
1761
|
"aria-label": "Email"
|
|
1484
1762
|
}),
|
|
1485
|
-
(0,
|
|
1763
|
+
(0, import_vue12.h)(
|
|
1486
1764
|
"button",
|
|
1487
1765
|
{ type: "submit", style: styles.buttonPrimary, disabled: isLoading.value },
|
|
1488
1766
|
[icon("search", 14), "Look up"]
|
|
@@ -1490,14 +1768,14 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1490
1768
|
showList.value ? refreshButton("Refresh", list.isLoading.value, () => void list.refresh()) : actionButton([icon("back", 14), "All users"], false, clear, styles.buttonGhost)
|
|
1491
1769
|
]
|
|
1492
1770
|
),
|
|
1493
|
-
showList.value ? (0,
|
|
1494
|
-
list.error.value ? (0,
|
|
1771
|
+
showList.value ? (0, import_vue12.h)("div", [
|
|
1772
|
+
list.error.value ? (0, import_vue12.h)("p", { style: styles.error, role: "alert" }, list.error.value.explanation) : null,
|
|
1495
1773
|
list.users.value.length === 0 && !list.isLoading.value ? empty("No users yet", "Sign-ups appear here as they happen.", "users") : table(
|
|
1496
1774
|
["Email", "Name", "Created", "Status"],
|
|
1497
1775
|
list.users.value.map(
|
|
1498
|
-
(u2) => (0,
|
|
1776
|
+
(u2) => (0, import_vue12.h)("tr", { key: u2.id }, [
|
|
1499
1777
|
td(
|
|
1500
|
-
(0,
|
|
1778
|
+
(0, import_vue12.h)(
|
|
1501
1779
|
"button",
|
|
1502
1780
|
{
|
|
1503
1781
|
type: "button",
|
|
@@ -1508,7 +1786,7 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1508
1786
|
)
|
|
1509
1787
|
),
|
|
1510
1788
|
td(
|
|
1511
|
-
`${u2.firstName ?? ""} ${u2.lastName ?? ""}`.trim() || (0,
|
|
1789
|
+
`${u2.firstName ?? ""} ${u2.lastName ?? ""}`.trim() || (0, import_vue12.h)("span", { style: styles.muted }, "\u2014")
|
|
1512
1790
|
),
|
|
1513
1791
|
td(new Date(u2.createdAt).toLocaleDateString()),
|
|
1514
1792
|
td(
|
|
@@ -1517,24 +1795,24 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1517
1795
|
])
|
|
1518
1796
|
)
|
|
1519
1797
|
),
|
|
1520
|
-
list.isLoading.value ? (0,
|
|
1798
|
+
list.isLoading.value ? (0, import_vue12.h)("p", { style: styles.status }, "Loading\u2026") : null,
|
|
1521
1799
|
list.hasMore.value && !list.isLoading.value ? loadMoreButton(() => void list.loadMore()) : null
|
|
1522
1800
|
]) : null,
|
|
1523
|
-
error.value ? (0,
|
|
1801
|
+
error.value ? (0, import_vue12.h)(
|
|
1524
1802
|
"p",
|
|
1525
1803
|
{ style: styles.error, role: "alert" },
|
|
1526
1804
|
error.value.status === 404 ? "No user with that email." : error.value.explanation
|
|
1527
1805
|
) : null,
|
|
1528
1806
|
u ? [
|
|
1529
|
-
(0,
|
|
1807
|
+
(0, import_vue12.h)("h2", { style: styles.subtitle }, [
|
|
1530
1808
|
u.firstName || u.lastName ? `${u.firstName} ${u.lastName}`.trim() : u.email,
|
|
1531
1809
|
" ",
|
|
1532
1810
|
u.suspended ? pill("warn", "suspended") : null,
|
|
1533
1811
|
u.deletedAt ? pill("neutral", "deleted") : null
|
|
1534
1812
|
]),
|
|
1535
|
-
(0,
|
|
1536
|
-
(0,
|
|
1537
|
-
row("id", (0,
|
|
1813
|
+
(0, import_vue12.h)("table", { style: styles.table }, [
|
|
1814
|
+
(0, import_vue12.h)("tbody", [
|
|
1815
|
+
row("id", (0, import_vue12.h)("span", { style: styles.mono }, u.id)),
|
|
1538
1816
|
row("email", [u.email, " \xB7 verified ", yesNo(u.isEmailVerified)]),
|
|
1539
1817
|
row("MFA", yesNo(u.mfaEnabled)),
|
|
1540
1818
|
row(
|
|
@@ -1543,12 +1821,12 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1543
1821
|
),
|
|
1544
1822
|
row(
|
|
1545
1823
|
"last login",
|
|
1546
|
-
u.lastLogin ? new Date(u.lastLogin).toLocaleString() : (0,
|
|
1824
|
+
u.lastLogin ? new Date(u.lastLogin).toLocaleString() : (0, import_vue12.h)("span", { style: styles.muted }, "never")
|
|
1547
1825
|
),
|
|
1548
1826
|
row("created", new Date(u.createdAt).toLocaleString())
|
|
1549
1827
|
])
|
|
1550
1828
|
]),
|
|
1551
|
-
(0,
|
|
1829
|
+
(0, import_vue12.h)("div", { style: { ...styles.toolbar, marginTop: "12px" } }, [
|
|
1552
1830
|
u.suspended ? actionButton("Unsuspend", isLoading.value, () => void unsuspend()) : actionButton(
|
|
1553
1831
|
"Suspend",
|
|
1554
1832
|
isLoading.value,
|
|
@@ -1561,19 +1839,19 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1561
1839
|
() => void revokeSessions().then(() => sessions.refresh())
|
|
1562
1840
|
)
|
|
1563
1841
|
]),
|
|
1564
|
-
(0,
|
|
1565
|
-
sessions.sessions.value.length === 0 ? (0,
|
|
1842
|
+
(0, import_vue12.h)("h2", { style: styles.subtitle }, "Live sessions"),
|
|
1843
|
+
sessions.sessions.value.length === 0 ? (0, import_vue12.h)("p", { style: styles.muted }, "None.") : (0, import_vue12.h)(
|
|
1566
1844
|
"ul",
|
|
1567
1845
|
{ style: styles.list },
|
|
1568
1846
|
sessions.sessions.value.map(
|
|
1569
|
-
(s) => (0,
|
|
1570
|
-
(0,
|
|
1847
|
+
(s) => (0, import_vue12.h)("li", { key: s.id, style: styles.row }, [
|
|
1848
|
+
(0, import_vue12.h)("span", { style: styles.mono }, s.ipAddress ?? "\u2014"),
|
|
1571
1849
|
" ",
|
|
1572
|
-
(0,
|
|
1850
|
+
(0, import_vue12.h)("span", { style: styles.muted }, (0, import_client.describeLocation)(s.location) ?? ""),
|
|
1573
1851
|
" ",
|
|
1574
|
-
(0,
|
|
1852
|
+
(0, import_vue12.h)("span", { style: styles.muted }, s.userAgent ?? ""),
|
|
1575
1853
|
" ",
|
|
1576
|
-
(0,
|
|
1854
|
+
(0, import_vue12.h)(
|
|
1577
1855
|
"span",
|
|
1578
1856
|
{ style: styles.muted },
|
|
1579
1857
|
`since ${new Date(s.createdAt).toLocaleString()}`
|
|
@@ -1581,22 +1859,22 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1581
1859
|
])
|
|
1582
1860
|
)
|
|
1583
1861
|
),
|
|
1584
|
-
(0,
|
|
1585
|
-
history.events.value.length === 0 && !history.isLoading.value ? (0,
|
|
1862
|
+
(0, import_vue12.h)("h2", { style: styles.subtitle }, "Recent sign-ins"),
|
|
1863
|
+
history.events.value.length === 0 && !history.isLoading.value ? (0, import_vue12.h)("p", { style: styles.muted }, "None recorded.") : (0, import_vue12.h)(
|
|
1586
1864
|
"ul",
|
|
1587
1865
|
{ style: styles.list },
|
|
1588
1866
|
history.events.value.map(
|
|
1589
|
-
(e) => (0,
|
|
1867
|
+
(e) => (0, import_vue12.h)("li", { key: e.id, style: styles.row }, [
|
|
1590
1868
|
pill(e.outcome === "success" ? "ok" : "bad", e.outcome),
|
|
1591
1869
|
" ",
|
|
1592
|
-
(0,
|
|
1870
|
+
(0, import_vue12.h)("span", { style: styles.muted }, e.method),
|
|
1593
1871
|
" ",
|
|
1594
|
-
(0,
|
|
1872
|
+
(0, import_vue12.h)("span", { style: styles.mono }, e.ipAddress ?? "\u2014"),
|
|
1595
1873
|
" ",
|
|
1596
|
-
(0,
|
|
1874
|
+
(0, import_vue12.h)("span", { style: styles.muted }, (0, import_client.describeLocation)(e.location) ?? ""),
|
|
1597
1875
|
e.location?.proxy || e.location?.hosting ? [" ", pill("warn", e.location.proxy ? "proxy/VPN" : "hosting")] : "",
|
|
1598
1876
|
" ",
|
|
1599
|
-
(0,
|
|
1877
|
+
(0, import_vue12.h)("span", { style: styles.muted }, new Date(e.createdAt).toLocaleString())
|
|
1600
1878
|
])
|
|
1601
1879
|
)
|
|
1602
1880
|
),
|
|
@@ -1608,27 +1886,27 @@ var UsersScreen = (0, import_vue11.defineComponent)({
|
|
|
1608
1886
|
});
|
|
1609
1887
|
|
|
1610
1888
|
// src/screens/CatalogScreen.ts
|
|
1611
|
-
var
|
|
1612
|
-
var
|
|
1613
|
-
var CatalogScreen = (0,
|
|
1889
|
+
var import_vue_admin11 = require("@fonderie/vue-admin");
|
|
1890
|
+
var import_vue13 = require("vue");
|
|
1891
|
+
var CatalogScreen = (0, import_vue13.defineComponent)({
|
|
1614
1892
|
name: "FonderieCatalogScreen",
|
|
1615
1893
|
props: { client: { type: Object, required: true } },
|
|
1616
1894
|
setup(props) {
|
|
1617
|
-
const { catalog, isLoading, error, refresh, deletePlan } = (0,
|
|
1895
|
+
const { catalog, isLoading, error, refresh, deletePlan } = (0, import_vue_admin11.useAdminCatalog)(props.client);
|
|
1618
1896
|
const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
|
|
1619
1897
|
return () => {
|
|
1620
1898
|
const c = catalog.value;
|
|
1621
|
-
return (0,
|
|
1899
|
+
return (0, import_vue13.h)("div", { style: styles.container }, [
|
|
1622
1900
|
pageHeader(
|
|
1623
1901
|
"Catalog",
|
|
1624
1902
|
"What you sell: plans as configured in code, and as stored in the database, side by side.",
|
|
1625
1903
|
[refreshButton("Refresh", isLoading.value, () => void refresh())]
|
|
1626
1904
|
),
|
|
1627
|
-
error.value ? (0,
|
|
1628
|
-
isLoading.value && !c ? (0,
|
|
1905
|
+
error.value ? (0, import_vue13.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
|
|
1906
|
+
isLoading.value && !c ? (0, import_vue13.h)("p", { style: styles.status }, "Loading\u2026") : null,
|
|
1629
1907
|
c ? [
|
|
1630
|
-
(0,
|
|
1631
|
-
(0,
|
|
1908
|
+
(0, import_vue13.h)("h2", { style: { ...styles.subtitle, marginTop: 0 } }, "Configured (code)"),
|
|
1909
|
+
(0, import_vue13.h)(
|
|
1632
1910
|
"pre",
|
|
1633
1911
|
{
|
|
1634
1912
|
style: {
|
|
@@ -1642,7 +1920,7 @@ var CatalogScreen = (0, import_vue12.defineComponent)({
|
|
|
1642
1920
|
},
|
|
1643
1921
|
JSON.stringify(c.configured, null, 2)
|
|
1644
1922
|
),
|
|
1645
|
-
(0,
|
|
1923
|
+
(0, import_vue13.h)("h2", { style: styles.subtitle }, "Stored (database)"),
|
|
1646
1924
|
c.stored.length === 0 ? empty(
|
|
1647
1925
|
"No stored plans",
|
|
1648
1926
|
"Plans are configured in code; nothing has been written to the database.",
|
|
@@ -1650,10 +1928,10 @@ var CatalogScreen = (0, import_vue12.defineComponent)({
|
|
|
1650
1928
|
) : table(
|
|
1651
1929
|
["Plan", "Tier", "Seats", "Monthly", "Yearly", "Trial", ""],
|
|
1652
1930
|
c.stored.map(
|
|
1653
|
-
(p) => (0,
|
|
1931
|
+
(p) => (0, import_vue13.h)("tr", { key: p.id }, [
|
|
1654
1932
|
td([
|
|
1655
|
-
(0,
|
|
1656
|
-
p.description ? (0,
|
|
1933
|
+
(0, import_vue13.h)("strong", p.name),
|
|
1934
|
+
p.description ? (0, import_vue13.h)("div", { style: styles.muted }, p.description) : ""
|
|
1657
1935
|
]),
|
|
1658
1936
|
td(String(p.tier)),
|
|
1659
1937
|
td(p.seats == null ? "\u221E" : String(p.seats)),
|
|
@@ -1661,7 +1939,7 @@ var CatalogScreen = (0, import_vue12.defineComponent)({
|
|
|
1661
1939
|
td(money(p.pricing?.yearly)),
|
|
1662
1940
|
td(p.trialDays ? `${p.trialDays} d` : "\u2014"),
|
|
1663
1941
|
td(
|
|
1664
|
-
(0,
|
|
1942
|
+
(0, import_vue13.h)(
|
|
1665
1943
|
"button",
|
|
1666
1944
|
{
|
|
1667
1945
|
type: "button",
|
|
@@ -1685,30 +1963,30 @@ var CatalogScreen = (0, import_vue12.defineComponent)({
|
|
|
1685
1963
|
});
|
|
1686
1964
|
|
|
1687
1965
|
// src/screens/SubscriberScreen.ts
|
|
1688
|
-
var
|
|
1689
|
-
var
|
|
1690
|
-
var SubscriberScreen = (0,
|
|
1966
|
+
var import_vue_admin12 = require("@fonderie/vue-admin");
|
|
1967
|
+
var import_vue14 = require("vue");
|
|
1968
|
+
var SubscriberScreen = (0, import_vue14.defineComponent)({
|
|
1691
1969
|
name: "FonderieSubscriberScreen",
|
|
1692
1970
|
props: {
|
|
1693
1971
|
client: { type: Object, required: true },
|
|
1694
1972
|
pageSize: { type: Number, default: 50 }
|
|
1695
1973
|
},
|
|
1696
1974
|
setup(props) {
|
|
1697
|
-
const type = (0,
|
|
1698
|
-
const idInput = (0,
|
|
1699
|
-
const subscriber = (0,
|
|
1700
|
-
const list = (0,
|
|
1701
|
-
const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0,
|
|
1975
|
+
const type = (0, import_vue14.ref)("user");
|
|
1976
|
+
const idInput = (0, import_vue14.ref)("");
|
|
1977
|
+
const subscriber = (0, import_vue14.ref)(null);
|
|
1978
|
+
const list = (0, import_vue_admin12.useAdminSubscribers)(props.client, { limit: props.pageSize });
|
|
1979
|
+
const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_vue_admin12.useAdminSubscriber)(props.client, subscriber, { limit: 20 });
|
|
1702
1980
|
const open = (t2, id) => {
|
|
1703
1981
|
granted.value = null;
|
|
1704
1982
|
type.value = t2;
|
|
1705
1983
|
idInput.value = id;
|
|
1706
1984
|
subscriber.value = { type: t2, id };
|
|
1707
1985
|
};
|
|
1708
|
-
const amount = (0,
|
|
1709
|
-
const note = (0,
|
|
1710
|
-
const granted = (0,
|
|
1711
|
-
const input = (model, placeholder, extra = {}) => (0,
|
|
1986
|
+
const amount = (0, import_vue14.ref)("");
|
|
1987
|
+
const note = (0, import_vue14.ref)("");
|
|
1988
|
+
const granted = (0, import_vue14.ref)(null);
|
|
1989
|
+
const input = (model, placeholder, extra = {}) => (0, import_vue14.h)("input", {
|
|
1712
1990
|
value: model.value,
|
|
1713
1991
|
onInput: (e) => model.value = e.target.value,
|
|
1714
1992
|
placeholder,
|
|
@@ -1718,12 +1996,12 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1718
1996
|
return () => {
|
|
1719
1997
|
const s = subscription.value;
|
|
1720
1998
|
const w = wallet.value;
|
|
1721
|
-
return (0,
|
|
1999
|
+
return (0, import_vue14.h)("div", { style: styles.container }, [
|
|
1722
2000
|
pageHeader(
|
|
1723
2001
|
"Subscribers",
|
|
1724
2002
|
"Who is subscribed. Open one for their plan, wallet and ledger, and to grant credit."
|
|
1725
2003
|
),
|
|
1726
|
-
(0,
|
|
2004
|
+
(0, import_vue14.h)(
|
|
1727
2005
|
"form",
|
|
1728
2006
|
{
|
|
1729
2007
|
style: styles.toolbar,
|
|
@@ -1734,7 +2012,7 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1734
2012
|
}
|
|
1735
2013
|
},
|
|
1736
2014
|
[
|
|
1737
|
-
(0,
|
|
2015
|
+
(0, import_vue14.h)(
|
|
1738
2016
|
"select",
|
|
1739
2017
|
{
|
|
1740
2018
|
value: type.value,
|
|
@@ -1743,17 +2021,17 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1743
2021
|
"aria-label": "Type"
|
|
1744
2022
|
},
|
|
1745
2023
|
[
|
|
1746
|
-
(0,
|
|
1747
|
-
(0,
|
|
2024
|
+
(0, import_vue14.h)("option", { value: "user" }, "user"),
|
|
2025
|
+
(0, import_vue14.h)("option", { value: "workspace" }, "workspace")
|
|
1748
2026
|
]
|
|
1749
2027
|
),
|
|
1750
2028
|
input(idInput, "subscriber id", { minWidth: "280px" }),
|
|
1751
|
-
(0,
|
|
2029
|
+
(0, import_vue14.h)(
|
|
1752
2030
|
"button",
|
|
1753
2031
|
{ type: "submit", style: styles.buttonPrimary, disabled: isLoading.value },
|
|
1754
2032
|
[icon("search", 14), "Look up"]
|
|
1755
2033
|
),
|
|
1756
|
-
subscriber.value ? (0,
|
|
2034
|
+
subscriber.value ? (0, import_vue14.h)(
|
|
1757
2035
|
"button",
|
|
1758
2036
|
{
|
|
1759
2037
|
type: "button",
|
|
@@ -1765,7 +2043,7 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1765
2043
|
}
|
|
1766
2044
|
},
|
|
1767
2045
|
[icon("back", 14), "All subscribers"]
|
|
1768
|
-
) : (0,
|
|
2046
|
+
) : (0, import_vue14.h)(
|
|
1769
2047
|
"button",
|
|
1770
2048
|
{
|
|
1771
2049
|
type: "button",
|
|
@@ -1777,8 +2055,8 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1777
2055
|
)
|
|
1778
2056
|
]
|
|
1779
2057
|
),
|
|
1780
|
-
!subscriber.value ? (0,
|
|
1781
|
-
list.error.value ? (0,
|
|
2058
|
+
!subscriber.value ? (0, import_vue14.h)("div", [
|
|
2059
|
+
list.error.value ? (0, import_vue14.h)("p", { style: styles.error, role: "alert" }, list.error.value.explanation) : null,
|
|
1782
2060
|
list.subscriptions.value.length === 0 && !list.isLoading.value ? empty(
|
|
1783
2061
|
"No subscribers yet",
|
|
1784
2062
|
"Subscriptions appear here once someone checks out.",
|
|
@@ -1786,9 +2064,9 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1786
2064
|
) : table(
|
|
1787
2065
|
["Subscriber", "Plan", "Status", "Renews"],
|
|
1788
2066
|
list.subscriptions.value.map(
|
|
1789
|
-
(sub) => (0,
|
|
2067
|
+
(sub) => (0, import_vue14.h)("tr", { key: sub.id }, [
|
|
1790
2068
|
td(
|
|
1791
|
-
(0,
|
|
2069
|
+
(0, import_vue14.h)(
|
|
1792
2070
|
"button",
|
|
1793
2071
|
{
|
|
1794
2072
|
type: "button",
|
|
@@ -1807,13 +2085,13 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1807
2085
|
sub.cancelAtPeriodEnd ? [" ", pill("warn", "cancels", false)] : null
|
|
1808
2086
|
]),
|
|
1809
2087
|
td(
|
|
1810
|
-
sub.currentPeriodEnd ? new Date(sub.currentPeriodEnd).toLocaleDateString() : (0,
|
|
2088
|
+
sub.currentPeriodEnd ? new Date(sub.currentPeriodEnd).toLocaleDateString() : (0, import_vue14.h)("span", { style: styles.muted }, "\u2014")
|
|
1811
2089
|
)
|
|
1812
2090
|
])
|
|
1813
2091
|
)
|
|
1814
2092
|
),
|
|
1815
|
-
list.isLoading.value ? (0,
|
|
1816
|
-
list.hasMore.value && !list.isLoading.value ? (0,
|
|
2093
|
+
list.isLoading.value ? (0, import_vue14.h)("p", { style: styles.status }, "Loading\u2026") : null,
|
|
2094
|
+
list.hasMore.value && !list.isLoading.value ? (0, import_vue14.h)(
|
|
1817
2095
|
"button",
|
|
1818
2096
|
{
|
|
1819
2097
|
type: "button",
|
|
@@ -1823,28 +2101,28 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1823
2101
|
"Load more"
|
|
1824
2102
|
) : null
|
|
1825
2103
|
]) : null,
|
|
1826
|
-
error.value ? (0,
|
|
2104
|
+
error.value ? (0, import_vue14.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
|
|
1827
2105
|
subscriber.value && !isLoading.value ? [
|
|
1828
|
-
(0,
|
|
1829
|
-
s ? (0,
|
|
1830
|
-
(0,
|
|
1831
|
-
(0,
|
|
1832
|
-
(0,
|
|
2106
|
+
(0, import_vue14.h)("h2", { style: styles.subtitle }, "Subscription"),
|
|
2107
|
+
s ? (0, import_vue14.h)("table", { style: styles.table }, [
|
|
2108
|
+
(0, import_vue14.h)("tbody", [
|
|
2109
|
+
(0, import_vue14.h)("tr", [td("plan"), td([(0, import_vue14.h)("strong", s.plan), ` \xB7 ${s.interval}`])]),
|
|
2110
|
+
(0, import_vue14.h)("tr", [
|
|
1833
2111
|
td("status"),
|
|
1834
2112
|
td(`${s.status}${s.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""}`)
|
|
1835
2113
|
]),
|
|
1836
|
-
(0,
|
|
2114
|
+
(0, import_vue14.h)("tr", [
|
|
1837
2115
|
td("period"),
|
|
1838
2116
|
td(
|
|
1839
2117
|
`${s.currentPeriodStart ? new Date(s.currentPeriodStart).toLocaleDateString() : "\u2014"} \u2192 ${s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : "\u2014"}`
|
|
1840
2118
|
)
|
|
1841
2119
|
]),
|
|
1842
|
-
(0,
|
|
2120
|
+
(0, import_vue14.h)("tr", [td("provider"), td(s.providerSubscriptionId ?? "\u2014", styles.mono)])
|
|
1843
2121
|
])
|
|
1844
|
-
]) : (0,
|
|
1845
|
-
(0,
|
|
2122
|
+
]) : (0, import_vue14.h)("p", { style: styles.muted }, "No subscription."),
|
|
2123
|
+
(0, import_vue14.h)("h2", { style: styles.subtitle }, "Wallet"),
|
|
1846
2124
|
w ? [
|
|
1847
|
-
(0,
|
|
2125
|
+
(0, import_vue14.h)(
|
|
1848
2126
|
"p",
|
|
1849
2127
|
{
|
|
1850
2128
|
style: {
|
|
@@ -1856,7 +2134,7 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1856
2134
|
}
|
|
1857
2135
|
},
|
|
1858
2136
|
[
|
|
1859
|
-
(0,
|
|
2137
|
+
(0, import_vue14.h)(
|
|
1860
2138
|
"strong",
|
|
1861
2139
|
{
|
|
1862
2140
|
style: {
|
|
@@ -1867,14 +2145,14 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1867
2145
|
w.balance
|
|
1868
2146
|
),
|
|
1869
2147
|
` ${w.currency} `,
|
|
1870
|
-
(0,
|
|
2148
|
+
(0, import_vue14.h)(
|
|
1871
2149
|
"span",
|
|
1872
2150
|
{ style: styles.muted },
|
|
1873
2151
|
`(granted ${w.granted ?? "0"} \xB7 purchased ${w.purchased ?? "0"}) \xB7 minor units, precision ${w.precision}`
|
|
1874
2152
|
)
|
|
1875
2153
|
]
|
|
1876
2154
|
),
|
|
1877
|
-
(0,
|
|
2155
|
+
(0, import_vue14.h)(
|
|
1878
2156
|
"form",
|
|
1879
2157
|
{
|
|
1880
2158
|
style: styles.toolbar,
|
|
@@ -1899,7 +2177,7 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1899
2177
|
[
|
|
1900
2178
|
input(amount, "amount (minor units)"),
|
|
1901
2179
|
input(note, "reason (optional)", { minWidth: "220px" }),
|
|
1902
|
-
(0,
|
|
2180
|
+
(0, import_vue14.h)(
|
|
1903
2181
|
"button",
|
|
1904
2182
|
{
|
|
1905
2183
|
type: "submit",
|
|
@@ -1908,14 +2186,14 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1908
2186
|
},
|
|
1909
2187
|
[icon("plus", 14), "Grant"]
|
|
1910
2188
|
),
|
|
1911
|
-
granted.value ? (0,
|
|
2189
|
+
granted.value ? (0, import_vue14.h)("span", { style: styles.ok }, granted.value) : null
|
|
1912
2190
|
]
|
|
1913
2191
|
),
|
|
1914
|
-
(0,
|
|
2192
|
+
(0, import_vue14.h)("h2", { style: styles.subtitle }, "Ledger"),
|
|
1915
2193
|
ledger.value.length === 0 ? empty("Nothing moved yet", void 0, "subscriber") : table(
|
|
1916
2194
|
["When", "Kind", "Amount", "Note"],
|
|
1917
2195
|
ledger.value.map(
|
|
1918
|
-
(t2) => (0,
|
|
2196
|
+
(t2) => (0, import_vue14.h)("tr", { key: t2.id }, [
|
|
1919
2197
|
td(new Date(t2.createdAt).toLocaleString(), styles.muted),
|
|
1920
2198
|
td(t2.type),
|
|
1921
2199
|
td(t2.amount, styles.mono),
|
|
@@ -1923,7 +2201,7 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1923
2201
|
])
|
|
1924
2202
|
)
|
|
1925
2203
|
),
|
|
1926
|
-
hasMoreLedger.value ? (0,
|
|
2204
|
+
hasMoreLedger.value ? (0, import_vue14.h)(
|
|
1927
2205
|
"button",
|
|
1928
2206
|
{
|
|
1929
2207
|
type: "button",
|
|
@@ -1932,7 +2210,7 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1932
2210
|
},
|
|
1933
2211
|
"Load more"
|
|
1934
2212
|
) : null
|
|
1935
|
-
] : (0,
|
|
2213
|
+
] : (0, import_vue14.h)(
|
|
1936
2214
|
"p",
|
|
1937
2215
|
{ style: styles.muted },
|
|
1938
2216
|
"No wallet \u2014 billing has no wallet configuration."
|
|
@@ -1944,34 +2222,34 @@ var SubscriberScreen = (0, import_vue13.defineComponent)({
|
|
|
1944
2222
|
});
|
|
1945
2223
|
|
|
1946
2224
|
// src/screens/AuditScreen.ts
|
|
1947
|
-
var
|
|
1948
|
-
var
|
|
1949
|
-
var AuditScreen = (0,
|
|
2225
|
+
var import_vue_admin13 = require("@fonderie/vue-admin");
|
|
2226
|
+
var import_vue15 = require("vue");
|
|
2227
|
+
var AuditScreen = (0, import_vue15.defineComponent)({
|
|
1950
2228
|
name: "FonderieAuditScreen",
|
|
1951
2229
|
props: {
|
|
1952
2230
|
client: { type: Object, required: true },
|
|
1953
2231
|
pageSize: { type: Number, default: 50 }
|
|
1954
2232
|
},
|
|
1955
2233
|
setup(props) {
|
|
1956
|
-
const draft = (0,
|
|
1957
|
-
const query = (0,
|
|
1958
|
-
const { events, hasMore, isLoading, error, refresh, loadMore } = (0,
|
|
2234
|
+
const draft = (0, import_vue15.ref)({ workspaceId: "", type: "", actorId: "" });
|
|
2235
|
+
const query = (0, import_vue15.ref)({ limit: props.pageSize });
|
|
2236
|
+
const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_vue_admin13.useAdminAudit)(
|
|
1959
2237
|
props.client,
|
|
1960
2238
|
query
|
|
1961
2239
|
);
|
|
1962
|
-
const field = (key, placeholder) => (0,
|
|
2240
|
+
const field = (key, placeholder) => (0, import_vue15.h)("input", {
|
|
1963
2241
|
value: draft.value[key],
|
|
1964
2242
|
onInput: (e) => draft.value = { ...draft.value, [key]: e.target.value },
|
|
1965
2243
|
placeholder,
|
|
1966
2244
|
style: styles.input,
|
|
1967
2245
|
"aria-label": placeholder
|
|
1968
2246
|
});
|
|
1969
|
-
return () => (0,
|
|
2247
|
+
return () => (0, import_vue15.h)("div", { style: styles.container }, [
|
|
1970
2248
|
pageHeader(
|
|
1971
2249
|
"Audit",
|
|
1972
2250
|
"What happened, across every workspace unless you name one. The chain's integrity verdict is on the Doctor page."
|
|
1973
2251
|
),
|
|
1974
|
-
(0,
|
|
2252
|
+
(0, import_vue15.h)(
|
|
1975
2253
|
"form",
|
|
1976
2254
|
{
|
|
1977
2255
|
style: styles.toolbar,
|
|
@@ -1990,7 +2268,7 @@ var AuditScreen = (0, import_vue14.defineComponent)({
|
|
|
1990
2268
|
field("workspaceId", "workspace id (all if empty)"),
|
|
1991
2269
|
field("type", "event type"),
|
|
1992
2270
|
field("actorId", "actor id"),
|
|
1993
|
-
(0,
|
|
2271
|
+
(0, import_vue15.h)(
|
|
1994
2272
|
"button",
|
|
1995
2273
|
{ type: "submit", style: styles.buttonPrimary, disabled: isLoading.value },
|
|
1996
2274
|
[icon("search", 14), "Filter"]
|
|
@@ -1998,11 +2276,11 @@ var AuditScreen = (0, import_vue14.defineComponent)({
|
|
|
1998
2276
|
refreshButton("Refresh", isLoading.value, () => void refresh())
|
|
1999
2277
|
]
|
|
2000
2278
|
),
|
|
2001
|
-
error.value ? (0,
|
|
2279
|
+
error.value ? (0, import_vue15.h)("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
|
|
2002
2280
|
events.value.length === 0 && !isLoading.value ? empty("Nothing recorded for this filter", void 0, "audit") : table(
|
|
2003
2281
|
["When", "Type", "Workspace", "Actor", "Request"],
|
|
2004
2282
|
events.value.map(
|
|
2005
|
-
(e) => (0,
|
|
2283
|
+
(e) => (0, import_vue15.h)("tr", { key: e.id }, [
|
|
2006
2284
|
td(new Date(e.createdAt).toLocaleString(), styles.muted),
|
|
2007
2285
|
td(e.type, styles.mono),
|
|
2008
2286
|
td(String(e.payload["workspaceId"] ?? "\u2014"), styles.mono),
|
|
@@ -2011,7 +2289,7 @@ var AuditScreen = (0, import_vue14.defineComponent)({
|
|
|
2011
2289
|
])
|
|
2012
2290
|
)
|
|
2013
2291
|
),
|
|
2014
|
-
isLoading.value ? (0,
|
|
2292
|
+
isLoading.value ? (0, import_vue15.h)("p", { style: styles.status }, "Loading\u2026") : null,
|
|
2015
2293
|
hasMore.value && !isLoading.value ? loadMoreButton(() => void loadMore()) : null
|
|
2016
2294
|
]);
|
|
2017
2295
|
}
|
|
@@ -2044,7 +2322,8 @@ var NAV = [
|
|
|
2044
2322
|
items: [
|
|
2045
2323
|
{ page: "audit", label: "Audit", needs: "audit" },
|
|
2046
2324
|
{ page: "log", label: "Admin log" },
|
|
2047
|
-
{ page: "
|
|
2325
|
+
{ page: "operators", label: "Operators", needs: "operators" },
|
|
2326
|
+
{ page: "tokens", label: "Tokens" },
|
|
2048
2327
|
{ page: "migrations", label: "Migrations" }
|
|
2049
2328
|
]
|
|
2050
2329
|
}
|
|
@@ -2063,10 +2342,11 @@ var ICON = {
|
|
|
2063
2342
|
audit: "audit",
|
|
2064
2343
|
log: "log",
|
|
2065
2344
|
tokens: "tokens",
|
|
2345
|
+
operators: "users",
|
|
2066
2346
|
migrations: "migrations"
|
|
2067
2347
|
};
|
|
2068
2348
|
var NARROW = "(max-width: 820px)";
|
|
2069
|
-
var AdminShell = (0,
|
|
2349
|
+
var AdminShell = (0, import_vue16.defineComponent)({
|
|
2070
2350
|
name: "FonderieAdminShell",
|
|
2071
2351
|
props: {
|
|
2072
2352
|
client: { type: Object, required: true },
|
|
@@ -2088,62 +2368,72 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2088
2368
|
appName: { type: String, default: "Admin" },
|
|
2089
2369
|
// A badge beside the name — the deployment's environment ("production").
|
|
2090
2370
|
// Production is tinted so an operator always knows where their clicks land.
|
|
2091
|
-
envLabel: { type: String, default: void 0 }
|
|
2371
|
+
envLabel: { type: String, default: void 0 },
|
|
2372
|
+
// The deployment has operator accounts (@fonderie/admin with a store):
|
|
2373
|
+
// shows the Operators page.
|
|
2374
|
+
operators: { type: Boolean, default: false },
|
|
2375
|
+
// The signed-in operator's email, when a person (not a token) is signed in.
|
|
2376
|
+
currentOperator: { type: String, default: void 0 }
|
|
2092
2377
|
},
|
|
2093
2378
|
// `footer` slot: pinned to the bottom of the sidebar — session controls
|
|
2094
2379
|
// (theme, sign out). The React shell takes the same thing as a `footer` prop.
|
|
2095
2380
|
emits: { navigate: (_page) => true },
|
|
2096
2381
|
setup(props, { emit, slots }) {
|
|
2097
2382
|
const query = typeof window !== "undefined" && window.matchMedia ? window.matchMedia(NARROW) : null;
|
|
2098
|
-
const narrow = (0,
|
|
2099
|
-
const drawer = (0,
|
|
2383
|
+
const narrow = (0, import_vue16.ref)(query?.matches ?? false);
|
|
2384
|
+
const drawer = (0, import_vue16.ref)(false);
|
|
2100
2385
|
const onMedia = (e) => narrow.value = e.matches;
|
|
2101
|
-
(0,
|
|
2102
|
-
(0,
|
|
2103
|
-
const own = (0,
|
|
2104
|
-
const current = (0,
|
|
2105
|
-
const editing = (0,
|
|
2386
|
+
(0, import_vue16.onMounted)(() => query?.addEventListener("change", onMedia));
|
|
2387
|
+
(0, import_vue16.onBeforeUnmount)(() => query?.removeEventListener("change", onMedia));
|
|
2388
|
+
const own = (0, import_vue16.ref)("attention");
|
|
2389
|
+
const current = (0, import_vue16.computed)(() => props.page ?? own.value);
|
|
2390
|
+
const editing = (0, import_vue16.ref)(null);
|
|
2106
2391
|
const go = (p) => {
|
|
2107
2392
|
editing.value = null;
|
|
2108
2393
|
emit("navigate", p);
|
|
2109
2394
|
if (props.page === void 0) own.value = p;
|
|
2110
2395
|
drawer.value = false;
|
|
2111
2396
|
};
|
|
2112
|
-
const back = (label) => (0,
|
|
2113
|
-
(0,
|
|
2397
|
+
const back = (label) => (0, import_vue16.h)("div", { style: { padding: "24px 40px 0" } }, [
|
|
2398
|
+
(0, import_vue16.h)(
|
|
2114
2399
|
"button",
|
|
2115
2400
|
{ type: "button", style: styles.buttonGhost, onClick: () => editing.value = null },
|
|
2116
2401
|
[icon("back", 14), label]
|
|
2117
2402
|
)
|
|
2118
2403
|
]);
|
|
2119
|
-
const missing = (text) => (0,
|
|
2404
|
+
const missing = (text) => (0, import_vue16.h)("p", { style: { ...styles.status, padding: "32px 40px" } }, text);
|
|
2120
2405
|
const body = () => {
|
|
2121
2406
|
const c = props.client;
|
|
2122
2407
|
switch (current.value) {
|
|
2123
2408
|
case "attention":
|
|
2124
|
-
return (0,
|
|
2409
|
+
return (0, import_vue16.h)(AttentionScreen, { client: c });
|
|
2125
2410
|
case "modules":
|
|
2126
|
-
return (0,
|
|
2411
|
+
return (0, import_vue16.h)(ModulesScreen, { client: c });
|
|
2127
2412
|
case "doctor":
|
|
2128
|
-
return (0,
|
|
2413
|
+
return (0, import_vue16.h)(DoctorScreen, { client: c });
|
|
2129
2414
|
case "environment":
|
|
2130
|
-
return (0,
|
|
2415
|
+
return (0, import_vue16.h)(EnvironmentScreen, { client: c });
|
|
2131
2416
|
case "routes":
|
|
2132
|
-
return (0,
|
|
2417
|
+
return (0, import_vue16.h)(RoutesScreen, { client: c });
|
|
2133
2418
|
case "tokens":
|
|
2134
|
-
return (0,
|
|
2419
|
+
return (0, import_vue16.h)(TokensScreen, { client: c });
|
|
2420
|
+
case "operators":
|
|
2421
|
+
return (0, import_vue16.h)(OperatorsScreen, {
|
|
2422
|
+
client: c,
|
|
2423
|
+
...props.currentOperator ? { me: props.currentOperator } : {}
|
|
2424
|
+
});
|
|
2135
2425
|
case "migrations":
|
|
2136
|
-
return (0,
|
|
2426
|
+
return (0, import_vue16.h)(MigrationsScreen, { client: c });
|
|
2137
2427
|
case "log":
|
|
2138
|
-
return (0,
|
|
2428
|
+
return (0, import_vue16.h)(AdminLogScreen, { client: c });
|
|
2139
2429
|
case "catalog":
|
|
2140
|
-
return props.billingClient ? (0,
|
|
2430
|
+
return props.billingClient ? (0, import_vue16.h)(CatalogScreen, { client: props.billingClient }) : missing("Pass a BillingAdminClient to see the catalog here.");
|
|
2141
2431
|
case "subscriber":
|
|
2142
|
-
return props.billingClient ? (0,
|
|
2432
|
+
return props.billingClient ? (0, import_vue16.h)(SubscriberScreen, { client: props.billingClient }) : missing("Pass a BillingAdminClient to look up subscribers here.");
|
|
2143
2433
|
case "audit":
|
|
2144
|
-
return props.auditClient ? (0,
|
|
2434
|
+
return props.auditClient ? (0, import_vue16.h)(AuditScreen, { client: props.auditClient }) : missing("Pass an AuditAdminClient to see the audit trail here.");
|
|
2145
2435
|
case "users":
|
|
2146
|
-
return props.authClient ? (0,
|
|
2436
|
+
return props.authClient ? (0, import_vue16.h)(UsersScreen, { client: props.authClient }) : missing("Pass an AuthAdminClient to look up users here.");
|
|
2147
2437
|
case "settings": {
|
|
2148
2438
|
const cc = props.configClient;
|
|
2149
2439
|
if (!cc) return missing("Pass a ConfigAdminClient to manage config and secrets here.");
|
|
@@ -2151,7 +2441,7 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2151
2441
|
if (e && e.kind !== "template")
|
|
2152
2442
|
return [
|
|
2153
2443
|
back("Config & secrets"),
|
|
2154
|
-
(0,
|
|
2444
|
+
(0, import_vue16.h)(import_vue_config_admin_screens.ConfigEditorScreen, {
|
|
2155
2445
|
client: cc,
|
|
2156
2446
|
kind: e.kind,
|
|
2157
2447
|
configKey: e.key,
|
|
@@ -2159,7 +2449,7 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2159
2449
|
onSaved: () => editing.value = null
|
|
2160
2450
|
})
|
|
2161
2451
|
];
|
|
2162
|
-
return (0,
|
|
2452
|
+
return (0, import_vue16.h)(import_vue_config_admin_screens.ConfigListScreen, {
|
|
2163
2453
|
client: cc,
|
|
2164
2454
|
...props.environment !== void 0 ? { environment: props.environment } : {},
|
|
2165
2455
|
"onSelect-config": (key) => editing.value = { kind: "config", key },
|
|
@@ -2176,27 +2466,27 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2176
2466
|
if (e?.kind === "template")
|
|
2177
2467
|
return [
|
|
2178
2468
|
back("Templates"),
|
|
2179
|
-
(0,
|
|
2469
|
+
(0, import_vue16.h)(import_vue_courier_admin_screens.TemplateEditorScreen, {
|
|
2180
2470
|
client: kc,
|
|
2181
2471
|
type: e.type,
|
|
2182
2472
|
onSaved: () => editing.value = null
|
|
2183
2473
|
})
|
|
2184
2474
|
];
|
|
2185
|
-
return (0,
|
|
2475
|
+
return (0, import_vue16.h)(import_vue_courier_admin_screens.TemplateListScreen, {
|
|
2186
2476
|
client: kc,
|
|
2187
2477
|
"onSelect-template": (t2) => editing.value = { kind: "template", type: t2.type }
|
|
2188
2478
|
});
|
|
2189
2479
|
}
|
|
2190
2480
|
}
|
|
2191
2481
|
};
|
|
2192
|
-
const visible = (i) => !i.needs || (i.needs === "config" ? props.configClient : i.needs === "courier" ? props.courierClient : i.needs === "auth" ? props.authClient : i.needs === "billing" ? props.billingClient : props.auditClient);
|
|
2482
|
+
const visible = (i) => !i.needs || (i.needs === "operators" ? props.operators : i.needs === "config" ? props.configClient : i.needs === "courier" ? props.courierClient : i.needs === "auth" ? props.authClient : i.needs === "billing" ? props.billingClient : props.auditClient);
|
|
2193
2483
|
const brand = () => {
|
|
2194
2484
|
const production = props.envLabel ? /^prod/i.test(props.envLabel) : false;
|
|
2195
|
-
return (0,
|
|
2196
|
-
(0,
|
|
2197
|
-
(0,
|
|
2198
|
-
(0,
|
|
2199
|
-
props.envLabel ? (0,
|
|
2485
|
+
return (0, import_vue16.h)("div", { style: styles.navBrand }, [
|
|
2486
|
+
(0, import_vue16.h)("div", { style: styles.navMark }, [icon("mark", 15)]),
|
|
2487
|
+
(0, import_vue16.h)("div", { style: { minWidth: 0, flex: 1 } }, [
|
|
2488
|
+
(0, import_vue16.h)("div", { style: styles.navBrandTitle }, props.appName),
|
|
2489
|
+
props.envLabel ? (0, import_vue16.h)(
|
|
2200
2490
|
"span",
|
|
2201
2491
|
{
|
|
2202
2492
|
style: {
|
|
@@ -2213,7 +2503,7 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2213
2503
|
props.envLabel
|
|
2214
2504
|
) : null
|
|
2215
2505
|
]),
|
|
2216
|
-
narrow.value ? (0,
|
|
2506
|
+
narrow.value ? (0, import_vue16.h)(
|
|
2217
2507
|
"button",
|
|
2218
2508
|
{
|
|
2219
2509
|
type: "button",
|
|
@@ -2225,7 +2515,7 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2225
2515
|
) : null
|
|
2226
2516
|
]);
|
|
2227
2517
|
};
|
|
2228
|
-
const nav = () => (0,
|
|
2518
|
+
const nav = () => (0, import_vue16.h)(
|
|
2229
2519
|
"nav",
|
|
2230
2520
|
{
|
|
2231
2521
|
style: {
|
|
@@ -2236,17 +2526,17 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2236
2526
|
},
|
|
2237
2527
|
[
|
|
2238
2528
|
brand(),
|
|
2239
|
-
(0,
|
|
2529
|
+
(0, import_vue16.h)(
|
|
2240
2530
|
"div",
|
|
2241
2531
|
{ style: styles.navScroll },
|
|
2242
2532
|
NAV.map((g) => {
|
|
2243
2533
|
const items = g.items.filter(visible);
|
|
2244
2534
|
if (items.length === 0) return null;
|
|
2245
|
-
return (0,
|
|
2246
|
-
(0,
|
|
2535
|
+
return (0, import_vue16.h)("div", { key: g.group }, [
|
|
2536
|
+
(0, import_vue16.h)("div", { style: styles.navGroup }, g.group),
|
|
2247
2537
|
...items.map((i) => {
|
|
2248
2538
|
const active = current.value === i.page;
|
|
2249
|
-
return (0,
|
|
2539
|
+
return (0, import_vue16.h)(
|
|
2250
2540
|
"button",
|
|
2251
2541
|
{
|
|
2252
2542
|
key: i.page,
|
|
@@ -2262,18 +2552,18 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2262
2552
|
]);
|
|
2263
2553
|
})
|
|
2264
2554
|
),
|
|
2265
|
-
slots["footer"] ? (0,
|
|
2555
|
+
slots["footer"] ? (0, import_vue16.h)("div", { style: styles.navFooter }, slots["footer"]()) : null
|
|
2266
2556
|
]
|
|
2267
2557
|
);
|
|
2268
2558
|
return () => {
|
|
2269
2559
|
const title = NAV.flatMap((g) => g.items).find((i) => i.page === current.value)?.label ?? "";
|
|
2270
|
-
return (0,
|
|
2560
|
+
return (0, import_vue16.h)(
|
|
2271
2561
|
"div",
|
|
2272
2562
|
{ style: { ...styles.shell, ...narrow.value ? { flexDirection: "column" } : {} } },
|
|
2273
2563
|
[
|
|
2274
2564
|
...narrow.value ? [
|
|
2275
|
-
(0,
|
|
2276
|
-
(0,
|
|
2565
|
+
(0, import_vue16.h)("div", { style: styles.topbar }, [
|
|
2566
|
+
(0, import_vue16.h)(
|
|
2277
2567
|
"button",
|
|
2278
2568
|
{
|
|
2279
2569
|
type: "button",
|
|
@@ -2284,19 +2574,19 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2284
2574
|
},
|
|
2285
2575
|
[icon("menu")]
|
|
2286
2576
|
),
|
|
2287
|
-
(0,
|
|
2288
|
-
props.envLabel ? (0,
|
|
2577
|
+
(0, import_vue16.h)("span", { style: { fontWeight: 600, fontSize: "14px" } }, title),
|
|
2578
|
+
props.envLabel ? (0, import_vue16.h)("span", { style: { ...styles.badge, marginLeft: "auto" } }, props.envLabel) : null
|
|
2289
2579
|
]),
|
|
2290
|
-
drawer.value ? (0,
|
|
2580
|
+
drawer.value ? (0, import_vue16.h)("div", { style: styles.drawer }, [
|
|
2291
2581
|
nav(),
|
|
2292
|
-
(0,
|
|
2582
|
+
(0, import_vue16.h)("div", {
|
|
2293
2583
|
style: styles.scrim,
|
|
2294
2584
|
"aria-hidden": "true",
|
|
2295
2585
|
onClick: () => drawer.value = false
|
|
2296
2586
|
})
|
|
2297
2587
|
]) : null
|
|
2298
2588
|
] : [nav()],
|
|
2299
|
-
(0,
|
|
2589
|
+
(0, import_vue16.h)("main", { class: "fonderie-admin-main", style: styles.main }, body())
|
|
2300
2590
|
]
|
|
2301
2591
|
);
|
|
2302
2592
|
};
|
|
@@ -2313,6 +2603,7 @@ var AdminShell = (0, import_vue15.defineComponent)({
|
|
|
2313
2603
|
EnvironmentScreen,
|
|
2314
2604
|
MigrationsScreen,
|
|
2315
2605
|
ModulesScreen,
|
|
2606
|
+
OperatorsScreen,
|
|
2316
2607
|
RoutesScreen,
|
|
2317
2608
|
SubscriberScreen,
|
|
2318
2609
|
TokensScreen,
|