diff --git a/frontend/app/src/lib/api/generated/control-plane/Api.ts b/frontend/app/src/lib/api/generated/control-plane/Api.ts index 7cc9b5db26..420906f47c 100644 --- a/frontend/app/src/lib/api/generated/control-plane/Api.ts +++ b/frontend/app/src/lib/api/generated/control-plane/Api.ts @@ -31,6 +31,7 @@ import { ManagementTokenList, Organization, OrganizationAvailableShardList, + OrganizationEntitlements, OrganizationForUserList, OrganizationInviteList, OrganizationTenant, @@ -849,6 +850,25 @@ export class Api< type: ContentType.Json, ...params, }); + /** + * @description Get entitlements for an organization + * + * @name OrganizationEntitlementsGet + * @summary Get organization entitlements + * @request GET:/api/v1/control-plane/organizations/{organization}/entitlements + * @secure + */ + organizationEntitlementsGet = ( + organization: string, + params: RequestParams = {}, + ) => + this.request({ + path: `/api/v1/control-plane/organizations/${organization}/entitlements`, + method: "GET", + secure: true, + format: "json", + ...params, + }); /** * @description Starts the OAuth flow * diff --git a/frontend/app/src/lib/api/generated/control-plane/data-contracts.ts b/frontend/app/src/lib/api/generated/control-plane/data-contracts.ts index 398b6b4d01..f78e3a2ffd 100644 --- a/frontend/app/src/lib/api/generated/control-plane/data-contracts.ts +++ b/frontend/app/src/lib/api/generated/control-plane/data-contracts.ts @@ -399,3 +399,8 @@ export interface SsoConfig { /** @example false */ forceSSO: boolean; } + +export interface OrganizationEntitlements { + /** @example false */ + canSSO: boolean; +} diff --git a/frontend/app/src/lib/api/organization-wrapper.ts b/frontend/app/src/lib/api/organization-wrapper.ts index 92ca3c205d..ca2a2b48a2 100644 --- a/frontend/app/src/lib/api/organization-wrapper.ts +++ b/frontend/app/src/lib/api/organization-wrapper.ts @@ -80,6 +80,14 @@ export function useOrganizationApi() { queryFn: async () => (await controlPlaneApi.ssoConfigGet(organization)).data, }), + + organizationEntitlementsGetQuery: (organization: string) => ({ + queryKey: ['organization:entitlements:get', organization] as const, + queryFn: async () => + (await controlPlaneApi.organizationEntitlementsGet(organization)) + .data, + }), + managementTokenListQuery: (organization: string) => ({ queryKey: ['management-tokens:list', organization] as const, queryFn: async () => diff --git a/frontend/app/src/pages/main/v1/tenant-settings/organization/index.tsx b/frontend/app/src/pages/main/v1/tenant-settings/organization/index.tsx index 7d73466a52..fc6b6b76a5 100644 --- a/frontend/app/src/pages/main/v1/tenant-settings/organization/index.tsx +++ b/frontend/app/src/pages/main/v1/tenant-settings/organization/index.tsx @@ -164,14 +164,20 @@ export function CloudOrganizationSettings({ orgId }: { orgId: string }) { const [newSsoDomain, setNewSsoDomain] = useState(''); const [isAddingSsoDomain, setIsAddingSsoDomain] = useState(false); + const organizationEntitlementsQuery = useQuery({ + ...orgApi.organizationEntitlementsGetQuery(orgId!), + enabled: !!orgId && canManageSso, + }); + const canUseSso = organizationEntitlementsQuery.data?.canSSO === true; + const organizationSsoDomainGetQuery = useQuery({ ...orgApi.organizationSsoDomainGetQuery(orgId), - enabled: !!orgId && canManageSso, + enabled: !!orgId && canUseSso, }); const organizationSsoConfigGetQuery = useQuery({ ...orgApi.organizationSsoConfigGetQuery(orgId), - enabled: !!orgId && canManageSso, + enabled: !!orgId && canUseSso, }); const ssoConfigUpdateMutation = useMutation({ @@ -947,101 +953,122 @@ export function CloudOrganizationSettings({ orgId }: { orgId: string }) { {canManageSso && ( -
- - {/* Force SSO toggle */} - {isOrganizationOwner && ( -
-
-

Force SSO

-

- Require all organization members to sign in with SSO. - All other login methods will be disabled. -

-
- - ssoConfigUpdateMutation.mutate(checked) - } - disabled={ - organizationSsoConfigGetQuery.isLoading || - ssoConfigUpdateMutation.isPending - } - /> -
- )} - {/* SSO Domains Table */} - {organizationSsoDomainGetQuery.isLoading ? ( -
- -
- ) : organizationSsoDomainGetQuery.data && - organizationSsoDomainGetQuery.data.length > 0 ? ( - ({ - domain: v.ssoDomain, - verified: v.verified, - verification_token: v.verificationToken, - }))} - columns={ssoDomainColumns} - rowKey={(row) => row.domain} - /> - ) : ( -
- -

No SSO Domains

-

- Add a domain below to enable SSO for your organization. -

-
- )} - - {/* Add New SSO Domain */} -
-
- setNewSsoDomain(e.target.value)} - onKeyDown={(e) => { - if (e.key === 'Enter') { - handleAddSsoDomain(); + {organizationEntitlementsQuery.isLoading ? ( +
+ +
+ ) : canUseSso ? ( +
+ + {/* Force SSO toggle */} + {isOrganizationOwner && ( +
+
+

Force SSO

+

+ Require all organization members to sign in with SSO. + All other login methods will be disabled. +

+
+ + ssoConfigUpdateMutation.mutate(checked) } - }} - className="max-w-sm" - disabled={isAddingSsoDomain} + disabled={ + organizationSsoConfigGetQuery.isLoading || + ssoConfigUpdateMutation.isPending + } + /> +
+ )} + {/* SSO Domains Table */} + {organizationSsoDomainGetQuery.isLoading ? ( +
+ +
+ ) : organizationSsoDomainGetQuery.data && + organizationSsoDomainGetQuery.data.length > 0 ? ( + ({ + domain: v.ssoDomain, + verified: v.verified, + verification_token: v.verificationToken, + }))} + columns={ssoDomainColumns} + rowKey={(row) => row.domain} /> - -
-
- {organizationSsoDomainGetQuery.data && - organizationSsoDomainGetQuery.data.length > 0 && ( -
-

- To verify your domain, add a DNS TXT record with the - value: -

-

- hatchet-sso-verify={verification_token} -

-

- It may take a few minutes for DNS changes to propagate - and for the verified status to update. + ) : ( +

+ +

+ No SSO Domains +

+

+ Add a domain below to enable SSO for your organization.

)} -
+ + {/* Add New SSO Domain */} +
+
+ setNewSsoDomain(e.target.value)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + handleAddSsoDomain(); + } + }} + className="max-w-sm" + disabled={isAddingSsoDomain} + /> + +
+
+ {organizationSsoDomainGetQuery.data && + organizationSsoDomainGetQuery.data.length > 0 && ( +
+

+ To verify your domain, add a DNS TXT record with the + value: +

+

+ hatchet-sso-verify={verification_token} +

+

+ It may take a few minutes for DNS changes to propagate + and for the verified status to update. +

+
+ )} +
+ ) : ( +
+ SSO is not enabled for this organization. Please{' '} + + contact us + {' '} + to get access. +
+ )} )}