apiblaze 0.19.5 → 0.19.7
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.js +12 -2
- package/dist/react/index.js +189 -44
- package/dist/react/index.mjs +189 -44
- package/dist/server/index.js +12 -3
- package/dist/server/index.mjs +12 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -933,7 +933,7 @@ var import_commander = require("commander");
|
|
|
933
933
|
var import_chalk44 = __toESM(require("chalk"));
|
|
934
934
|
|
|
935
935
|
// package.json
|
|
936
|
-
var version = "0.19.
|
|
936
|
+
var version = "0.19.7";
|
|
937
937
|
|
|
938
938
|
// src/index.ts
|
|
939
939
|
init_types();
|
|
@@ -5297,7 +5297,17 @@ async function runGroupMembers(name, opts) {
|
|
|
5297
5297
|
}
|
|
5298
5298
|
async function runGroupAddUser(userRef, groupName, opts) {
|
|
5299
5299
|
const t = await resolveTransport(opts);
|
|
5300
|
-
const
|
|
5300
|
+
const g = await groupByName(t, groupName);
|
|
5301
|
+
let u;
|
|
5302
|
+
try {
|
|
5303
|
+
u = await userByRef(t, userRef);
|
|
5304
|
+
} catch (e) {
|
|
5305
|
+
if (!userRef.includes("@")) throw e;
|
|
5306
|
+
const created = await t.call("/v1/admin/users", "POST", { email: userRef.trim().toLowerCase() });
|
|
5307
|
+
if (!created?.abz_sub) throw e;
|
|
5308
|
+
console.log(import_chalk34.default.dim(` ${userRef} wasn't a user yet \u2014 created.`));
|
|
5309
|
+
u = { abz_sub: created.abz_sub, email: created.email ?? userRef, display_name: null };
|
|
5310
|
+
}
|
|
5301
5311
|
const role = opts.role === "admin" ? "admin" : "member";
|
|
5302
5312
|
const spinner = (0, import_ora17.default)(`Adding ${label2(u)} to ${g.name}...`).start();
|
|
5303
5313
|
try {
|
package/dist/react/index.js
CHANGED
|
@@ -144,9 +144,15 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
144
144
|
const [groups, setGroups] = React.useState(null);
|
|
145
145
|
const [groupTotal, setGroupTotal] = React.useState(0);
|
|
146
146
|
const [groupQuery, setGroupQuery] = React.useState("");
|
|
147
|
+
const [users, setUsers] = React.useState([]);
|
|
148
|
+
const [userTotal, setUserTotal] = React.useState(0);
|
|
149
|
+
const [userQuery, setUserQuery] = React.useState("");
|
|
147
150
|
const [observed, setObserved] = React.useState([]);
|
|
151
|
+
const [observedTotal, setObservedTotal] = React.useState(0);
|
|
152
|
+
const [observedQuery, setObservedQuery] = React.useState("");
|
|
148
153
|
const [observedNew, setObservedNew] = React.useState(0);
|
|
149
154
|
const [observedLoaded, setObservedLoaded] = React.useState(false);
|
|
155
|
+
const [showObserved, setShowObserved] = React.useState(false);
|
|
150
156
|
const [loadError, setLoadError] = React.useState(null);
|
|
151
157
|
const [open, setOpen] = React.useState(null);
|
|
152
158
|
const [detail, setDetail] = React.useState(null);
|
|
@@ -176,6 +182,9 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
176
182
|
setMyEmail(d.email ?? null);
|
|
177
183
|
setGroups(d.groups ?? []);
|
|
178
184
|
setGroupTotal(d.groupTotal ?? (d.groups?.length ?? 0));
|
|
185
|
+
setUsers(d.users ?? []);
|
|
186
|
+
setUserTotal(d.userTotal ?? (d.users?.length ?? 0));
|
|
187
|
+
setUserQuery("");
|
|
179
188
|
setObservedNew(d.observedNew ?? 0);
|
|
180
189
|
setObservedLoaded(false);
|
|
181
190
|
setGroupQuery("");
|
|
@@ -203,11 +212,30 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
203
212
|
setGroups((prev) => [...prev ?? [], ...d.groups ?? []]);
|
|
204
213
|
if (typeof d.total === "number") setGroupTotal(d.total);
|
|
205
214
|
}, [call, groupQuery, groups]);
|
|
206
|
-
const
|
|
207
|
-
|
|
215
|
+
const searchUsers = React.useCallback(async (q) => {
|
|
216
|
+
setUserQuery(q);
|
|
217
|
+
const d = await call({ action: "search-users", q, limit: 25, offset: 0 });
|
|
218
|
+
setUsers(d.users ?? []);
|
|
219
|
+
setUserTotal(d.total ?? (d.users?.length ?? 0));
|
|
220
|
+
}, [call]);
|
|
221
|
+
const loadMoreUsers = React.useCallback(async () => {
|
|
222
|
+
const d = await call({ action: "search-users", q: userQuery, limit: 25, offset: users.length });
|
|
223
|
+
setUsers((prev) => [...prev, ...d.users ?? []]);
|
|
224
|
+
if (typeof d.total === "number") setUserTotal(d.total);
|
|
225
|
+
}, [call, userQuery, users]);
|
|
226
|
+
const searchObserved = React.useCallback(async (q) => {
|
|
227
|
+
setObservedQuery(q);
|
|
228
|
+
const d = await call({ action: "list-observed", q, offset: 0 });
|
|
208
229
|
setObserved(d.identities ?? []);
|
|
230
|
+
setObservedTotal(d.total ?? (d.identities?.length ?? 0));
|
|
209
231
|
setObservedLoaded(true);
|
|
210
232
|
}, [call]);
|
|
233
|
+
const loadObserved = React.useCallback(() => searchObserved(""), [searchObserved]);
|
|
234
|
+
const loadMoreObserved = React.useCallback(async () => {
|
|
235
|
+
const d = await call({ action: "list-observed", q: observedQuery, offset: observed.length });
|
|
236
|
+
setObserved((prev) => [...prev, ...d.identities ?? []]);
|
|
237
|
+
if (typeof d.total === "number") setObservedTotal(d.total);
|
|
238
|
+
}, [call, observedQuery, observed]);
|
|
211
239
|
const loadDetail = React.useCallback(async (groupId) => {
|
|
212
240
|
setDetailLoading(true);
|
|
213
241
|
setDetail(null);
|
|
@@ -278,7 +306,8 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
278
306
|
if (!ref2) return;
|
|
279
307
|
await act("create-user", { action: "create-user", ref: ref2 }, async () => {
|
|
280
308
|
setNewUserRef("");
|
|
281
|
-
|
|
309
|
+
setShowNewUser(false);
|
|
310
|
+
await searchUsers("");
|
|
282
311
|
});
|
|
283
312
|
}
|
|
284
313
|
const vars = {
|
|
@@ -322,10 +351,8 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
322
351
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { style: { fontSize: 15 }, children: title }),
|
|
323
352
|
access === "ok" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
|
|
324
353
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: btn("ghost", true), disabled: busy, onClick: () => {
|
|
325
|
-
|
|
326
|
-
setShowNewUser(nv);
|
|
354
|
+
setShowNewUser((v) => !v);
|
|
327
355
|
setShowCreate(false);
|
|
328
|
-
if (nv && !observedLoaded) loadObserved();
|
|
329
356
|
}, "aria-label": "Add a new user", children: "+ New user" }),
|
|
330
357
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: btn("primary", true), disabled: busy, onClick: () => {
|
|
331
358
|
setShowCreate((v) => !v);
|
|
@@ -380,8 +407,12 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
380
407
|
setNewName("");
|
|
381
408
|
}, children: "Cancel" })
|
|
382
409
|
] }),
|
|
383
|
-
access === "ok" &&
|
|
384
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
|
|
410
|
+
access === "ok" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderBottom: `1px solid ${t.border}` }, children: [
|
|
411
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "12px 16px 6px" }, children: [
|
|
412
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { style: { fontSize: 13 }, children: "Users" }),
|
|
413
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: chip, children: userTotal })
|
|
414
|
+
] }),
|
|
415
|
+
showNewUser && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8, padding: "6px 16px" }, children: [
|
|
385
416
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
386
417
|
"input",
|
|
387
418
|
{
|
|
@@ -390,7 +421,8 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
390
421
|
value: newUserRef,
|
|
391
422
|
onChange: (e) => setNewUserRef(e.target.value),
|
|
392
423
|
onKeyDown: (e) => e.key === "Enter" && createUser(),
|
|
393
|
-
"aria-label": "New user email or id"
|
|
424
|
+
"aria-label": "New user email or id",
|
|
425
|
+
autoFocus: true
|
|
394
426
|
}
|
|
395
427
|
),
|
|
396
428
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: btn("primary", true), disabled: busy || !newUserRef.trim(), onClick: createUser, children: "Add" }),
|
|
@@ -399,22 +431,77 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
399
431
|
setNewUserRef("");
|
|
400
432
|
}, children: "Cancel" })
|
|
401
433
|
] }),
|
|
402
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
434
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "6px 16px" }, children: [
|
|
435
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
436
|
+
"input",
|
|
437
|
+
{
|
|
438
|
+
style: { ...inputStyle, flex: 1 },
|
|
439
|
+
placeholder: "Search users\u2026",
|
|
440
|
+
defaultValue: userQuery,
|
|
441
|
+
onChange: (e) => searchUsers(e.target.value),
|
|
442
|
+
"aria-label": "Search users"
|
|
443
|
+
}
|
|
444
|
+
),
|
|
445
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontSize: 12, color: t.muted, whiteSpace: "nowrap" }, children: [
|
|
446
|
+
users.length,
|
|
447
|
+
" of ",
|
|
448
|
+
userTotal
|
|
449
|
+
] })
|
|
408
450
|
] }),
|
|
409
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
451
|
+
users.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "6px 16px 12px", fontSize: 13, color: t.muted }, children: userQuery ? `No users match \u201C${userQuery}\u201D.` : "No users yet \u2014 add one with + New user." }),
|
|
452
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: { listStyle: "none", margin: 0, padding: "0 16px 8px" }, children: users.map((u) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: { display: "flex", gap: 8, alignItems: "center", padding: "5px 0", flexWrap: "wrap" }, children: [
|
|
453
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1, minWidth: 140, fontSize: 13 }, children: userLabel(u) }),
|
|
454
|
+
u.email && u.email !== userLabel(u) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 12, color: t.muted, fontFamily: t.monoFontFamily }, children: u.email }),
|
|
455
|
+
u.source_label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: chip, children: u.source_label }),
|
|
456
|
+
u.status && u.status !== "active" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...chip, color: t.danger, borderColor: t.danger }, children: u.status })
|
|
457
|
+
] }, u.abz_sub)) }),
|
|
458
|
+
users.length < userTotal && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "0 16px 12px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { style: btn("ghost", true), disabled: busy, onClick: loadMoreUsers, children: [
|
|
459
|
+
"Load more (",
|
|
460
|
+
users.length,
|
|
461
|
+
" of ",
|
|
462
|
+
userTotal,
|
|
463
|
+
")"
|
|
464
|
+
] }) })
|
|
465
|
+
] }),
|
|
466
|
+
access === "ok" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { borderBottom: `1px solid ${t.border}` }, children: [
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
468
|
+
"button",
|
|
469
|
+
{
|
|
470
|
+
onClick: () => {
|
|
471
|
+
const nv = !showObserved;
|
|
472
|
+
setShowObserved(nv);
|
|
473
|
+
if (nv && !observedLoaded) loadObserved();
|
|
474
|
+
},
|
|
475
|
+
"aria-expanded": showObserved,
|
|
476
|
+
style: { display: "flex", width: "100%", gap: 10, alignItems: "center", padding: "12px 16px", background: "transparent", border: "none", cursor: "pointer", color: t.text, fontFamily: "inherit", fontSize: 13, textAlign: "left" },
|
|
477
|
+
children: [
|
|
478
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { "aria-hidden": "true", style: { color: t.muted, fontSize: 11 }, children: showObserved ? "\u25BE" : "\u25B8" }),
|
|
479
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { style: { flex: 1 }, children: "Candidates seen in traffic" }),
|
|
480
|
+
observedNew > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: chip, children: observedNew })
|
|
481
|
+
]
|
|
482
|
+
}
|
|
483
|
+
),
|
|
484
|
+
showObserved && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "0 16px 12px 34px" }, children: [
|
|
485
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center", marginBottom: 6 }, children: [
|
|
486
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
487
|
+
"input",
|
|
488
|
+
{
|
|
489
|
+
style: { ...inputStyle, flex: 1 },
|
|
490
|
+
placeholder: "Search candidates\u2026",
|
|
491
|
+
defaultValue: observedQuery,
|
|
492
|
+
onChange: (e) => searchObserved(e.target.value),
|
|
493
|
+
"aria-label": "Search candidates seen in traffic"
|
|
494
|
+
}
|
|
495
|
+
),
|
|
496
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontSize: 12, color: t.muted, whiteSpace: "nowrap" }, children: [
|
|
497
|
+
observed.length,
|
|
498
|
+
" of ",
|
|
499
|
+
observedTotal
|
|
500
|
+
] })
|
|
414
501
|
] }),
|
|
415
502
|
!observedLoaded && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 12, color: t.muted }, children: "Loading\u2026" }),
|
|
416
|
-
observedLoaded && observed.
|
|
417
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: observed.
|
|
503
|
+
observedLoaded && observed.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 12, color: t.muted }, children: observedQuery ? `No candidates match \u201C${observedQuery}\u201D.` : "Nothing yet \u2014 identities appear here after their first API call." }),
|
|
504
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: observed.map((o) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: { display: "flex", gap: 8, alignItems: "center", padding: "5px 0", flexWrap: "wrap" }, children: [
|
|
418
505
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1, minWidth: 140, fontFamily: t.monoFontFamily, fontSize: 13 }, children: o.email || o.abz_sub }),
|
|
419
506
|
o.source_label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: chip, children: o.source_label }),
|
|
420
507
|
o.last_seen && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontSize: 11, color: t.muted }, children: [
|
|
@@ -422,17 +509,31 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
422
509
|
relTime(o.last_seen),
|
|
423
510
|
o.seen_count ? ` \xB7 ${o.seen_count}\xD7` : ""
|
|
424
511
|
] }),
|
|
425
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
512
|
+
o.provisioned ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...chip, color: t.success, borderColor: t.success }, children: "user \u2713" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
426
513
|
"button",
|
|
427
514
|
{
|
|
428
515
|
style: btn("ghost", true),
|
|
429
516
|
disabled: busy,
|
|
430
517
|
"aria-label": `Add ${o.email || o.abz_sub} as a user`,
|
|
431
|
-
onClick: () => act(
|
|
518
|
+
onClick: () => act(
|
|
519
|
+
`provision:${o.abz_sub}`,
|
|
520
|
+
{ action: "provision-observed", consumerUserId: o.abz_sub, email: o.email ?? void 0 },
|
|
521
|
+
async () => {
|
|
522
|
+
await searchObserved(observedQuery);
|
|
523
|
+
await searchUsers("");
|
|
524
|
+
}
|
|
525
|
+
),
|
|
432
526
|
children: "Add"
|
|
433
527
|
}
|
|
434
528
|
)
|
|
435
|
-
] }, o.abz_sub)) })
|
|
529
|
+
] }, o.abz_sub)) }),
|
|
530
|
+
observed.length < observedTotal && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { style: { ...btn("ghost", true), marginTop: 6 }, disabled: busy, onClick: loadMoreObserved, children: [
|
|
531
|
+
"Load more (",
|
|
532
|
+
observed.length,
|
|
533
|
+
" of ",
|
|
534
|
+
observedTotal,
|
|
535
|
+
")"
|
|
536
|
+
] })
|
|
436
537
|
] })
|
|
437
538
|
] }),
|
|
438
539
|
access === "ok" && groups === null && !loadError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "aria-busy": "true", style: { padding: 24, color: t.muted }, children: "Loading groups\u2026" }),
|
|
@@ -441,24 +542,30 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
441
542
|
" ",
|
|
442
543
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: { ...btn("ghost", true), marginLeft: 6 }, onClick: load, children: "Retry" })
|
|
443
544
|
] }),
|
|
444
|
-
access === "ok" && groups !== null &&
|
|
445
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
446
|
-
"
|
|
447
|
-
{
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
545
|
+
access === "ok" && groups !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
546
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "12px 16px 6px" }, children: [
|
|
547
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { style: { fontSize: 13 }, children: "Groups" }),
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: chip, children: groupTotal })
|
|
549
|
+
] }),
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "6px 16px 10px", borderBottom: `1px solid ${t.border}` }, children: [
|
|
551
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
552
|
+
"input",
|
|
553
|
+
{
|
|
554
|
+
style: { ...inputStyle, flex: 1 },
|
|
555
|
+
placeholder: "Search groups\u2026",
|
|
556
|
+
defaultValue: groupQuery,
|
|
557
|
+
onChange: (e) => {
|
|
558
|
+
const v = e.target.value;
|
|
559
|
+
searchGroups(v);
|
|
560
|
+
},
|
|
561
|
+
"aria-label": "Search groups"
|
|
562
|
+
}
|
|
563
|
+
),
|
|
564
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontSize: 12, color: t.muted, whiteSpace: "nowrap" }, children: [
|
|
565
|
+
groups.length,
|
|
566
|
+
" of ",
|
|
567
|
+
groupTotal
|
|
568
|
+
] })
|
|
462
569
|
] })
|
|
463
570
|
] }),
|
|
464
571
|
access === "ok" && groups !== null && groups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: "28px 20px", textAlign: "center", color: t.muted }, children: groupQuery ? `No groups match \u201C${groupQuery}\u201D.` : "No groups yet. Create one to start organizing your users." }),
|
|
@@ -731,6 +838,8 @@ var ApiKeyWidget = React2.forwardRef(function ApiKeyWidget2({ endpoint = "/api/a
|
|
|
731
838
|
const [confirming, setConfirming] = React2.useState(null);
|
|
732
839
|
const [rowError, setRowError] = React2.useState(null);
|
|
733
840
|
const [copied, setCopied] = React2.useState(false);
|
|
841
|
+
const [keyQuery, setKeyQuery] = React2.useState("");
|
|
842
|
+
const [visibleCount, setVisibleCount] = React2.useState(10);
|
|
734
843
|
const call = React2.useCallback(async (body) => {
|
|
735
844
|
const res = await fetch(endpoint, body ? { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) } : { cache: "no-store" });
|
|
736
845
|
const data = await res.json().catch(() => ({}));
|
|
@@ -914,7 +1023,20 @@ var ApiKeyWidget = React2.forwardRef(function ApiKeyWidget2({ endpoint = "/api/a
|
|
|
914
1023
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { style: { ...btn("primary"), ...disabledStyle(creating) }, disabled: creating, onClick: create, children: creating ? "Creating\u2026" : "Create API key" })
|
|
915
1024
|
] })
|
|
916
1025
|
] }),
|
|
917
|
-
!denied && keys !== null && keys.length >
|
|
1026
|
+
!denied && keys !== null && keys.length > 5 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "10px 16px", borderBottom: `1px solid ${t.border}` }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1027
|
+
"input",
|
|
1028
|
+
{
|
|
1029
|
+
value: keyQuery,
|
|
1030
|
+
onChange: (e) => {
|
|
1031
|
+
setKeyQuery(e.target.value);
|
|
1032
|
+
setVisibleCount(10);
|
|
1033
|
+
},
|
|
1034
|
+
placeholder: "Search keys\u2026",
|
|
1035
|
+
"aria-label": "Search keys",
|
|
1036
|
+
style: { flex: 1, fontFamily: "inherit", fontSize: 13, padding: "6px 10px", borderRadius: 8, border: `1px solid ${t.border}`, background: t.surface, color: t.text, minWidth: 0 }
|
|
1037
|
+
}
|
|
1038
|
+
) }),
|
|
1039
|
+
!denied && keys !== null && keys.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: keys.filter(matchesKeyQuery(keyQuery)).slice(0, visibleCount).map((k) => {
|
|
918
1040
|
const anyBusy = busyAny;
|
|
919
1041
|
const used = relTime2(k.last_used);
|
|
920
1042
|
const created = k.created_at ? new Date(k.created_at).toLocaleDateString() : null;
|
|
@@ -973,6 +1095,24 @@ var ApiKeyWidget = React2.forwardRef(function ApiKeyWidget2({ endpoint = "/api/a
|
|
|
973
1095
|
rowError?.keyId === k.key_id && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { role: "alert", style: { fontSize: 12, color: t.danger, marginTop: 6 }, children: rowError.msg })
|
|
974
1096
|
] }, k.key_id);
|
|
975
1097
|
}) }),
|
|
1098
|
+
!denied && keys !== null && keys.length > 0 && (() => {
|
|
1099
|
+
const matched = keys.filter(matchesKeyQuery(keyQuery));
|
|
1100
|
+
if (matched.length === 0) {
|
|
1101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { padding: "14px 16px", fontSize: 13, color: t.muted }, children: [
|
|
1102
|
+
"No keys match \u201C",
|
|
1103
|
+
keyQuery,
|
|
1104
|
+
"\u201D."
|
|
1105
|
+
] });
|
|
1106
|
+
}
|
|
1107
|
+
if (matched.length <= visibleCount) return null;
|
|
1108
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: "10px 16px", borderTop: `1px solid ${t.border}` }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { style: btn("ghost", true), onClick: () => setVisibleCount((v) => v + 10), children: [
|
|
1109
|
+
"Show more (",
|
|
1110
|
+
Math.min(visibleCount, matched.length),
|
|
1111
|
+
" of ",
|
|
1112
|
+
matched.length,
|
|
1113
|
+
")"
|
|
1114
|
+
] }) });
|
|
1115
|
+
})(),
|
|
976
1116
|
!denied && rowError && rowError.keyId === "" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { role: "alert", style: { padding: "0 16px 14px", fontSize: 12, color: t.danger }, children: rowError.msg })
|
|
977
1117
|
] })
|
|
978
1118
|
] });
|
|
@@ -980,6 +1120,11 @@ var ApiKeyWidget = React2.forwardRef(function ApiKeyWidget2({ endpoint = "/api/a
|
|
|
980
1120
|
function byNewest(a, b) {
|
|
981
1121
|
return new Date(b.created_at ?? 0).getTime() - new Date(a.created_at ?? 0).getTime();
|
|
982
1122
|
}
|
|
1123
|
+
function matchesKeyQuery(q) {
|
|
1124
|
+
const term = q.trim().toLowerCase();
|
|
1125
|
+
if (!term) return () => true;
|
|
1126
|
+
return (k) => `${k.key_prefix ?? ""} ${k.key_suffix ?? ""} ${k.environment ?? ""} ${k.key_id}`.toLowerCase().includes(term);
|
|
1127
|
+
}
|
|
983
1128
|
var react_default = ApiKeyWidget;
|
|
984
1129
|
// Annotate the CommonJS export names for ESM import in node:
|
|
985
1130
|
0 && (module.exports = {
|
package/dist/react/index.mjs
CHANGED
|
@@ -109,9 +109,15 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
109
109
|
const [groups, setGroups] = React.useState(null);
|
|
110
110
|
const [groupTotal, setGroupTotal] = React.useState(0);
|
|
111
111
|
const [groupQuery, setGroupQuery] = React.useState("");
|
|
112
|
+
const [users, setUsers] = React.useState([]);
|
|
113
|
+
const [userTotal, setUserTotal] = React.useState(0);
|
|
114
|
+
const [userQuery, setUserQuery] = React.useState("");
|
|
112
115
|
const [observed, setObserved] = React.useState([]);
|
|
116
|
+
const [observedTotal, setObservedTotal] = React.useState(0);
|
|
117
|
+
const [observedQuery, setObservedQuery] = React.useState("");
|
|
113
118
|
const [observedNew, setObservedNew] = React.useState(0);
|
|
114
119
|
const [observedLoaded, setObservedLoaded] = React.useState(false);
|
|
120
|
+
const [showObserved, setShowObserved] = React.useState(false);
|
|
115
121
|
const [loadError, setLoadError] = React.useState(null);
|
|
116
122
|
const [open, setOpen] = React.useState(null);
|
|
117
123
|
const [detail, setDetail] = React.useState(null);
|
|
@@ -141,6 +147,9 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
141
147
|
setMyEmail(d.email ?? null);
|
|
142
148
|
setGroups(d.groups ?? []);
|
|
143
149
|
setGroupTotal(d.groupTotal ?? (d.groups?.length ?? 0));
|
|
150
|
+
setUsers(d.users ?? []);
|
|
151
|
+
setUserTotal(d.userTotal ?? (d.users?.length ?? 0));
|
|
152
|
+
setUserQuery("");
|
|
144
153
|
setObservedNew(d.observedNew ?? 0);
|
|
145
154
|
setObservedLoaded(false);
|
|
146
155
|
setGroupQuery("");
|
|
@@ -168,11 +177,30 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
168
177
|
setGroups((prev) => [...prev ?? [], ...d.groups ?? []]);
|
|
169
178
|
if (typeof d.total === "number") setGroupTotal(d.total);
|
|
170
179
|
}, [call, groupQuery, groups]);
|
|
171
|
-
const
|
|
172
|
-
|
|
180
|
+
const searchUsers = React.useCallback(async (q) => {
|
|
181
|
+
setUserQuery(q);
|
|
182
|
+
const d = await call({ action: "search-users", q, limit: 25, offset: 0 });
|
|
183
|
+
setUsers(d.users ?? []);
|
|
184
|
+
setUserTotal(d.total ?? (d.users?.length ?? 0));
|
|
185
|
+
}, [call]);
|
|
186
|
+
const loadMoreUsers = React.useCallback(async () => {
|
|
187
|
+
const d = await call({ action: "search-users", q: userQuery, limit: 25, offset: users.length });
|
|
188
|
+
setUsers((prev) => [...prev, ...d.users ?? []]);
|
|
189
|
+
if (typeof d.total === "number") setUserTotal(d.total);
|
|
190
|
+
}, [call, userQuery, users]);
|
|
191
|
+
const searchObserved = React.useCallback(async (q) => {
|
|
192
|
+
setObservedQuery(q);
|
|
193
|
+
const d = await call({ action: "list-observed", q, offset: 0 });
|
|
173
194
|
setObserved(d.identities ?? []);
|
|
195
|
+
setObservedTotal(d.total ?? (d.identities?.length ?? 0));
|
|
174
196
|
setObservedLoaded(true);
|
|
175
197
|
}, [call]);
|
|
198
|
+
const loadObserved = React.useCallback(() => searchObserved(""), [searchObserved]);
|
|
199
|
+
const loadMoreObserved = React.useCallback(async () => {
|
|
200
|
+
const d = await call({ action: "list-observed", q: observedQuery, offset: observed.length });
|
|
201
|
+
setObserved((prev) => [...prev, ...d.identities ?? []]);
|
|
202
|
+
if (typeof d.total === "number") setObservedTotal(d.total);
|
|
203
|
+
}, [call, observedQuery, observed]);
|
|
176
204
|
const loadDetail = React.useCallback(async (groupId) => {
|
|
177
205
|
setDetailLoading(true);
|
|
178
206
|
setDetail(null);
|
|
@@ -243,7 +271,8 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
243
271
|
if (!ref2) return;
|
|
244
272
|
await act("create-user", { action: "create-user", ref: ref2 }, async () => {
|
|
245
273
|
setNewUserRef("");
|
|
246
|
-
|
|
274
|
+
setShowNewUser(false);
|
|
275
|
+
await searchUsers("");
|
|
247
276
|
});
|
|
248
277
|
}
|
|
249
278
|
const vars = {
|
|
@@ -287,10 +316,8 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
287
316
|
/* @__PURE__ */ jsx("strong", { style: { fontSize: 15 }, children: title }),
|
|
288
317
|
access === "ok" && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
289
318
|
/* @__PURE__ */ jsx("button", { style: btn("ghost", true), disabled: busy, onClick: () => {
|
|
290
|
-
|
|
291
|
-
setShowNewUser(nv);
|
|
319
|
+
setShowNewUser((v) => !v);
|
|
292
320
|
setShowCreate(false);
|
|
293
|
-
if (nv && !observedLoaded) loadObserved();
|
|
294
321
|
}, "aria-label": "Add a new user", children: "+ New user" }),
|
|
295
322
|
/* @__PURE__ */ jsx("button", { style: btn("primary", true), disabled: busy, onClick: () => {
|
|
296
323
|
setShowCreate((v) => !v);
|
|
@@ -345,8 +372,12 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
345
372
|
setNewName("");
|
|
346
373
|
}, children: "Cancel" })
|
|
347
374
|
] }),
|
|
348
|
-
access === "ok" &&
|
|
349
|
-
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
|
|
375
|
+
access === "ok" && /* @__PURE__ */ jsxs("div", { style: { borderBottom: `1px solid ${t.border}` }, children: [
|
|
376
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "12px 16px 6px" }, children: [
|
|
377
|
+
/* @__PURE__ */ jsx("strong", { style: { fontSize: 13 }, children: "Users" }),
|
|
378
|
+
/* @__PURE__ */ jsx("span", { style: chip, children: userTotal })
|
|
379
|
+
] }),
|
|
380
|
+
showNewUser && /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, padding: "6px 16px" }, children: [
|
|
350
381
|
/* @__PURE__ */ jsx(
|
|
351
382
|
"input",
|
|
352
383
|
{
|
|
@@ -355,7 +386,8 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
355
386
|
value: newUserRef,
|
|
356
387
|
onChange: (e) => setNewUserRef(e.target.value),
|
|
357
388
|
onKeyDown: (e) => e.key === "Enter" && createUser(),
|
|
358
|
-
"aria-label": "New user email or id"
|
|
389
|
+
"aria-label": "New user email or id",
|
|
390
|
+
autoFocus: true
|
|
359
391
|
}
|
|
360
392
|
),
|
|
361
393
|
/* @__PURE__ */ jsx("button", { style: btn("primary", true), disabled: busy || !newUserRef.trim(), onClick: createUser, children: "Add" }),
|
|
@@ -364,22 +396,77 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
364
396
|
setNewUserRef("");
|
|
365
397
|
}, children: "Cancel" })
|
|
366
398
|
] }),
|
|
367
|
-
/* @__PURE__ */ jsxs("div", { style: {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
399
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "6px 16px" }, children: [
|
|
400
|
+
/* @__PURE__ */ jsx(
|
|
401
|
+
"input",
|
|
402
|
+
{
|
|
403
|
+
style: { ...inputStyle, flex: 1 },
|
|
404
|
+
placeholder: "Search users\u2026",
|
|
405
|
+
defaultValue: userQuery,
|
|
406
|
+
onChange: (e) => searchUsers(e.target.value),
|
|
407
|
+
"aria-label": "Search users"
|
|
408
|
+
}
|
|
409
|
+
),
|
|
410
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: 12, color: t.muted, whiteSpace: "nowrap" }, children: [
|
|
411
|
+
users.length,
|
|
412
|
+
" of ",
|
|
413
|
+
userTotal
|
|
414
|
+
] })
|
|
373
415
|
] }),
|
|
374
|
-
/* @__PURE__ */
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
416
|
+
users.length === 0 && /* @__PURE__ */ jsx("div", { style: { padding: "6px 16px 12px", fontSize: 13, color: t.muted }, children: userQuery ? `No users match \u201C${userQuery}\u201D.` : "No users yet \u2014 add one with + New user." }),
|
|
417
|
+
/* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: "0 16px 8px" }, children: users.map((u) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: 8, alignItems: "center", padding: "5px 0", flexWrap: "wrap" }, children: [
|
|
418
|
+
/* @__PURE__ */ jsx("span", { style: { flex: 1, minWidth: 140, fontSize: 13 }, children: userLabel(u) }),
|
|
419
|
+
u.email && u.email !== userLabel(u) && /* @__PURE__ */ jsx("span", { style: { fontSize: 12, color: t.muted, fontFamily: t.monoFontFamily }, children: u.email }),
|
|
420
|
+
u.source_label && /* @__PURE__ */ jsx("span", { style: chip, children: u.source_label }),
|
|
421
|
+
u.status && u.status !== "active" && /* @__PURE__ */ jsx("span", { style: { ...chip, color: t.danger, borderColor: t.danger }, children: u.status })
|
|
422
|
+
] }, u.abz_sub)) }),
|
|
423
|
+
users.length < userTotal && /* @__PURE__ */ jsx("div", { style: { padding: "0 16px 12px" }, children: /* @__PURE__ */ jsxs("button", { style: btn("ghost", true), disabled: busy, onClick: loadMoreUsers, children: [
|
|
424
|
+
"Load more (",
|
|
425
|
+
users.length,
|
|
426
|
+
" of ",
|
|
427
|
+
userTotal,
|
|
428
|
+
")"
|
|
429
|
+
] }) })
|
|
430
|
+
] }),
|
|
431
|
+
access === "ok" && /* @__PURE__ */ jsxs("div", { style: { borderBottom: `1px solid ${t.border}` }, children: [
|
|
432
|
+
/* @__PURE__ */ jsxs(
|
|
433
|
+
"button",
|
|
434
|
+
{
|
|
435
|
+
onClick: () => {
|
|
436
|
+
const nv = !showObserved;
|
|
437
|
+
setShowObserved(nv);
|
|
438
|
+
if (nv && !observedLoaded) loadObserved();
|
|
439
|
+
},
|
|
440
|
+
"aria-expanded": showObserved,
|
|
441
|
+
style: { display: "flex", width: "100%", gap: 10, alignItems: "center", padding: "12px 16px", background: "transparent", border: "none", cursor: "pointer", color: t.text, fontFamily: "inherit", fontSize: 13, textAlign: "left" },
|
|
442
|
+
children: [
|
|
443
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: { color: t.muted, fontSize: 11 }, children: showObserved ? "\u25BE" : "\u25B8" }),
|
|
444
|
+
/* @__PURE__ */ jsx("strong", { style: { flex: 1 }, children: "Candidates seen in traffic" }),
|
|
445
|
+
observedNew > 0 && /* @__PURE__ */ jsx("span", { style: chip, children: observedNew })
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
),
|
|
449
|
+
showObserved && /* @__PURE__ */ jsxs("div", { style: { padding: "0 16px 12px 34px" }, children: [
|
|
450
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", marginBottom: 6 }, children: [
|
|
451
|
+
/* @__PURE__ */ jsx(
|
|
452
|
+
"input",
|
|
453
|
+
{
|
|
454
|
+
style: { ...inputStyle, flex: 1 },
|
|
455
|
+
placeholder: "Search candidates\u2026",
|
|
456
|
+
defaultValue: observedQuery,
|
|
457
|
+
onChange: (e) => searchObserved(e.target.value),
|
|
458
|
+
"aria-label": "Search candidates seen in traffic"
|
|
459
|
+
}
|
|
460
|
+
),
|
|
461
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: 12, color: t.muted, whiteSpace: "nowrap" }, children: [
|
|
462
|
+
observed.length,
|
|
463
|
+
" of ",
|
|
464
|
+
observedTotal
|
|
465
|
+
] })
|
|
379
466
|
] }),
|
|
380
467
|
!observedLoaded && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: t.muted }, children: "Loading\u2026" }),
|
|
381
|
-
observedLoaded && observed.
|
|
382
|
-
/* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: observed.
|
|
468
|
+
observedLoaded && observed.length === 0 && /* @__PURE__ */ jsx("div", { style: { fontSize: 12, color: t.muted }, children: observedQuery ? `No candidates match \u201C${observedQuery}\u201D.` : "Nothing yet \u2014 identities appear here after their first API call." }),
|
|
469
|
+
/* @__PURE__ */ jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: observed.map((o) => /* @__PURE__ */ jsxs("li", { style: { display: "flex", gap: 8, alignItems: "center", padding: "5px 0", flexWrap: "wrap" }, children: [
|
|
383
470
|
/* @__PURE__ */ jsx("span", { style: { flex: 1, minWidth: 140, fontFamily: t.monoFontFamily, fontSize: 13 }, children: o.email || o.abz_sub }),
|
|
384
471
|
o.source_label && /* @__PURE__ */ jsx("span", { style: chip, children: o.source_label }),
|
|
385
472
|
o.last_seen && /* @__PURE__ */ jsxs("span", { style: { fontSize: 11, color: t.muted }, children: [
|
|
@@ -387,17 +474,31 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
387
474
|
relTime(o.last_seen),
|
|
388
475
|
o.seen_count ? ` \xB7 ${o.seen_count}\xD7` : ""
|
|
389
476
|
] }),
|
|
390
|
-
/* @__PURE__ */ jsx(
|
|
477
|
+
o.provisioned ? /* @__PURE__ */ jsx("span", { style: { ...chip, color: t.success, borderColor: t.success }, children: "user \u2713" }) : /* @__PURE__ */ jsx(
|
|
391
478
|
"button",
|
|
392
479
|
{
|
|
393
480
|
style: btn("ghost", true),
|
|
394
481
|
disabled: busy,
|
|
395
482
|
"aria-label": `Add ${o.email || o.abz_sub} as a user`,
|
|
396
|
-
onClick: () => act(
|
|
483
|
+
onClick: () => act(
|
|
484
|
+
`provision:${o.abz_sub}`,
|
|
485
|
+
{ action: "provision-observed", consumerUserId: o.abz_sub, email: o.email ?? void 0 },
|
|
486
|
+
async () => {
|
|
487
|
+
await searchObserved(observedQuery);
|
|
488
|
+
await searchUsers("");
|
|
489
|
+
}
|
|
490
|
+
),
|
|
397
491
|
children: "Add"
|
|
398
492
|
}
|
|
399
493
|
)
|
|
400
|
-
] }, o.abz_sub)) })
|
|
494
|
+
] }, o.abz_sub)) }),
|
|
495
|
+
observed.length < observedTotal && /* @__PURE__ */ jsxs("button", { style: { ...btn("ghost", true), marginTop: 6 }, disabled: busy, onClick: loadMoreObserved, children: [
|
|
496
|
+
"Load more (",
|
|
497
|
+
observed.length,
|
|
498
|
+
" of ",
|
|
499
|
+
observedTotal,
|
|
500
|
+
")"
|
|
501
|
+
] })
|
|
401
502
|
] })
|
|
402
503
|
] }),
|
|
403
504
|
access === "ok" && groups === null && !loadError && /* @__PURE__ */ jsx("div", { "aria-busy": "true", style: { padding: 24, color: t.muted }, children: "Loading groups\u2026" }),
|
|
@@ -406,24 +507,30 @@ var UsersGroupsWidget = React.forwardRef(function UsersGroupsWidget2({ endpoint
|
|
|
406
507
|
" ",
|
|
407
508
|
/* @__PURE__ */ jsx("button", { style: { ...btn("ghost", true), marginLeft: 6 }, onClick: load, children: "Retry" })
|
|
408
509
|
] }),
|
|
409
|
-
access === "ok" && groups !== null &&
|
|
410
|
-
/* @__PURE__ */
|
|
411
|
-
"
|
|
412
|
-
{
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
510
|
+
access === "ok" && groups !== null && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
511
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "12px 16px 6px" }, children: [
|
|
512
|
+
/* @__PURE__ */ jsx("strong", { style: { fontSize: 13 }, children: "Groups" }),
|
|
513
|
+
/* @__PURE__ */ jsx("span", { style: chip, children: groupTotal })
|
|
514
|
+
] }),
|
|
515
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "6px 16px 10px", borderBottom: `1px solid ${t.border}` }, children: [
|
|
516
|
+
/* @__PURE__ */ jsx(
|
|
517
|
+
"input",
|
|
518
|
+
{
|
|
519
|
+
style: { ...inputStyle, flex: 1 },
|
|
520
|
+
placeholder: "Search groups\u2026",
|
|
521
|
+
defaultValue: groupQuery,
|
|
522
|
+
onChange: (e) => {
|
|
523
|
+
const v = e.target.value;
|
|
524
|
+
searchGroups(v);
|
|
525
|
+
},
|
|
526
|
+
"aria-label": "Search groups"
|
|
527
|
+
}
|
|
528
|
+
),
|
|
529
|
+
/* @__PURE__ */ jsxs("span", { style: { fontSize: 12, color: t.muted, whiteSpace: "nowrap" }, children: [
|
|
530
|
+
groups.length,
|
|
531
|
+
" of ",
|
|
532
|
+
groupTotal
|
|
533
|
+
] })
|
|
427
534
|
] })
|
|
428
535
|
] }),
|
|
429
536
|
access === "ok" && groups !== null && groups.length === 0 && /* @__PURE__ */ jsx("div", { style: { padding: "28px 20px", textAlign: "center", color: t.muted }, children: groupQuery ? `No groups match \u201C${groupQuery}\u201D.` : "No groups yet. Create one to start organizing your users." }),
|
|
@@ -696,6 +803,8 @@ var ApiKeyWidget = React2.forwardRef(function ApiKeyWidget2({ endpoint = "/api/a
|
|
|
696
803
|
const [confirming, setConfirming] = React2.useState(null);
|
|
697
804
|
const [rowError, setRowError] = React2.useState(null);
|
|
698
805
|
const [copied, setCopied] = React2.useState(false);
|
|
806
|
+
const [keyQuery, setKeyQuery] = React2.useState("");
|
|
807
|
+
const [visibleCount, setVisibleCount] = React2.useState(10);
|
|
699
808
|
const call = React2.useCallback(async (body) => {
|
|
700
809
|
const res = await fetch(endpoint, body ? { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) } : { cache: "no-store" });
|
|
701
810
|
const data = await res.json().catch(() => ({}));
|
|
@@ -879,7 +988,20 @@ var ApiKeyWidget = React2.forwardRef(function ApiKeyWidget2({ endpoint = "/api/a
|
|
|
879
988
|
/* @__PURE__ */ jsx2("button", { style: { ...btn("primary"), ...disabledStyle(creating) }, disabled: creating, onClick: create, children: creating ? "Creating\u2026" : "Create API key" })
|
|
880
989
|
] })
|
|
881
990
|
] }),
|
|
882
|
-
!denied && keys !== null && keys.length >
|
|
991
|
+
!denied && keys !== null && keys.length > 5 && /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: 8, alignItems: "center", padding: "10px 16px", borderBottom: `1px solid ${t.border}` }, children: /* @__PURE__ */ jsx2(
|
|
992
|
+
"input",
|
|
993
|
+
{
|
|
994
|
+
value: keyQuery,
|
|
995
|
+
onChange: (e) => {
|
|
996
|
+
setKeyQuery(e.target.value);
|
|
997
|
+
setVisibleCount(10);
|
|
998
|
+
},
|
|
999
|
+
placeholder: "Search keys\u2026",
|
|
1000
|
+
"aria-label": "Search keys",
|
|
1001
|
+
style: { flex: 1, fontFamily: "inherit", fontSize: 13, padding: "6px 10px", borderRadius: 8, border: `1px solid ${t.border}`, background: t.surface, color: t.text, minWidth: 0 }
|
|
1002
|
+
}
|
|
1003
|
+
) }),
|
|
1004
|
+
!denied && keys !== null && keys.length > 0 && /* @__PURE__ */ jsx2("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: keys.filter(matchesKeyQuery(keyQuery)).slice(0, visibleCount).map((k) => {
|
|
883
1005
|
const anyBusy = busyAny;
|
|
884
1006
|
const used = relTime2(k.last_used);
|
|
885
1007
|
const created = k.created_at ? new Date(k.created_at).toLocaleDateString() : null;
|
|
@@ -938,6 +1060,24 @@ var ApiKeyWidget = React2.forwardRef(function ApiKeyWidget2({ endpoint = "/api/a
|
|
|
938
1060
|
rowError?.keyId === k.key_id && /* @__PURE__ */ jsx2("div", { role: "alert", style: { fontSize: 12, color: t.danger, marginTop: 6 }, children: rowError.msg })
|
|
939
1061
|
] }, k.key_id);
|
|
940
1062
|
}) }),
|
|
1063
|
+
!denied && keys !== null && keys.length > 0 && (() => {
|
|
1064
|
+
const matched = keys.filter(matchesKeyQuery(keyQuery));
|
|
1065
|
+
if (matched.length === 0) {
|
|
1066
|
+
return /* @__PURE__ */ jsxs2("div", { style: { padding: "14px 16px", fontSize: 13, color: t.muted }, children: [
|
|
1067
|
+
"No keys match \u201C",
|
|
1068
|
+
keyQuery,
|
|
1069
|
+
"\u201D."
|
|
1070
|
+
] });
|
|
1071
|
+
}
|
|
1072
|
+
if (matched.length <= visibleCount) return null;
|
|
1073
|
+
return /* @__PURE__ */ jsx2("div", { style: { padding: "10px 16px", borderTop: `1px solid ${t.border}` }, children: /* @__PURE__ */ jsxs2("button", { style: btn("ghost", true), onClick: () => setVisibleCount((v) => v + 10), children: [
|
|
1074
|
+
"Show more (",
|
|
1075
|
+
Math.min(visibleCount, matched.length),
|
|
1076
|
+
" of ",
|
|
1077
|
+
matched.length,
|
|
1078
|
+
")"
|
|
1079
|
+
] }) });
|
|
1080
|
+
})(),
|
|
941
1081
|
!denied && rowError && rowError.keyId === "" && /* @__PURE__ */ jsx2("div", { role: "alert", style: { padding: "0 16px 14px", fontSize: 12, color: t.danger }, children: rowError.msg })
|
|
942
1082
|
] })
|
|
943
1083
|
] });
|
|
@@ -945,6 +1085,11 @@ var ApiKeyWidget = React2.forwardRef(function ApiKeyWidget2({ endpoint = "/api/a
|
|
|
945
1085
|
function byNewest(a, b) {
|
|
946
1086
|
return new Date(b.created_at ?? 0).getTime() - new Date(a.created_at ?? 0).getTime();
|
|
947
1087
|
}
|
|
1088
|
+
function matchesKeyQuery(q) {
|
|
1089
|
+
const term = q.trim().toLowerCase();
|
|
1090
|
+
if (!term) return () => true;
|
|
1091
|
+
return (k) => `${k.key_prefix ?? ""} ${k.key_suffix ?? ""} ${k.environment ?? ""} ${k.key_id}`.toLowerCase().includes(term);
|
|
1092
|
+
}
|
|
948
1093
|
var react_default = ApiKeyWidget;
|
|
949
1094
|
export {
|
|
950
1095
|
ApiKeyWidget,
|
package/dist/server/index.js
CHANGED
|
@@ -109,17 +109,26 @@ function createApiblazeGroups(cfg) {
|
|
|
109
109
|
async function run(user, op) {
|
|
110
110
|
const { tenant } = await context(user);
|
|
111
111
|
if (op.action === "snapshot") {
|
|
112
|
-
const [groupsRes, observedRes] = await Promise.all([
|
|
112
|
+
const [groupsRes, usersRes, observedRes] = await Promise.all([
|
|
113
113
|
iam("GET", "/groups", user, tenant, void 0, { limit: "25" }),
|
|
114
|
+
iam("GET", "/users", user, tenant, void 0, { limit: "25" }),
|
|
114
115
|
iam("GET", "/observed-identities", user, tenant, void 0, { limit: "1" })
|
|
115
116
|
]);
|
|
116
|
-
if (groupsRes.status === 403) return { status: 200, data: { access: "pending", email: user.email ?? null, groups: [], groupTotal: 0, observedNew: 0 } };
|
|
117
|
+
if (groupsRes.status === 403) return { status: 200, data: { access: "pending", email: user.email ?? null, groups: [], groupTotal: 0, users: [], userTotal: 0, observedNew: 0 } };
|
|
117
118
|
if (!groupsRes.ok) return { status: groupsRes.status, data: { error: await safeErr(groupsRes) } };
|
|
118
119
|
const g = await groupsRes.json();
|
|
120
|
+
const u = usersRes.ok ? await usersRes.json() : {};
|
|
119
121
|
const o = observedRes.ok ? await observedRes.json() : {};
|
|
120
122
|
return {
|
|
121
123
|
status: 200,
|
|
122
|
-
data: {
|
|
124
|
+
data: {
|
|
125
|
+
access: "ok",
|
|
126
|
+
groups: g.groups ?? [],
|
|
127
|
+
groupTotal: g.total ?? (g.groups?.length ?? 0),
|
|
128
|
+
users: u.users ?? [],
|
|
129
|
+
userTotal: u.total ?? (u.users?.length ?? 0),
|
|
130
|
+
observedNew: o.total ?? 0
|
|
131
|
+
}
|
|
123
132
|
};
|
|
124
133
|
}
|
|
125
134
|
switch (op.action) {
|
package/dist/server/index.mjs
CHANGED
|
@@ -81,17 +81,26 @@ function createApiblazeGroups(cfg) {
|
|
|
81
81
|
async function run(user, op) {
|
|
82
82
|
const { tenant } = await context(user);
|
|
83
83
|
if (op.action === "snapshot") {
|
|
84
|
-
const [groupsRes, observedRes] = await Promise.all([
|
|
84
|
+
const [groupsRes, usersRes, observedRes] = await Promise.all([
|
|
85
85
|
iam("GET", "/groups", user, tenant, void 0, { limit: "25" }),
|
|
86
|
+
iam("GET", "/users", user, tenant, void 0, { limit: "25" }),
|
|
86
87
|
iam("GET", "/observed-identities", user, tenant, void 0, { limit: "1" })
|
|
87
88
|
]);
|
|
88
|
-
if (groupsRes.status === 403) return { status: 200, data: { access: "pending", email: user.email ?? null, groups: [], groupTotal: 0, observedNew: 0 } };
|
|
89
|
+
if (groupsRes.status === 403) return { status: 200, data: { access: "pending", email: user.email ?? null, groups: [], groupTotal: 0, users: [], userTotal: 0, observedNew: 0 } };
|
|
89
90
|
if (!groupsRes.ok) return { status: groupsRes.status, data: { error: await safeErr(groupsRes) } };
|
|
90
91
|
const g = await groupsRes.json();
|
|
92
|
+
const u = usersRes.ok ? await usersRes.json() : {};
|
|
91
93
|
const o = observedRes.ok ? await observedRes.json() : {};
|
|
92
94
|
return {
|
|
93
95
|
status: 200,
|
|
94
|
-
data: {
|
|
96
|
+
data: {
|
|
97
|
+
access: "ok",
|
|
98
|
+
groups: g.groups ?? [],
|
|
99
|
+
groupTotal: g.total ?? (g.groups?.length ?? 0),
|
|
100
|
+
users: u.users ?? [],
|
|
101
|
+
userTotal: u.total ?? (u.users?.length ?? 0),
|
|
102
|
+
observedNew: o.total ?? 0
|
|
103
|
+
}
|
|
95
104
|
};
|
|
96
105
|
}
|
|
97
106
|
switch (op.action) {
|