f7cde28dd6
## Problem **CRITICAL:** Two PRs were accidentally reverted when PR #14347 "Prevent csv export injections" was merged: 1. **PR #14348** "[Page Layout] - Review Refactor" - ✅ **RESTORED** 2. **PR #14352** "Fix wrong path used by backend" - ✅ **RESTORED** ## Root Cause Analysis During the merge of PR #14347, there was a complex merge conflict with PR #14352 "Fix wrong path used by backend". The merge commit `324d7204bb` in the PR #14347 branch brought in changes from PR #14352, but during the conflict resolution, **BOTH PR #14348 and PR #14352's changes were accidentally overwritten**. ## What This PR Restores This PR restores **BOTH** PRs by cherry-picking their commits: ### ✅ PR #14348 Changes Restored: - `GraphWidgetRenderer.tsx` - was deleted, now restored - `WidgetRenderer.tsx` - was missing, now restored - `SettingsPageLayoutTabsInstanceId.ts` - was deleted, now restored - `useUpdatePageLayoutWidget.ts` - was renamed back, now restored with correct name - Multiple test files that were deleted - Several hook files that were renamed/reverted - File renames: `usePageLayoutWidgetUpdate.ts` → `useUpdatePageLayoutWidget.ts` - Hook refactoring and test file organization - Page layout component improvements ### ✅ PR #14352 Changes Restored: - **Types moved to twenty-shared:** - `packages/twenty-shared/src/types/AppBasePath.ts` ✅ RESTORED - `packages/twenty-shared/src/types/AppPath.ts` ✅ RESTORED - `packages/twenty-shared/src/types/SettingsPath.ts` ✅ RESTORED - **Navigation utilities moved to twenty-shared:** - `packages/twenty-shared/src/utils/navigation/getAppPath.ts` ✅ RESTORED - `packages/twenty-shared/src/utils/navigation/getSettingsPath.ts` ✅ RESTORED - **200+ import statements updated** across the codebase to use twenty-shared - **Old type files deleted** from twenty-front/src/modules/types/ ## Evidence of Complete Restoration **Before (reverted state):** - ❌ Types were in `packages/twenty-front/src/modules/types/` - ❌ Page layout files missing - ❌ Hook files incorrectly named **After (this PR):** - ✅ Types correctly in `packages/twenty-shared/src/types/` - ✅ All page layout files restored - ✅ Hook files correctly named - ✅ All import statements updated ## Verification **Total changes:** - PR #14348: 36 files changed, 863 insertions(+), 442 deletions(-) - PR #14352: 243 files changed, 492 insertions(+), 461 deletions(-) - **Combined: 279 files changed, 1355 insertions(+), 903 deletions(-)** ## Impact This completely restores both PRs that were accidentally lost, ensuring: 1. Page layout refactoring work is back 2. Type organization and path utilities are correctly in twenty-shared 3. Backend email paths work correctly again 4. No functionality is lost Fixes the reversion caused by the merge conflict in PR #14347. --------- Co-authored-by: nitin <142569587+ehconitin@users.noreply.github.com>
183 lines
5.4 KiB
TypeScript
183 lines
5.4 KiB
TypeScript
import { zodResolver } from '@hookform/resolvers/zod';
|
|
import { useCallback, useMemo } from 'react';
|
|
import { useForm } from 'react-hook-form';
|
|
import { useRecoilValue } from 'recoil';
|
|
|
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
|
|
|
import { t } from '@lingui/core/macro';
|
|
import { SettingsPath } from 'twenty-shared/types';
|
|
import {
|
|
type ConnectionParameters,
|
|
useSaveImapSmtpCaldavAccountMutation,
|
|
} from '~/generated-metadata/graphql';
|
|
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
|
|
|
import { type ImapSmtpCaldavAccount } from '@/accounts/types/ImapSmtpCaldavAccount';
|
|
import { ACCOUNT_PROTOCOLS } from '@/settings/accounts/constants/AccountProtocols';
|
|
import {
|
|
connectionImapSmtpCalDav,
|
|
isProtocolConfigured,
|
|
} from '@/settings/accounts/validation-schemas/connectionImapSmtpCalDav';
|
|
import { ApolloError } from '@apollo/client';
|
|
import { isDefined } from 'twenty-shared/utils';
|
|
import {
|
|
type ConnectedImapSmtpCaldavAccount,
|
|
useConnectedImapSmtpCaldavAccount,
|
|
} from './useConnectedImapSmtpCaldavAccount';
|
|
|
|
type UseConnectionFormProps = {
|
|
isEditing?: boolean;
|
|
connectedAccountId?: string;
|
|
};
|
|
|
|
export type ConnectionFormData = {
|
|
handle: string;
|
|
} & ImapSmtpCaldavAccount;
|
|
|
|
export const useImapSmtpCaldavConnectionForm = ({
|
|
isEditing = false,
|
|
connectedAccountId,
|
|
}: UseConnectionFormProps = {}) => {
|
|
const navigate = useNavigateSettings();
|
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
|
|
|
const formMethods = useForm<ConnectionFormData>({
|
|
mode: 'onSubmit',
|
|
resolver: zodResolver(connectionImapSmtpCalDav),
|
|
defaultValues: {
|
|
handle: '',
|
|
IMAP: { host: '', port: 993, password: '', secure: true },
|
|
SMTP: { host: '', username: '', port: 587, password: '', secure: true },
|
|
CALDAV: {
|
|
host: '',
|
|
port: 443,
|
|
password: '',
|
|
secure: true,
|
|
username: undefined,
|
|
},
|
|
},
|
|
});
|
|
|
|
const { handleSubmit, formState, watch, reset } = formMethods;
|
|
const { enqueueErrorSnackBar, enqueueSuccessSnackBar } = useSnackBar();
|
|
const { isSubmitting } = formState;
|
|
|
|
const { connectedAccount, loading: accountLoading } =
|
|
useConnectedImapSmtpCaldavAccount(
|
|
isEditing ? connectedAccountId : undefined,
|
|
useCallback(
|
|
(account: ConnectedImapSmtpCaldavAccount | null) => {
|
|
if (isDefined(account)) {
|
|
reset({
|
|
handle: account.handle || '',
|
|
IMAP: account.connectionParameters?.IMAP || undefined,
|
|
SMTP: account.connectionParameters?.SMTP || undefined,
|
|
CALDAV: account.connectionParameters?.CALDAV || undefined,
|
|
});
|
|
}
|
|
},
|
|
[reset],
|
|
),
|
|
);
|
|
|
|
const [saveConnection, { loading: saveLoading }] =
|
|
useSaveImapSmtpCaldavAccountMutation();
|
|
|
|
const watchedValues = watch();
|
|
|
|
const getConfiguredProtocols = useCallback(
|
|
(
|
|
values: ConnectionFormData = watchedValues,
|
|
): (keyof ImapSmtpCaldavAccount)[] => {
|
|
return ACCOUNT_PROTOCOLS.filter((protocol) => {
|
|
const protocolConfig = values[protocol];
|
|
return (
|
|
protocolConfig &&
|
|
isProtocolConfigured(protocolConfig as ConnectionParameters)
|
|
);
|
|
});
|
|
},
|
|
[watchedValues],
|
|
);
|
|
|
|
const isValid = useMemo(() => {
|
|
return (
|
|
Boolean(watchedValues.handle?.trim()) &&
|
|
getConfiguredProtocols().length > 0
|
|
);
|
|
}, [getConfiguredProtocols, watchedValues.handle]);
|
|
|
|
const handleSave = useCallback(
|
|
async (formValues: ConnectionFormData): Promise<void> => {
|
|
if (!currentWorkspaceMember?.id) {
|
|
throw new Error('Workspace member ID is missing');
|
|
}
|
|
|
|
const configuredProtocols = getConfiguredProtocols(formValues);
|
|
|
|
if (configuredProtocols.length === 0) {
|
|
throw new Error('At least one protocol must be configured');
|
|
}
|
|
|
|
const connectionParameters: Partial<
|
|
Record<keyof ImapSmtpCaldavAccount, ConnectionParameters>
|
|
> = {};
|
|
configuredProtocols.forEach((protocol) => {
|
|
const protocolConfig = formValues[protocol];
|
|
if (isDefined(protocolConfig)) {
|
|
connectionParameters[protocol] = protocolConfig;
|
|
}
|
|
});
|
|
|
|
try {
|
|
await saveConnection({
|
|
variables: {
|
|
...(isEditing && connectedAccountId
|
|
? { id: connectedAccountId }
|
|
: {}),
|
|
accountOwnerId: currentWorkspaceMember.id,
|
|
handle: formValues.handle,
|
|
connectionParameters,
|
|
},
|
|
});
|
|
|
|
const successMessage = isEditing
|
|
? t`Connection successfully updated`
|
|
: t`Connection successfully created`;
|
|
|
|
enqueueSuccessSnackBar({ message: successMessage });
|
|
navigate(SettingsPath.Accounts);
|
|
} catch (error) {
|
|
enqueueErrorSnackBar({
|
|
apolloError: error instanceof ApolloError ? error : undefined,
|
|
});
|
|
}
|
|
},
|
|
[
|
|
currentWorkspaceMember?.id,
|
|
getConfiguredProtocols,
|
|
saveConnection,
|
|
isEditing,
|
|
connectedAccountId,
|
|
enqueueSuccessSnackBar,
|
|
navigate,
|
|
enqueueErrorSnackBar,
|
|
],
|
|
);
|
|
|
|
const canSave = isValid && !isSubmitting;
|
|
const loading = accountLoading || saveLoading;
|
|
|
|
return {
|
|
formMethods,
|
|
handleSave,
|
|
handleSubmit,
|
|
canSave,
|
|
isSubmitting,
|
|
loading,
|
|
connectedAccount,
|
|
};
|
|
};
|