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

Function OrgPage

packages/react/src/pages/org.tsx:146–487  ·  view source on GitHub ↗
(props: {
  domainsSection?: React.ReactNode;
  // Cloud injects the plan-upgrade call to action (a link to billing/plans).
  // When set and the org is at its seat limit, clicking "Invite member" opens
  // an upgrade prompt instead of the invite form. Self-host has no seat limit,
  // so it never reaches this and can omit it.
  upgradeAction?: React.ReactNode;
  // Cloud injects a destructive "delete organization" section here. It hangs
  // off the cloud-only `/auth/delete-organization` endpoint (WorkOS + billing
  // teardown), so self-host omits it. Rendered last, below members.
  dangerZoneSection?: React.ReactNode;
})

Source from the content-addressed store, hash-verified

144}
145
146export function OrgPage(props: {
147 domainsSection?: React.ReactNode;
148 // Cloud injects the plan-upgrade call to action (a link to billing/plans).
149 // When set and the org is at its seat limit, clicking "Invite member" opens
150 // an upgrade prompt instead of the invite form. Self-host has no seat limit,
151 // so it never reaches this and can omit it.
152 upgradeAction?: React.ReactNode;
153 // Cloud injects a destructive "delete organization" section here. It hangs
154 // off the cloud-only `/auth/delete-organization` endpoint (WorkOS + billing
155 // teardown), so self-host omits it. Rendered last, below members.
156 dangerZoneSection?: React.ReactNode;
157}) {
158 useExecutorDocumentTitle("Organization");
159 const auth = useAuth();
160 const organizationName =
161 auth.status === "authenticated" ? (auth.organization?.name ?? "Organization") : "Organization";
162 const membersResult = useAtomValue(orgMembersAtom);
163 const refreshMembers = useAtomRefresh(orgMembersAtom);
164 const rolesResult = useAtomValue(orgRolesAtom);
165 const doRemove = useAtomSet(removeMember, { mode: "promiseExit" });
166 const [removingMember, setRemovingMember] = useState<{ id: string; name: string } | null>(null);
167 const doUpdateRole = useAtomSet(updateMemberRole, { mode: "promiseExit" });
168 const doUpdateOrgName = useAtomSet(updateOrgName, { mode: "promiseExit" });
169 const [inviteOpen, setInviteOpen] = useState(false);
170 const [upgradeOpen, setUpgradeOpen] = useState(false);
171 const [editName, setEditName] = useState(organizationName);
172 const [savingName, setSavingName] = useState(false);
173 const [search, setSearch] = useState("");
174
175 const roles = AsyncResult.match(rolesResult, {
176 onInitial: () => [] as readonly RoleData[],
177 onFailure: () => [] as readonly RoleData[],
178 onSuccess: ({ value }) => value.roles,
179 });
180
181 const seats = AsyncResult.match(membersResult, {
182 onInitial: () => undefined,
183 onFailure: () => undefined,
184 onSuccess: ({ value }) => value.seats,
185 });
186 // At the plan's member-seat limit, "Invite member" opens an upgrade prompt
187 // (when cloud provided one) instead of the invite form, so the admin gets a
188 // clear next step rather than a refused invite.
189 const atSeatLimit = !!seats && !seats.unlimited && seats.used >= seats.granted;
190 const showUpgradeOnInvite = atSeatLimit && !!props.upgradeAction;
191
192 const handleRemove = async (membershipId: string, name: string) => {
193 setRemovingMember(null);
194 const exit = await doRemove({
195 params: { membershipId },
196 reactivityKeys: orgMemberWriteKeys,
197 });
198 trackEvent("org_member_removed", { success: Exit.isSuccess(exit) });
199 toast[Exit.isSuccess(exit) ? "success" : "error"](
200 Exit.isSuccess(exit) ? `Removed ${name}` : "Failed to remove member",
201 );
202 };
203

Callers

nothing calls this directly

Calls 7

useExecutorDocumentTitleFunction · 0.90
useAuthFunction · 0.90
isAsyncResultLoadingFunction · 0.90
handleSaveNameFunction · 0.85
formatLastActiveFunction · 0.85
handleChangeRoleFunction · 0.85
handleRemoveFunction · 0.70

Tested by

no test coverage detected