feat(): enable custom domain usage (#9911)
# Content - Introduce the `workspaceUrls` property. It contains two sub-properties: `customUrl, subdomainUrl`. These endpoints are used to access the workspace. Even if the `workspaceUrls` is invalid for multiple reasons, the `subdomainUrl` remains valid. - Introduce `ResolveField` workspaceEndpoints to avoid unnecessary URL computation on the frontend part. - Add a `forceSubdomainUrl` to avoid custom URL using a query parameter
This commit is contained in:
@ -13,8 +13,8 @@ import { SignInUpSSOIdentityProviderSelection } from '@/auth/sign-in-up/componen
|
||||
import { SignInUpWorkspaceScopeForm } from '@/auth/sign-in-up/components/SignInUpWorkspaceScopeForm';
|
||||
import { SignInUpWorkspaceScopeFormEffect } from '@/auth/sign-in-up/components/SignInUpWorkspaceScopeFormEffect';
|
||||
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
|
||||
import { useGetPublicWorkspaceDataBySubdomain } from '@/domain-manager/hooks/useGetPublicWorkspaceDataBySubdomain';
|
||||
import { useIsCurrentLocationOnAWorkspaceSubdomain } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspaceSubdomain';
|
||||
import { useGetPublicWorkspaceDataByDomain } from '@/domain-manager/hooks/useGetPublicWorkspaceDataByDomain';
|
||||
import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace';
|
||||
import { useIsCurrentLocationOnDefaultDomain } from '@/domain-manager/hooks/useIsCurrentLocationOnDefaultDomain';
|
||||
import { DEFAULT_WORKSPACE_NAME } from '@/ui/navigation/navigation-drawer/constants/DefaultWorkspaceName';
|
||||
import { useMemo } from 'react';
|
||||
@ -24,7 +24,7 @@ import { AnimatedEaseIn } from 'twenty-ui';
|
||||
import { useWorkspaceFromInviteHash } from '@/auth/sign-in-up/hooks/useWorkspaceFromInviteHash';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { PublicWorkspaceDataOutput } from '~/generated-metadata/graphql';
|
||||
import { PublicWorkspaceDataOutput } from '~/generated/graphql';
|
||||
|
||||
const StandardContent = ({
|
||||
workspacePublicData,
|
||||
@ -55,10 +55,9 @@ export const SignInUp = () => {
|
||||
const { form } = useSignInUpForm();
|
||||
const { signInUpStep } = useSignInUp(form);
|
||||
const { isDefaultDomain } = useIsCurrentLocationOnDefaultDomain();
|
||||
const { isOnAWorkspaceSubdomain } =
|
||||
useIsCurrentLocationOnAWorkspaceSubdomain();
|
||||
const { isOnAWorkspace } = useIsCurrentLocationOnAWorkspace();
|
||||
const workspacePublicData = useRecoilValue(workspacePublicDataState);
|
||||
const { loading } = useGetPublicWorkspaceDataBySubdomain();
|
||||
const { loading } = useGetPublicWorkspaceDataByDomain();
|
||||
const isMultiWorkspaceEnabled = useRecoilValue(isMultiWorkspaceEnabledState);
|
||||
const { workspaceInviteHash, workspace: workspaceFromInviteHash } =
|
||||
useWorkspaceFromInviteHash();
|
||||
@ -91,7 +90,7 @@ export const SignInUp = () => {
|
||||
|
||||
if (
|
||||
(!isMultiWorkspaceEnabled ||
|
||||
(isMultiWorkspaceEnabled && isOnAWorkspaceSubdomain)) &&
|
||||
(isMultiWorkspaceEnabled && isOnAWorkspace)) &&
|
||||
signInUpStep === SignInUpStep.SSOIdentityProviderSelection
|
||||
) {
|
||||
return <SignInUpSSOIdentityProviderSelection />;
|
||||
@ -99,7 +98,7 @@ export const SignInUp = () => {
|
||||
|
||||
if (
|
||||
isDefined(workspacePublicData) &&
|
||||
(!isMultiWorkspaceEnabled || isOnAWorkspaceSubdomain)
|
||||
(!isMultiWorkspaceEnabled || isOnAWorkspace)
|
||||
) {
|
||||
return (
|
||||
<>
|
||||
@ -113,7 +112,7 @@ export const SignInUp = () => {
|
||||
}, [
|
||||
isDefaultDomain,
|
||||
isMultiWorkspaceEnabled,
|
||||
isOnAWorkspaceSubdomain,
|
||||
isOnAWorkspace,
|
||||
loading,
|
||||
signInUpStep,
|
||||
workspacePublicData,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { ApolloError } from '@apollo/client';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||
@ -13,7 +14,6 @@ import { SettingsSubdomain } from '~/pages/settings/workspace/SettingsSubdomain'
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||
import { ApolloError } from '@apollo/client';
|
||||
import { Trans, useLingui } from '@lingui/react/macro';
|
||||
import { z } from 'zod';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
@ -94,12 +94,18 @@ export const SettingsDomain = () => {
|
||||
});
|
||||
},
|
||||
onCompleted: () => {
|
||||
const currentUrl = new URL(window.location.href);
|
||||
|
||||
currentUrl.hostname = new URL(
|
||||
currentWorkspace.workspaceUrls.subdomainUrl,
|
||||
).hostname.replace(currentWorkspace.subdomain, values.subdomain);
|
||||
|
||||
setCurrentWorkspace({
|
||||
...currentWorkspace,
|
||||
subdomain: values.subdomain,
|
||||
});
|
||||
|
||||
redirectToWorkspaceDomain(values.subdomain);
|
||||
redirectToWorkspaceDomain(currentUrl.toString());
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||
import styled from '@emotion/styled';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
@ -41,7 +40,6 @@ export const SettingsHostname = () => {
|
||||
const [updateWorkspace] = useUpdateWorkspaceMutation();
|
||||
const { data: getHostnameDetailsData } = useGetHostnameDetailsQuery();
|
||||
|
||||
const { redirectToWorkspaceDomain } = useRedirectToWorkspaceDomain();
|
||||
const { t } = useLingui();
|
||||
|
||||
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
|
||||
@ -75,8 +73,6 @@ export const SettingsHostname = () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
redirectToWorkspaceDomain(currentWorkspace.subdomain);
|
||||
} catch (error) {
|
||||
control.setError('hostname', {
|
||||
type: 'manual',
|
||||
@ -106,8 +102,6 @@ export const SettingsHostname = () => {
|
||||
...currentWorkspace,
|
||||
hostname: values.hostname,
|
||||
});
|
||||
|
||||
// redirectToWorkspaceDomain(values.subdomain);
|
||||
} catch (error) {
|
||||
control.setError('hostname', {
|
||||
type: 'manual',
|
||||
@ -139,12 +133,36 @@ export const SettingsHostname = () => {
|
||||
{isDefined(getHostnameDetailsData?.getHostnameDetails?.hostname) && (
|
||||
<pre>
|
||||
{getHostnameDetailsData.getHostnameDetails.hostname} CNAME
|
||||
app.twenty-main.com
|
||||
twenty-main.com
|
||||
</pre>
|
||||
)}
|
||||
{getHostnameDetailsData && (
|
||||
<pre>{JSON.stringify(getHostnameDetailsData, null, 4)}</pre>
|
||||
)}
|
||||
{getHostnameDetailsData?.getHostnameDetails &&
|
||||
getHostnameDetailsData.getHostnameDetails.ownershipVerifications.map(
|
||||
(ownershipVerification) => {
|
||||
if (
|
||||
ownershipVerification.__typename ===
|
||||
'CustomHostnameOwnershipVerificationTxt'
|
||||
) {
|
||||
return (
|
||||
<pre>
|
||||
{ownershipVerification.name} TXT {ownershipVerification.value}
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
ownershipVerification.__typename ===
|
||||
'CustomHostnameOwnershipVerificationHttp'
|
||||
) {
|
||||
return (
|
||||
<pre>
|
||||
{ownershipVerification.url} HTTP {ownershipVerification.body}
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
},
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user