@stigmer/react 3.30.0 → 3.32.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.
Files changed (78) hide show
  1. package/iam-policy/OrgMembersPanel.d.ts +7 -0
  2. package/iam-policy/OrgMembersPanel.d.ts.map +1 -1
  3. package/iam-policy/OrgMembersPanel.js +28 -12
  4. package/iam-policy/OrgMembersPanel.js.map +1 -1
  5. package/iam-policy/RoleSelector.d.ts +7 -1
  6. package/iam-policy/RoleSelector.d.ts.map +1 -1
  7. package/iam-policy/RoleSelector.js +2 -2
  8. package/iam-policy/RoleSelector.js.map +1 -1
  9. package/iam-policy/useOwnerAssignment.d.ts +23 -0
  10. package/iam-policy/useOwnerAssignment.d.ts.map +1 -0
  11. package/iam-policy/useOwnerAssignment.js +23 -0
  12. package/iam-policy/useOwnerAssignment.js.map +1 -0
  13. package/iam-policy/useRoleSelector.d.ts +6 -1
  14. package/iam-policy/useRoleSelector.d.ts.map +1 -1
  15. package/iam-policy/useRoleSelector.js +11 -3
  16. package/iam-policy/useRoleSelector.js.map +1 -1
  17. package/invitation/InvitationManager.d.ts.map +1 -1
  18. package/invitation/InvitationManager.js +5 -1
  19. package/invitation/InvitationManager.js.map +1 -1
  20. package/oauth-app/OAuthAppDetailPanel.d.ts +5 -1
  21. package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
  22. package/oauth-app/OAuthAppDetailPanel.js +10 -5
  23. package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
  24. package/oauth-app/OAuthAppListPanel.d.ts +11 -3
  25. package/oauth-app/OAuthAppListPanel.d.ts.map +1 -1
  26. package/oauth-app/OAuthAppListPanel.js +4 -4
  27. package/oauth-app/OAuthAppListPanel.js.map +1 -1
  28. package/oauth-app/copy.d.ts +15 -0
  29. package/oauth-app/copy.d.ts.map +1 -0
  30. package/oauth-app/copy.js +15 -0
  31. package/oauth-app/copy.js.map +1 -0
  32. package/oauth-app/useDeleteOAuthApp.d.ts +4 -3
  33. package/oauth-app/useDeleteOAuthApp.d.ts.map +1 -1
  34. package/oauth-app/useDeleteOAuthApp.js +4 -3
  35. package/oauth-app/useDeleteOAuthApp.js.map +1 -1
  36. package/oauth-app/useOAuthAppList.d.ts +6 -4
  37. package/oauth-app/useOAuthAppList.d.ts.map +1 -1
  38. package/oauth-app/useOAuthAppList.js +6 -4
  39. package/oauth-app/useOAuthAppList.js.map +1 -1
  40. package/package.json +5 -5
  41. package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
  42. package/platform-client/PlatformClientDetailPanel.js +9 -4
  43. package/platform-client/PlatformClientDetailPanel.js.map +1 -1
  44. package/platform-client/PlatformClientListPanel.d.ts.map +1 -1
  45. package/platform-client/PlatformClientListPanel.js +2 -1
  46. package/platform-client/PlatformClientListPanel.js.map +1 -1
  47. package/platform-client/expiry.d.ts +4 -0
  48. package/platform-client/expiry.d.ts.map +1 -0
  49. package/platform-client/expiry.js +18 -0
  50. package/platform-client/expiry.js.map +1 -0
  51. package/settings/MembersSection.d.ts.map +1 -1
  52. package/settings/MembersSection.js +1 -1
  53. package/settings/MembersSection.js.map +1 -1
  54. package/settings/OAuthAppsSection.d.ts +9 -1
  55. package/settings/OAuthAppsSection.d.ts.map +1 -1
  56. package/settings/OAuthAppsSection.js +17 -3
  57. package/settings/OAuthAppsSection.js.map +1 -1
  58. package/src/iam-policy/OrgMembersPanel.tsx +38 -8
  59. package/src/iam-policy/RoleSelector.tsx +8 -0
  60. package/src/iam-policy/__tests__/OrgMembersPanel.test.tsx +139 -0
  61. package/src/iam-policy/__tests__/useOwnerAssignment.test.tsx +55 -0
  62. package/src/iam-policy/useOwnerAssignment.ts +40 -0
  63. package/src/iam-policy/useRoleSelector.ts +14 -3
  64. package/src/invitation/InvitationManager.tsx +5 -0
  65. package/src/oauth-app/OAuthAppDetailPanel.tsx +39 -24
  66. package/src/oauth-app/OAuthAppListPanel.tsx +12 -3
  67. package/src/oauth-app/__tests__/OAuthAppDetailPanel.test.tsx +57 -9
  68. package/src/oauth-app/copy.ts +16 -0
  69. package/src/oauth-app/useDeleteOAuthApp.ts +4 -3
  70. package/src/oauth-app/useOAuthAppList.ts +6 -4
  71. package/src/platform-client/PlatformClientDetailPanel.tsx +28 -5
  72. package/src/platform-client/PlatformClientListPanel.tsx +2 -1
  73. package/src/platform-client/__tests__/PlatformClientDetailPanel.test.tsx +45 -3
  74. package/src/platform-client/__tests__/expiry.test.ts +37 -0
  75. package/src/platform-client/expiry.ts +22 -0
  76. package/src/settings/MembersSection.tsx +2 -1
  77. package/src/settings/OAuthAppsSection.tsx +21 -3
  78. package/src/settings/__tests__/OAuthAppsSection.test.tsx +133 -0
@@ -8,6 +8,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js"
8
8
  import { usePlatformClientList } from "./usePlatformClientList.js";
9
9
  import { useDeletePlatformClient } from "./useDeletePlatformClient.js";
10
10
  import { SpinnerIcon } from "../internal/SpinnerIcon.js";
11
+ import { isPlatformClientExpired } from "./expiry.js";
11
12
  /**
12
13
  * Displays a list of {@link PlatformClient} resources for an
13
14
  * organization with inline delete confirmation.
@@ -92,7 +93,7 @@ function ExpiryBadge({ spec }) {
92
93
  }
93
94
  if (spec?.expiresAt) {
94
95
  const date = timestampDate(spec.expiresAt);
95
- const isExpired = date < new Date();
96
+ const isExpired = isPlatformClientExpired(spec);
96
97
  return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: _jsx("time", { dateTime: date.toISOString(), className: cn("stg:text-[0.65rem]", isExpired ? "stg:text-destructive stg:font-medium" : "stg:text-muted-foreground") }), children: isExpired ? "Expired" : `Exp ${formatShortDate(date)}` }), _jsx(TooltipContent, { side: "top", children: `Expires ${date.toISOString()}` })] }));
97
98
  }
98
99
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"PlatformClientListPanel.js","sourceRoot":"","sources":["../../src/platform-client/PlatformClientListPanel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PlatformClientListPanel.js","sourceRoot":"","sources":["../../src/platform-client/PlatformClientListPanel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { PlatformClient } from "@stigmer/protos/ai/stigmer/iam/platformclient/v1/api_pb";
2
+ /** Whether the client's secret no longer mints (its expiry has passed). */
3
+ export declare function isPlatformClientExpired(spec: PlatformClient["spec"], now?: Date): boolean;
4
+ //# sourceMappingURL=expiry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expiry.d.ts","sourceRoot":"","sources":["../../src/platform-client/expiry.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yDAAyD,CAAC;AAE9F,2EAA2E;AAC3E,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAC5B,GAAG,GAAE,IAAiB,GACrB,OAAO,CAKT"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The one rule for "this PlatformClient has expired", shared by the list's
3
+ * expiry badge, the detail view and the rotate confirmation so the three
4
+ * never disagree. It is the server's rule, the one the mint refuses by: an
5
+ * expiry is set, `never_expires` is off, and the expiry has passed.
6
+ *
7
+ * Package-internal on purpose: every name the barrel exports is a public
8
+ * API contract, and no platform builder has asked for this one.
9
+ */
10
+ import { timestampDate } from "@bufbuild/protobuf/wkt";
11
+ /** Whether the client's secret no longer mints (its expiry has passed). */
12
+ export function isPlatformClientExpired(spec, now = new Date()) {
13
+ if (spec === undefined || spec.neverExpires || spec.expiresAt === undefined) {
14
+ return false;
15
+ }
16
+ return timestampDate(spec.expiresAt).getTime() < now.getTime();
17
+ }
18
+ //# sourceMappingURL=expiry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expiry.js","sourceRoot":"","sources":["../../src/platform-client/expiry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD,2EAA2E;AAC3E,MAAM,UAAU,uBAAuB,CACrC,IAA4B,EAC5B,MAAY,IAAI,IAAI,EAAE;IAEtB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC;AACjE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"MembersSection.d.ts","sourceRoot":"","sources":["../../src/settings/MembersSection.tsx"],"names":[],"mappings":"AAQA;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,4CA2D7B"}
1
+ {"version":3,"file":"MembersSection.d.ts","sourceRoot":"","sources":["../../src/settings/MembersSection.tsx"],"names":[],"mappings":"AAQA;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,4CA4D7B"}
@@ -25,6 +25,6 @@ export function MembersSection() {
25
25
  const orgSlug = activeOrg?.metadata?.slug ?? "";
26
26
  const { identityProviders } = useIdentityProviderList(idpAvailable && orgSlug ? orgSlug : null);
27
27
  const hasJitProviders = identityProviders.some((idp) => idp.spec?.autoProvisionAccounts || idp.spec?.isSsoProvider);
28
- return (_jsxs("section", { "aria-labelledby": headingId, children: [_jsx("h2", { id: headingId, className: "stg:text-foreground stg:mb-1 stg:text-sm stg:font-semibold", children: "Members" }), _jsxs("p", { className: "stg:text-muted-foreground stg:mb-4 stg:text-xs", children: ["Manage who has access to this organization and what they can do. Members can be granted owner, admin, member, or viewer roles.", !invitationsAvailable && (_jsxs(_Fragment, { children: [" ", "There are no invitations on this edition: people join this organization the first time they sign in, and you adjust their roles here."] }))] }), !orgId ? (_jsx("p", { className: "stg:text-muted-foreground stg:py-4 stg:text-center stg:text-xs", children: "Select an organization to manage members." })) : (_jsxs(_Fragment, { children: [hasJitProviders && (_jsx("div", { className: "stg:mb-3 stg:rounded-md stg:border stg:border-border-muted stg:bg-muted-faint stg:px-3 stg:py-2", children: _jsx("p", { className: "stg:text-[0.65rem] stg:text-muted-foreground", children: "This organization has identity providers with auto-provisioning enabled. Members may appear here automatically when users authenticate via federated identity." }) })), _jsx(OrgMembersPanel, { orgId: orgId })] }))] }));
28
+ return (_jsxs("section", { "aria-labelledby": headingId, children: [_jsx("h2", { id: headingId, className: "stg:text-foreground stg:mb-1 stg:text-sm stg:font-semibold", children: "Members" }), _jsxs("p", { className: "stg:text-muted-foreground stg:mb-4 stg:text-xs", children: ["Manage who has access to this organization and what they can do. Members can be granted owner, admin, member, or viewer roles; only an owner grants or removes owner.", !invitationsAvailable && (_jsxs(_Fragment, { children: [" ", "There are no invitations on this edition: people join this organization the first time they sign in, and you adjust their roles here."] }))] }), !orgId ? (_jsx("p", { className: "stg:text-muted-foreground stg:py-4 stg:text-center stg:text-xs", children: "Select an organization to manage members." })) : (_jsxs(_Fragment, { children: [hasJitProviders && (_jsx("div", { className: "stg:mb-3 stg:rounded-md stg:border stg:border-border-muted stg:bg-muted-faint stg:px-3 stg:py-2", children: _jsx("p", { className: "stg:text-[0.65rem] stg:text-muted-foreground", children: "This organization has identity providers with auto-provisioning enabled. Members may appear here automatically when users authenticate via federated identity." }) })), _jsx(OrgMembersPanel, { orgId: orgId })] }))] }));
29
29
  }
30
30
  //# sourceMappingURL=MembersSection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MembersSection.js","sourceRoot":"","sources":["../../src/settings/MembersSection.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAE1F;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,SAAS,GAAG,KAAK,EAAE,CAAC;IAC1B,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC;IAC/B,MAAM,oBAAoB,GAAG,oBAAoB,CAC/C,eAAe,CAAC,UAAU,CAC3B,CAAC;IACF,MAAM,YAAY,GAAG,oBAAoB,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,SAAS,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC;IAEhD,MAAM,EAAE,iBAAiB,EAAE,GAAG,uBAAuB,CACnD,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACzC,CAAC;IAEF,MAAM,eAAe,GAAG,iBAAiB,CAAC,IAAI,CAC5C,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,qBAAqB,IAAI,GAAG,CAAC,IAAI,EAAE,aAAa,CACpE,CAAC;IAEF,OAAO,CACL,sCAA0B,SAAS,aACjC,aACE,EAAE,EAAE,SAAS,EACb,SAAS,EAAC,4DAA4D,wBAGnE,EACL,aAAG,SAAS,EAAC,gDAAgD,+IAG1D,CAAC,oBAAoB,IAAI,CACxB,8BACG,GAAG,6IAIH,CACJ,IACC,EAEH,CAAC,KAAK,CAAC,CAAC,CAAC,CACR,YAAG,SAAS,EAAC,gEAAgE,0DAEzE,CACL,CAAC,CAAC,CAAC,CACF,8BACG,eAAe,IAAI,CAClB,cAAK,SAAS,EAAC,iGAAiG,YAC9G,YAAG,SAAS,EAAC,8CAA8C,+KAIvD,GACA,CACP,EACD,KAAC,eAAe,IAAC,KAAK,EAAE,KAAK,GAAI,IAChC,CACJ,IACO,CACX,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"MembersSection.js","sourceRoot":"","sources":["../../src/settings/MembersSection.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iDAAiD,CAAC;AAE1F;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,SAAS,GAAG,KAAK,EAAE,CAAC;IAC1B,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC;IAC/B,MAAM,oBAAoB,GAAG,oBAAoB,CAC/C,eAAe,CAAC,UAAU,CAC3B,CAAC;IACF,MAAM,YAAY,GAAG,oBAAoB,CAAC,eAAe,CAAC,iBAAiB,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,SAAS,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,SAAS,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC;IAEhD,MAAM,EAAE,iBAAiB,EAAE,GAAG,uBAAuB,CACnD,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CACzC,CAAC;IAEF,MAAM,eAAe,GAAG,iBAAiB,CAAC,IAAI,CAC5C,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,qBAAqB,IAAI,GAAG,CAAC,IAAI,EAAE,aAAa,CACpE,CAAC;IAEF,OAAO,CACL,sCAA0B,SAAS,aACjC,aACE,EAAE,EAAE,SAAS,EACb,SAAS,EAAC,4DAA4D,wBAGnE,EACL,aAAG,SAAS,EAAC,gDAAgD,sLAI1D,CAAC,oBAAoB,IAAI,CACxB,8BACG,GAAG,6IAIH,CACJ,IACC,EAEH,CAAC,KAAK,CAAC,CAAC,CAAC,CACR,YAAG,SAAS,EAAC,gEAAgE,0DAEzE,CACL,CAAC,CAAC,CAAC,CACF,8BACG,eAAe,IAAI,CAClB,cAAK,SAAS,EAAC,iGAAiG,YAC9G,YAAG,SAAS,EAAC,8CAA8C,+KAIvD,GACA,CACP,EACD,KAAC,eAAe,IAAC,KAAK,EAAE,KAAK,GAAI,IAChC,CACJ,IACO,CACX,CAAC;AACJ,CAAC"}
@@ -1,3 +1,11 @@
1
- /** Settings section for organization OAuth app credentials. */
1
+ /**
2
+ * Settings section for organization OAuth app credentials.
3
+ *
4
+ * "New OAuth app" is offered once the server confirms the caller holds
5
+ * `can_create_oauth_app` on the organization. The list shows only the apps
6
+ * the caller may view (each app's creator and the organization's admins),
7
+ * so a caller who may not create OAuth apps is told that the
8
+ * organization's admins manage them rather than that none is configured.
9
+ */
2
10
  export declare function OAuthAppsSection(): import("react/jsx-runtime").JSX.Element;
3
11
  //# sourceMappingURL=OAuthAppsSection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OAuthAppsSection.d.ts","sourceRoot":"","sources":["../../src/settings/OAuthAppsSection.tsx"],"names":[],"mappings":"AAgBA,+DAA+D;AAC/D,wBAAgB,gBAAgB,4CAmF/B"}
1
+ {"version":3,"file":"OAuthAppsSection.d.ts","sourceRoot":"","sources":["../../src/settings/OAuthAppsSection.tsx"],"names":[],"mappings":"AAkBA;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,4CA2F/B"}
@@ -4,14 +4,28 @@ import { useCallback, useId, useRef, useState } from "react";
4
4
  import { OAuthAppListPanel } from "../oauth-app/OAuthAppListPanel.js";
5
5
  import { CreateOAuthAppForm } from "../oauth-app/CreateOAuthAppForm.js";
6
6
  import { OAuthAppDetailPanel } from "../oauth-app/OAuthAppDetailPanel.js";
7
+ import { OAUTH_APPS_MANAGED_BY_ADMINS } from "../oauth-app/copy.js";
7
8
  import { useResourceAvailable, ApiResourceKind } from "../deployment-mode.js";
9
+ import { useCheckPermission } from "../iam-policy/useCheckPermission.js";
8
10
  import { CloudFeatureNotice } from "../internal/CloudFeatureNotice.js";
9
- import { useActiveOrgSlug } from "../organization/OrgProvider.js";
10
- /** Settings section for organization OAuth app credentials. */
11
+ import { useActiveOrgId, useActiveOrgSlug } from "../organization/OrgProvider.js";
12
+ /**
13
+ * Settings section for organization OAuth app credentials.
14
+ *
15
+ * "New OAuth app" is offered once the server confirms the caller holds
16
+ * `can_create_oauth_app` on the organization. The list shows only the apps
17
+ * the caller may view (each app's creator and the organization's admins),
18
+ * so a caller who may not create OAuth apps is told that the
19
+ * organization's admins manage them rather than that none is configured.
20
+ */
11
21
  export function OAuthAppsSection() {
12
22
  const headingId = useId();
13
23
  const org = useActiveOrgSlug();
24
+ const orgId = useActiveOrgId();
14
25
  const oauthAppsAvailable = useResourceAvailable(ApiResourceKind.oauth_app);
26
+ const createCheck = useCheckPermission(oauthAppsAvailable && orgId ? { kind: "organization", id: orgId } : null, "can_create_oauth_app");
27
+ const canCreate = !createCheck.isLoading && createCheck.allowed;
28
+ const deniedCreate = !createCheck.isLoading && !createCheck.allowed;
15
29
  const [flow, setFlow] = useState({ phase: "idle" });
16
30
  const listRefetchRef = useRef(null);
17
31
  const handleRefetchRef = useCallback((refetch) => {
@@ -29,6 +43,6 @@ export function OAuthAppsSection() {
29
43
  listRefetchRef.current?.();
30
44
  setFlow({ phase: "idle" });
31
45
  }, []);
32
- return (_jsxs("section", { "aria-labelledby": headingId, children: [_jsxs("div", { className: "stg:mb-3 stg:flex stg:items-center stg:justify-between", children: [_jsx("h2", { id: headingId, className: "stg:text-foreground stg:text-sm stg:font-semibold", children: "OAuth Apps" }), oauthAppsAvailable && org && flow.phase === "idle" && (_jsx("button", { type: "button", onClick: () => setFlow({ phase: "creating" }), className: "stg:text-primary stg:hover:text-foreground stg:text-xs stg:font-medium stg:transition-colors", children: "+ New OAuth app" }))] }), _jsx("p", { className: "stg:text-muted-foreground stg:mb-4 stg:text-xs", children: "OAuth app credentials configured for your organization. Create new apps here or bring your own from an MCP server's detail page." }), !oauthAppsAvailable ? (_jsx(CloudFeatureNotice, { children: "OAuth apps are not available in local mode. Bring-your-own-app OAuth requires the cloud platform." })) : flow.phase === "creating" ? (_jsx("div", { className: "stg:border-border stg:bg-card stg:rounded-lg stg:border stg:p-4", children: _jsx(CreateOAuthAppForm, { org: org, onCreated: handleCreated, onCancel: () => setFlow({ phase: "idle" }) }) })) : flow.phase === "editing" ? (_jsx("div", { className: "stg:border-border stg:bg-card stg:rounded-lg stg:border stg:p-4", children: _jsx(OAuthAppDetailPanel, { oauthApp: flow.oauthApp, onUpdated: handleUpdated, onDeleted: handleDeleted, onBack: () => setFlow({ phase: "idle" }) }) })) : (_jsx(OAuthAppListPanel, { org: org, onEdit: (app) => setFlow({ phase: "editing", oauthApp: app }), onRefetchRef: handleRefetchRef }))] }));
46
+ return (_jsxs("section", { "aria-labelledby": headingId, children: [_jsxs("div", { className: "stg:mb-3 stg:flex stg:items-center stg:justify-between", children: [_jsx("h2", { id: headingId, className: "stg:text-foreground stg:text-sm stg:font-semibold", children: "OAuth Apps" }), oauthAppsAvailable && org && canCreate && flow.phase === "idle" && (_jsx("button", { type: "button", onClick: () => setFlow({ phase: "creating" }), className: "stg:text-primary stg:hover:text-foreground stg:text-xs stg:font-medium stg:transition-colors", children: "+ New OAuth app" }))] }), _jsx("p", { className: "stg:text-muted-foreground stg:mb-4 stg:text-xs", children: "OAuth app credentials configured for your organization. Create new apps here or bring your own from an MCP server's detail page." }), !oauthAppsAvailable ? (_jsx(CloudFeatureNotice, { children: "OAuth apps are not available in local mode. Bring-your-own-app OAuth requires the cloud platform." })) : flow.phase === "creating" ? (_jsx("div", { className: "stg:border-border stg:bg-card stg:rounded-lg stg:border stg:p-4", children: _jsx(CreateOAuthAppForm, { org: org, onCreated: handleCreated, onCancel: () => setFlow({ phase: "idle" }) }) })) : flow.phase === "editing" ? (_jsx("div", { className: "stg:border-border stg:bg-card stg:rounded-lg stg:border stg:p-4", children: _jsx(OAuthAppDetailPanel, { oauthApp: flow.oauthApp, onUpdated: handleUpdated, onDeleted: handleDeleted, onBack: () => setFlow({ phase: "idle" }) }) })) : (_jsx(OAuthAppListPanel, { org: org, onEdit: (app) => setFlow({ phase: "editing", oauthApp: app }), onRefetchRef: handleRefetchRef, emptyState: deniedCreate ? OAUTH_APPS_MANAGED_BY_ADMINS : undefined }))] }));
33
47
  }
34
48
  //# sourceMappingURL=OAuthAppsSection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OAuthAppsSection.js","sourceRoot":"","sources":["../../src/settings/OAuthAppsSection.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OAuthAppsSection.js","sourceRoot":"","sources":["../../src/settings/OAuthAppsSection.tsx"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  import { useCallback, useState } from "react";
4
4
  import { create } from "@bufbuild/protobuf";
5
5
  import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
6
- import type { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
6
+ import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
7
7
  import type { PrincipalAccess, RoleGrant } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/io_pb";
8
8
  import {
9
9
  IamPolicySpecSchema,
@@ -16,6 +16,7 @@ import {
16
16
  iamRoleToString,
17
17
  } from "@stigmer/sdk";
18
18
  import { Tooltip, TooltipContent, TooltipTrigger } from "../internal/tooltip.js";
19
+ import { useOwnerAssignment } from "./useOwnerAssignment.js";
19
20
  import { useResourceAccess } from "./useResourceAccess.js";
20
21
  import { usePrincipalsCount } from "./usePrincipalsCount.js";
21
22
  import { useWhoAmI } from "./useWhoAmI.js";
@@ -52,6 +53,13 @@ export interface OrgMembersPanelProps {
52
53
  * `identityAccount.whoAmI()` for self-protection (disabling
53
54
  * destructive actions on yourself).
54
55
  *
56
+ * Owner is assigned by owners: the server asks `can_assign_roles` on the
57
+ * organization before any change to the owner role. The panel asks the
58
+ * same question once, and for a caller without it offers no owner in the
59
+ * role picker and no change or removal on an owner's row. A role change
60
+ * grants the new role before it revokes the old one, so a refused step
61
+ * leaves the member with the role they had.
62
+ *
55
63
  * All visual properties flow through `--stgm-*` design tokens.
56
64
  *
57
65
  * @example
@@ -69,6 +77,7 @@ export function OrgMembersPanel({
69
77
  const { count, refetch: refetchCount } = usePrincipalsCount(orgId || null);
70
78
  const { account: currentAccount } = useWhoAmI();
71
79
  const currentAccountId = currentAccount?.metadata?.id ?? null;
80
+ const { canAssignOwner, unassignable } = useOwnerAssignment(orgId || null);
72
81
 
73
82
  const [actionMemberId, setActionMemberId] = useState<string | null>(null);
74
83
 
@@ -133,6 +142,8 @@ export function OrgMembersPanel({
133
142
  entry={entry}
134
143
  orgId={orgId}
135
144
  isSelf={memberId === currentAccountId}
145
+ canAssignOwner={canAssignOwner}
146
+ unassignable={unassignable}
136
147
  isActioning={actionMemberId === memberId}
137
148
  onStartAction={() => setActionMemberId(memberId)}
138
149
  onEndAction={() => setActionMemberId(null)}
@@ -154,6 +165,8 @@ function MemberRow({
154
165
  entry,
155
166
  orgId,
156
167
  isSelf,
168
+ canAssignOwner,
169
+ unassignable,
157
170
  isActioning,
158
171
  onStartAction,
159
172
  onEndAction,
@@ -162,6 +175,10 @@ function MemberRow({
162
175
  entry: PrincipalAccess;
163
176
  orgId: string;
164
177
  isSelf: boolean;
178
+ /** Whether the caller may grant, revoke or remove the owner role here. */
179
+ canAssignOwner: boolean;
180
+ /** The roles the caller may not assign, left out of the role picker. */
181
+ unassignable: readonly IamRole[];
165
182
  isActioning: boolean;
166
183
  onStartAction: () => void;
167
184
  onEndAction: () => void;
@@ -177,6 +194,11 @@ function MemberRow({
177
194
  const email = principal?.email ?? "";
178
195
  const initial = name.charAt(0).toUpperCase();
179
196
  const directRoles = entry.roles.filter((r) => !r.isInherited);
197
+ const holdsOwner = directRoles.some(
198
+ (grant) => grant.role?.code === iamRoleToString(IamRole.owner),
199
+ );
200
+ // Changing or removing an owner changes the owner role: an owner's act.
201
+ const mayAct = !isSelf && (canAssignOwner || !holdsOwner);
180
202
 
181
203
  const startAction = (type: "remove" | "change-role") => {
182
204
  setActionType(type);
@@ -208,6 +230,7 @@ function MemberRow({
208
230
  <ChangeRoleRow
209
231
  entry={entry}
210
232
  orgId={orgId}
233
+ omitRoles={unassignable}
211
234
  onDone={() => {
212
235
  cancelAction();
213
236
  onMutated();
@@ -255,7 +278,7 @@ function MemberRow({
255
278
  </div>
256
279
 
257
280
  {/* Actions */}
258
- {!isSelf && (
281
+ {mayAct && (
259
282
  <div className="stg:flex stg:shrink-0 stg:items-center stg:gap-1">
260
283
  <button
261
284
  type="button"
@@ -398,11 +421,14 @@ function RemoveConfirmation({
398
421
  function ChangeRoleRow({
399
422
  entry,
400
423
  orgId,
424
+ omitRoles,
401
425
  onDone,
402
426
  onCancel,
403
427
  }: {
404
428
  entry: PrincipalAccess;
405
429
  orgId: string;
430
+ /** The roles the caller may not assign, left out of the picker. */
431
+ omitRoles: readonly IamRole[];
406
432
  onDone: () => void;
407
433
  onCancel: () => void;
408
434
  }) {
@@ -429,7 +455,10 @@ function ChangeRoleRow({
429
455
  setError(null);
430
456
 
431
457
  try {
432
- const deleteSpec = create(IamPolicySpecSchema, {
458
+ // Grant first, then revoke: a refusal of either step (the owner rule,
459
+ // an organization's last owner) leaves the member holding a role, never
460
+ // none, and the revoke is the one that can be retried.
461
+ const createSpec = create(IamPolicySpecSchema, {
433
462
  principal: create(ApiResourceRefSchema, {
434
463
  kind: "identity_account",
435
464
  id: memberId,
@@ -438,11 +467,11 @@ function ChangeRoleRow({
438
467
  kind: "organization",
439
468
  id: orgId,
440
469
  }),
441
- relation: currentRoleCode,
470
+ relation: iamRoleToString(selectedRole),
442
471
  });
443
- await deletePolicy(deleteSpec);
472
+ await createPolicy(createSpec);
444
473
 
445
- const createSpec = create(IamPolicySpecSchema, {
474
+ const deleteSpec = create(IamPolicySpecSchema, {
446
475
  principal: create(ApiResourceRefSchema, {
447
476
  kind: "identity_account",
448
477
  id: memberId,
@@ -451,9 +480,9 @@ function ChangeRoleRow({
451
480
  kind: "organization",
452
481
  id: orgId,
453
482
  }),
454
- relation: iamRoleToString(selectedRole),
483
+ relation: currentRoleCode,
455
484
  });
456
- await createPolicy(createSpec);
485
+ await deletePolicy(deleteSpec);
457
486
 
458
487
  onDone();
459
488
  } catch (err) {
@@ -482,6 +511,7 @@ function ChangeRoleRow({
482
511
  kind={ApiResourceKind.organization}
483
512
  selected={selectedRole ?? currentRole}
484
513
  onSelect={setSelectedRole}
514
+ omitRoles={omitRoles}
485
515
  disabled={isWorking}
486
516
  />
487
517
 
@@ -25,6 +25,12 @@ export interface RoleSelectorProps {
25
25
  * Defaults to a person.
26
26
  */
27
27
  readonly granteeKind?: GranteeKind;
28
+ /**
29
+ * Roles to leave out even though the kind grants them: the ones the
30
+ * caller may not assign (an organization's `owner`, for anyone who is not
31
+ * its owner). See {@link useRoleSelector}.
32
+ */
33
+ readonly omitRoles?: readonly IamRole[];
28
34
  /** Additional CSS class names for the root container. */
29
35
  readonly className?: string;
30
36
  }
@@ -54,6 +60,7 @@ export function RoleSelector({
54
60
  defaultRole,
55
61
  disabled = false,
56
62
  granteeKind = "identity_account",
63
+ omitRoles,
57
64
  className,
58
65
  }: RoleSelectorProps) {
59
66
  // Instance-scoped radio-group name (oss#593): a hardcoded name would make
@@ -66,6 +73,7 @@ export function RoleSelector({
66
73
  kind,
67
74
  defaultRole,
68
75
  granteeKind,
76
+ omitRoles,
69
77
  );
70
78
 
71
79
  const currentSelected = controlledSelected !== undefined
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Pins OrgMembersPanel's reading of the owner rule (the server asks
3
+ * `can_assign_roles` on the organization before any change to its owner
4
+ * role):
5
+ *
6
+ * - a caller who may not assign owner is offered no change and no removal
7
+ * on an owner's row, and no owner in the role picker for anyone else;
8
+ * an owner is offered all of them;
9
+ * - a role change grants the new role before it revokes the old one, so
10
+ * a refused grant leaves the member with the role they had.
11
+ *
12
+ * The data hooks are stubbed: each is proven by its own tests, and the
13
+ * permission answer is the one question this panel adds.
14
+ */
15
+ import { afterEach, describe, expect, it, vi } from "vitest";
16
+ import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
17
+ import { create } from "@bufbuild/protobuf";
18
+ import {
19
+ PrincipalAccessSchema,
20
+ type PrincipalAccess,
21
+ } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/io_pb";
22
+ import type { IamPolicySpec } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/spec_pb";
23
+ import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
24
+
25
+ const state = vi.hoisted(() => ({
26
+ members: [] as PrincipalAccess[],
27
+ canAssignOwner: false,
28
+ calls: [] as string[],
29
+ createFails: false,
30
+ }));
31
+
32
+ vi.mock("../useResourceAccess.js", () => ({
33
+ useResourceAccess: () => ({
34
+ members: state.members,
35
+ isLoading: false,
36
+ error: null,
37
+ refetch: () => {},
38
+ }),
39
+ }));
40
+ vi.mock("../usePrincipalsCount.js", () => ({
41
+ usePrincipalsCount: () => ({ count: state.members.length, refetch: () => {} }),
42
+ }));
43
+ vi.mock("../useWhoAmI.js", () => ({
44
+ useWhoAmI: () => ({ account: { metadata: { id: "ida_me" } } }),
45
+ }));
46
+ vi.mock("../useOwnerAssignment.js", () => ({
47
+ useOwnerAssignment: () => ({
48
+ canAssignOwner: state.canAssignOwner,
49
+ unassignable: state.canAssignOwner ? [] : [IamRole.owner],
50
+ }),
51
+ }));
52
+ vi.mock("../useRevokeOrgAccess.js", () => ({
53
+ useRevokeOrgAccess: () => ({ revoke: async () => {}, isRevoking: false, error: null }),
54
+ }));
55
+ vi.mock("../useCreateIamPolicy.js", () => ({
56
+ useCreateIamPolicy: () => ({
57
+ create: async (spec: IamPolicySpec) => {
58
+ state.calls.push(`create ${spec.relation}`);
59
+ if (state.createFails) {
60
+ throw new Error("only an owner of the organization can grant, revoke or remove the owner role");
61
+ }
62
+ },
63
+ isCreating: false,
64
+ }),
65
+ }));
66
+ vi.mock("../useDeleteIamPolicy.js", () => ({
67
+ useDeleteIamPolicy: () => ({
68
+ remove: async (spec: IamPolicySpec) => {
69
+ state.calls.push(`delete ${spec.relation}`);
70
+ },
71
+ isDeleting: false,
72
+ }),
73
+ }));
74
+
75
+ import { OrgMembersPanel } from "../OrgMembersPanel";
76
+
77
+ function member(id: string, name: string, role: string): PrincipalAccess {
78
+ return create(PrincipalAccessSchema, {
79
+ principal: { kind: "identity_account", id, name },
80
+ roles: [{ role: { code: role, name: role } }],
81
+ });
82
+ }
83
+
84
+ afterEach(() => {
85
+ cleanup();
86
+ state.members = [];
87
+ state.canAssignOwner = false;
88
+ state.calls = [];
89
+ state.createFails = false;
90
+ });
91
+
92
+ describe("OrgMembersPanel and the owner role", () => {
93
+ it("offers a caller who is no owner nothing on an owner's row, and no owner in the picker", () => {
94
+ state.members = [member("ida_root", "Root", "owner"), member("ida_dave", "Dave", "member")];
95
+ render(<OrgMembersPanel orgId="acme" />);
96
+
97
+ expect(screen.queryByRole("button", { name: "Change role for Root" })).toBeNull();
98
+ expect(screen.queryByRole("button", { name: "Remove Root" })).toBeNull();
99
+ expect(screen.getByRole("button", { name: "Remove Dave" })).toBeTruthy();
100
+
101
+ fireEvent.click(screen.getByRole("button", { name: "Change role for Dave" }));
102
+ expect(screen.queryByRole("radio", { name: /^Owner/ })).toBeNull();
103
+ expect(screen.getByRole("radio", { name: /^Admin/ })).toBeTruthy();
104
+ });
105
+
106
+ it("offers an owner every control on every row, owner in the picker included", () => {
107
+ state.canAssignOwner = true;
108
+ state.members = [member("ida_root", "Root", "owner"), member("ida_dave", "Dave", "member")];
109
+ render(<OrgMembersPanel orgId="acme" />);
110
+
111
+ expect(screen.getByRole("button", { name: "Remove Root" })).toBeTruthy();
112
+ fireEvent.click(screen.getByRole("button", { name: "Change role for Dave" }));
113
+ expect(screen.getByRole("radio", { name: /^Owner/ })).toBeTruthy();
114
+ });
115
+
116
+ it("grants the new role before it revokes the old one", async () => {
117
+ state.canAssignOwner = true;
118
+ state.members = [member("ida_dave", "Dave", "member")];
119
+ render(<OrgMembersPanel orgId="acme" />);
120
+
121
+ fireEvent.click(screen.getByRole("button", { name: "Change role for Dave" }));
122
+ fireEvent.click(screen.getByRole("radio", { name: /^Admin/ }));
123
+ fireEvent.click(screen.getByRole("button", { name: "Confirm" }));
124
+ await waitFor(() => expect(state.calls).toEqual(["create admin", "delete member"]));
125
+ });
126
+
127
+ it("revokes nothing when the new role is refused, so the member keeps the one they had", async () => {
128
+ state.canAssignOwner = true;
129
+ state.createFails = true;
130
+ state.members = [member("ida_dave", "Dave", "member")];
131
+ render(<OrgMembersPanel orgId="acme" />);
132
+
133
+ fireEvent.click(screen.getByRole("button", { name: "Change role for Dave" }));
134
+ fireEvent.click(screen.getByRole("radio", { name: /^Owner/ }));
135
+ fireEvent.click(screen.getByRole("button", { name: "Confirm" }));
136
+ await waitFor(() => expect(screen.getByRole("alert")).toBeTruthy());
137
+ expect(state.calls).toEqual(["create owner"]);
138
+ });
139
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Pins useOwnerAssignment, the console's one reading of the owner rule: it
3
+ * asks `can_assign_roles` on the organization it is given (and nothing
4
+ * without one), and leaves owner out of a role picker exactly when the
5
+ * answer is no. The permission hook is stubbed: it is proven by its own
6
+ * tests, fail-open posture included.
7
+ */
8
+ import { afterEach, describe, expect, it, vi } from "vitest";
9
+ import { renderHook } from "@testing-library/react";
10
+ import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
11
+
12
+ const check = vi.hoisted(() => ({
13
+ allowed: false,
14
+ asked: [] as Array<{ resource: { kind: string; id: string } | null; relation: string }>,
15
+ }));
16
+
17
+ vi.mock("../useCheckPermission.js", () => ({
18
+ useCheckPermission: (resource: { kind: string; id: string } | null, relation: string) => {
19
+ check.asked.push({ resource, relation });
20
+ return { allowed: check.allowed, isLoading: false, error: null };
21
+ },
22
+ }));
23
+
24
+ import { useOwnerAssignment } from "../useOwnerAssignment";
25
+
26
+ afterEach(() => {
27
+ check.allowed = false;
28
+ check.asked = [];
29
+ });
30
+
31
+ describe("useOwnerAssignment", () => {
32
+ it("asks can_assign_roles on the organization, and leaves owner out when the answer is no", () => {
33
+ const { result } = renderHook(() => useOwnerAssignment("acme"));
34
+ expect(check.asked.at(-1)).toEqual({
35
+ resource: { kind: "organization", id: "acme" },
36
+ relation: "can_assign_roles",
37
+ });
38
+ expect(result.current).toEqual({ canAssignOwner: false, unassignable: [IamRole.owner] });
39
+ });
40
+
41
+ it("leaves nothing out for an owner, and hands back the same list on every render", () => {
42
+ check.allowed = true;
43
+ const { result, rerender } = renderHook(() => useOwnerAssignment("acme"));
44
+ const first = result.current.unassignable;
45
+ rerender();
46
+ expect(result.current.canAssignOwner).toBe(true);
47
+ expect(result.current.unassignable).toEqual([]);
48
+ expect(result.current.unassignable).toBe(first);
49
+ });
50
+
51
+ it("names no organization to the check when it has none", () => {
52
+ renderHook(() => useOwnerAssignment(null));
53
+ expect(check.asked.at(-1)?.resource).toBeNull();
54
+ });
55
+ });
@@ -0,0 +1,40 @@
1
+ "use client";
2
+
3
+ import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
4
+ import { useCheckPermission } from "./useCheckPermission.js";
5
+
6
+ /** What a caller who is not an owner may not assign: owner is assigned by owners. */
7
+ const OWNER_ONLY: readonly IamRole[] = [IamRole.owner];
8
+ const NOTHING_OMITTED: readonly IamRole[] = [];
9
+
10
+ /** Return value of {@link useOwnerAssignment}. */
11
+ export interface UseOwnerAssignmentReturn {
12
+ /** Whether the caller may grant, revoke or remove the owner role on the organization. */
13
+ readonly canAssignOwner: boolean;
14
+ /**
15
+ * The organization roles to leave out of a role picker for this caller:
16
+ * owner unless they may assign it. A stable list, as `RoleSelector`'s
17
+ * `omitRoles` asks.
18
+ */
19
+ readonly unassignable: readonly IamRole[];
20
+ }
21
+
22
+ /**
23
+ * The console's one reading of the owner rule: the server asks
24
+ * `can_assign_roles` on an organization before any change to its owner
25
+ * role (only its owners hold it), and every surface that offers such a
26
+ * change asks the same question here. Fails open, like every capability
27
+ * gate: the server refuses whatever this lets through.
28
+ *
29
+ * @param orgId - The organization's id, or `null` to skip the check.
30
+ */
31
+ export function useOwnerAssignment(orgId: string | null): UseOwnerAssignmentReturn {
32
+ const { allowed } = useCheckPermission(
33
+ orgId ? { kind: "organization", id: orgId } : null,
34
+ "can_assign_roles",
35
+ );
36
+ return {
37
+ canAssignOwner: allowed,
38
+ unassignable: allowed ? NOTHING_OMITTED : OWNER_ONLY,
39
+ };
40
+ }