MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / AdminUsersPage

Function AdminUsersPage

packages/react/src/pages/admin-users.tsx:605–808  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

603// ── Page ────────────────────────────────────────────────────────────────────
604
605export function AdminUsersPage() {
606 useExecutorDocumentTitle("Users");
607 const [offset, setOffset] = useState(0);
608 const [selected, setSelected] = useState<AdminUserRow | null>(null);
609 const search = useDebouncedSearch();
610
611 // A new term is a new list, so it starts on its first page: an offset kept
612 // from a broader list would land past the end of a narrower one.
613 const page = { limit: ADMIN_USERS_PAGE_SIZE, offset, search: search.term };
614 const result = useAtomValue(adminUsersWithConnectionsAtom(page));
615 const refresh = useAtomRefresh(adminUsersWithConnectionsAtom(page));
616 const catalog = useCatalogRows();
617 const icons = useIntegrationIcons();
618 // The route is `/{-$orgSlug}/users`: the segment is OPTIONAL, so this reads
619 // `undefined` on any host that renders no segment and the link falls back to
620 // the bare form. Both cloud and self-host do canonicalize onto a slug (self-
621 // host onto `default`), so in practice the prefixed form is what ships — but
622 // the optional param is the contract, not an assumption about the host.
623 const { orgSlug } = useParams({ strict: false }) as { orgSlug?: string };
624
625 const header = (
626 <PageHeader
627 title="Users"
628 description="Everyone who has used this workspace, and what each of them has connected."
629 />
630 );
631
632 const loading = (
633 <div className="flex flex-col gap-2">
634 {[0, 1, 2, 3].map((row) => (
635 <Skeleton key={row} className="h-14" />
636 ))}
637 </div>
638 );
639
640 const searching = search.term !== "";
641
642 return (
643 <PageContainer>
644 {header}
645
646 <UserSearch
647 value={search.typed}
648 onChange={(value) => {
649 search.setTyped(value);
650 setOffset(0);
651 }}
652 onClear={() => {
653 search.clear();
654 setOffset(0);
655 }}
656 />
657
658 {isAsyncResultLoading(result)
659 ? loading
660 : AsyncResult.match(result, {
661 onInitial: () => loading,
662 onFailure: (failure) =>

Callers

nothing calls this directly

Calls 12

useExecutorDocumentTitleFunction · 0.90
isAsyncResultLoadingFunction · 0.90
splitPageFunction · 0.90
formatAdminDateFunction · 0.90
lastSeenTitleFunction · 0.90
formatLastSeenFunction · 0.90
pageNumberFunction · 0.90
useDebouncedSearchFunction · 0.85
useCatalogRowsFunction · 0.85
useIntegrationIconsFunction · 0.85
isAccessDeniedFunction · 0.85
clearMethod · 0.80

Tested by

no test coverage detected