diff --git a/src/api/tenants/index.ts b/src/api/tenants/index.ts index 64961cf9..4d41c4e7 100644 --- a/src/api/tenants/index.ts +++ b/src/api/tenants/index.ts @@ -73,7 +73,7 @@ export const useCoreConfigService = () => { config: CoreConfigOptions; }> => { const response = await fetchData({ - url: getApiUrl("/api/multitenancy/core-config/list"), + url: getApiUrl("/api/core/config/list"), method: "GET", }); diff --git a/src/api/tenants/types.ts b/src/api/tenants/types.ts index 1e829149..4147b809 100644 --- a/src/api/tenants/types.ts +++ b/src/api/tenants/types.ts @@ -48,6 +48,7 @@ export type TenantInfo = { thirdParty: { enabled: boolean; providers: Array; + mergedProvidersFromCoreAndStatic: Array; }; passwordless: { enabled: boolean; @@ -57,7 +58,6 @@ export type TenantInfo = { coreConfig: Record; userCount: number; validFirstFactors: Array; - mergedProvidersFromCoreAndStatic: Array; }; export type UpdateTenant = { diff --git a/src/ui/components/tenants/tenantDetail/TenantDetail.tsx b/src/ui/components/tenants/tenantDetail/TenantDetail.tsx index 66915d14..c01c8b75 100644 --- a/src/ui/components/tenants/tenantDetail/TenantDetail.tsx +++ b/src/ui/components/tenants/tenantDetail/TenantDetail.tsx @@ -92,7 +92,7 @@ export const TenantDetail = ({ if ( typeof tenant?.tenantId === "string" && tenant?.thirdParty.enabled && - tenant?.mergedProvidersFromCoreAndStatic.length === 0 + tenant?.thirdParty.mergedProvidersFromCoreAndStatic.length === 0 ) { setIsNoProviderAddedDialogVisible(true); } diff --git a/src/ui/components/tenants/tenantDetail/TenantDetailContext.tsx b/src/ui/components/tenants/tenantDetail/TenantDetailContext.tsx index e02c9b23..5d93e138 100644 --- a/src/ui/components/tenants/tenantDetail/TenantDetailContext.tsx +++ b/src/ui/components/tenants/tenantDetail/TenantDetailContext.tsx @@ -46,7 +46,7 @@ export const TenantDetailContextProvider = ({ refetchTenant, coreConfigOptions, setTenantInfo, - resolvedProviders: tenantInfo.mergedProvidersFromCoreAndStatic, + resolvedProviders: tenantInfo.thirdParty.mergedProvidersFromCoreAndStatic, }}> {children} diff --git a/src/ui/components/tenants/tenantDetail/deleteThirdPartyProvider/DeleteThirdPartyProvider.tsx b/src/ui/components/tenants/tenantDetail/deleteThirdPartyProvider/DeleteThirdPartyProvider.tsx index 51fadcbb..2648c256 100644 --- a/src/ui/components/tenants/tenantDetail/deleteThirdPartyProvider/DeleteThirdPartyProvider.tsx +++ b/src/ui/components/tenants/tenantDetail/deleteThirdPartyProvider/DeleteThirdPartyProvider.tsx @@ -35,8 +35,9 @@ export const DeleteThirdPartyProviderDialog = ({ }) => { const [isDeletingProvider, setIsDeletingProvider] = useState(false); const { deleteThirdPartyProvider } = useThirdPartyService(); - const { tenantInfo } = useTenantDetailContext(); + const { tenantInfo, resolvedProviders } = useTenantDetailContext(); const { showToast } = useContext(PopupContentContext); + const isLastProvider = resolvedProviders.length === 1; const handleDeleteProperty = async () => { try { @@ -62,11 +63,21 @@ export const DeleteThirdPartyProviderDialog = ({ return (

- Are you sure you want to delete the provider: {thirdPartyId} + {isLastProvider ? ( + <> + This is your only added provider, and it cannot be deleted because at least one provider is + required when third party login method is enabled. + + ) : ( + <> + Are you sure you want to delete the provider:{" "} + {thirdPartyId} + + )}

- + {!isLastProvider && ( + + )}
diff --git a/src/ui/components/tenants/tenantsListTable/TenantsListTable.tsx b/src/ui/components/tenants/tenantsListTable/TenantsListTable.tsx index 659ed555..f06116ec 100644 --- a/src/ui/components/tenants/tenantsListTable/TenantsListTable.tsx +++ b/src/ui/components/tenants/tenantsListTable/TenantsListTable.tsx @@ -12,9 +12,8 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { Tenant } from "../../../../api/tenants/list"; -import { FIRST_FACTOR_IDS } from "../../../../constants"; -import { getImageUrl, getInitializedRecipes } from "../../../../utils"; +import { Tenant } from "../../../../api/tenants/login-methods"; +import { getImageUrl } from "../../../../utils"; import Pagination from "../../pagination"; import { RecipePill } from "../../recipePill/RecipePill"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../../table"; @@ -34,30 +33,13 @@ type TenantsListTableProps = { const TenantLoginMethods = ({ tenant }: { tenant: Tenant }) => { const getEnabledLoginMethods = () => { - const tenantLoginMethods = { - emailPassword: tenant.emailPassword.enabled, - passwordless: tenant.passwordless.enabled, - thirdParty: tenant.thirdParty.enabled, - }; - if (Array.isArray(tenant.firstFactors) && tenant.firstFactors.length > 0) { - const allFactors = Array.from( - new Set([...tenant.firstFactors, ...(tenant.requiredSecondaryFactors ?? [])]) - ); - tenantLoginMethods.emailPassword = allFactors.some((factor) => - FIRST_FACTOR_IDS.some((f) => f.loginMethod === "emailpassword" && f.id === factor) - ); - tenantLoginMethods.passwordless = allFactors.some((factor) => - FIRST_FACTOR_IDS.some((f) => f.loginMethod === "otp-email" && f.id === factor) - ); - tenantLoginMethods.thirdParty = allFactors.some((factor) => - FIRST_FACTOR_IDS.some((f) => f.loginMethod === "thirdparty" && f.id === factor) - ); - } - const initalizedRecipes = getInitializedRecipes(); return { - emailPassword: tenantLoginMethods.emailPassword && initalizedRecipes.emailPassword, - passwordless: tenantLoginMethods.passwordless && initalizedRecipes.passwordless.enabled, - thirdParty: tenantLoginMethods.thirdParty && initalizedRecipes.thirdParty, + emailPassword: tenant.emailPassword.enabled || tenant.thirdPartyEmailPasssword.enabled, + passwordless: tenant.passwordless.enabled || tenant.thirdPartyPasswordless.enabled, + thirdParty: + tenant.thirdParty.enabled || + tenant.thirdPartyEmailPasssword.enabled || + tenant.thirdPartyPasswordless.enabled, }; }; diff --git a/src/ui/pages/tenants/index.tsx b/src/ui/pages/tenants/index.tsx index 2cd2ad0d..c6a2f04d 100644 --- a/src/ui/pages/tenants/index.tsx +++ b/src/ui/pages/tenants/index.tsx @@ -15,7 +15,7 @@ import { useContext, useDeferredValue, useEffect, useState } from "react"; import { useLocation, useNavigate } from "react-router"; -import { useGetTenantsList, type Tenant } from "../../../api/tenants/list"; +import { useGetTenantsLoginMethods, type Tenant } from "../../../api/tenants/login-methods"; import { ReactComponent as PlusIcon } from "../../../assets/plus.svg"; import { getImageUrl, useQuery } from "../../../utils"; import Button from "../../components/button"; @@ -29,7 +29,7 @@ import "./index.scss"; const TENANTS_PAGINATION_LIMIT = 10; const TenantList = ({ selectTenant }: { selectTenant: (tenantId: string) => void }) => { - const { fetchTenants } = useGetTenantsList(); + const { fetchTenantsLoginMethods } = useGetTenantsLoginMethods(); const { showToast } = useContext(PopupContentContext); const [tenants, setTenants] = useState | undefined>(undefined); const [searchQuery, setSearchQuery] = useState(""); @@ -47,7 +47,7 @@ const TenantList = ({ selectTenant }: { selectTenant: (tenantId: string) => void useEffect(() => { const getTenants = async () => { try { - const response = await fetchTenants(); + const response = await fetchTenantsLoginMethods(); if (response?.status === "OK") { setTenants(response.tenants); } else {