Refactor modal (#18377)

## Summary

- Move Modal UI components (`Modal`, `ModalContent`, `ModalHeader`,
`ModalFooter`, `ModalBackdrop`) from `twenty-front` to `twenty-ui` as
stateless, reusable components
- Create `ModalStatefulWrapper` in `twenty-front` that connects Jotai
state (`isModalOpenedComponentState`) to the stateless `Modal` via an
`isOpen` prop
- Rename `modalVariant` prop to `overlay` with clearer values: `'dark'`
(default), `'light'` (in-container), `'transparent'` (invisible panel).
Remove unused `'medium'` overlay
- Rename `modalId` to `modalInstanceId` across the entire modal zone
(~30 consumer files)
- Extract `ModalProps` to its own file in
`twenty-ui/types/ModalProps.ts`; extract `ModalStatefulWrapperProps` to
its own file using `Pick<ModalProps, ...>` for shared props
- Extract `ModalBackdrop` to its own file and export from `twenty-ui`;
use it in `UserOrMetadataLoader` instead of a local styled component
- Use `ModalFooter` in `StepNavigationButton` and `ModalHeader` in
`SpreadsheetImportStepperContainer` instead of duplicated `styled.div`
definitions
- Remove unused `onClose` prop from stateless `Modal`; fix `typeof
document` guard in `ModalStatefulWrapper`
- Split shared types into individual files: `ModalSize.ts`,
`ModalPadding.ts`, `ModalOverlay.ts`
- Extract wyw profiling instrumentation from `vite.config.ts` into
reusable `createWywProfilingPlugin` with parametrized threshold and
improved logging
- Delete old `Modal.tsx`, `Modal.styles.ts`, `ModalContent.tsx`,
`ModalHeader.tsx`, `ModalFooter.tsx` from `twenty-front`
- Add comprehensive Storybook stories in `twenty-ui` covering Default,
Confirmation, Small, ExtraLarge, Closed, and Interactive variants
This commit is contained in:
Charles Bochet
2026-03-04 13:22:31 +01:00
committed by GitHub
parent 995793c0ac
commit 3b2bf39565
99 changed files with 4283 additions and 3688 deletions
@@ -137,7 +137,7 @@ export const SettingsAccountsRowDropdownMenu = ({
}
/>
<ConfirmationModal
modalId={deleteAccountModalId}
modalInstanceId={deleteAccountModalId}
title={t`Data deletion`}
subtitle={
<Trans>
@@ -2,14 +2,14 @@ import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModa
import { plural, t } from '@lingui/core/macro';
type SettingsAdminDeleteJobsConfirmationModalProps = {
modalId: string;
modalInstanceId: string;
jobCount: number;
onConfirm: () => void;
onClose?: () => void;
};
export const SettingsAdminDeleteJobsConfirmationModal = ({
modalId,
modalInstanceId,
jobCount,
onConfirm,
onClose,
@@ -26,7 +26,7 @@ export const SettingsAdminDeleteJobsConfirmationModal = ({
return (
<ConfirmationModal
modalId={modalId}
modalInstanceId={modalInstanceId}
title={title}
subtitle={subtitle}
onConfirmClick={onConfirm}
@@ -399,12 +399,12 @@ export const SettingsAdminQueueJobsTable = ({
)}
<SettingsAdminRetryJobsConfirmationModal
modalId={RETRY_MODAL_ID}
modalInstanceId={RETRY_MODAL_ID}
jobCount={selectedCount > 0 ? selectedCount : failedJobs.length}
onConfirm={confirmRetrySelected}
/>
<SettingsAdminDeleteJobsConfirmationModal
modalId={DELETE_MODAL_ID}
modalInstanceId={DELETE_MODAL_ID}
jobCount={selectedCount}
onConfirm={confirmDeleteSelected}
/>
@@ -2,14 +2,14 @@ import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModa
import { plural, t } from '@lingui/core/macro';
type SettingsAdminRetryJobsConfirmationModalProps = {
modalId: string;
modalInstanceId: string;
jobCount: number;
onConfirm: () => void;
onClose?: () => void;
};
export const SettingsAdminRetryJobsConfirmationModal = ({
modalId,
modalInstanceId,
jobCount,
onConfirm,
onClose,
@@ -26,7 +26,7 @@ export const SettingsAdminRetryJobsConfirmationModal = ({
return (
<ConfirmationModal
modalId={modalId}
modalInstanceId={modalInstanceId}
title={title}
subtitle={subtitle}
onConfirmClick={onConfirm}
@@ -139,7 +139,7 @@ export const ObjectSettings = ({
</StyledFormSection>
)}
<ConfirmationModal
modalId={DELETE_OBJECT_MODAL_ID}
modalInstanceId={DELETE_OBJECT_MODAL_ID}
title={t`Delete ${objectLabel} object?`}
subtitle={t`This will permanently delete the object and all its records. Type "yes" to confirm.`}
confirmButtonText={t`Delete`}
@@ -198,7 +198,7 @@ export const SettingsDevelopersWebhookForm = ({
<ConfirmationModal
confirmationPlaceholder={t`yes`}
confirmationValue={t`yes`}
modalId={DELETE_WEBHOOK_MODAL_ID}
modalInstanceId={DELETE_WEBHOOK_MODAL_ID}
title={t`Delete webhook`}
subtitle={
<Trans>
@@ -150,7 +150,7 @@ export const MemberPermissionsTab = ({
{pendingRole && (
<ConfirmationModal
modalId={CONFIRM_ROLE_CHANGE_MODAL_ID}
modalInstanceId={CONFIRM_ROLE_CHANGE_MODAL_ID}
title={t`Confirm role update`}
subtitle={t`Are you sure you want to update the role of this user from "${oldRoleLabel}" to "${newRoleLabel}"?`}
onConfirmClick={handleConfirmRoleChange}
@@ -86,7 +86,7 @@ export const DeleteAccount = () => {
<ConfirmationModal
confirmationValue={userEmail}
confirmationPlaceholder={userEmail ?? ''}
modalId={LEAVE_WORKSPACE_MODAL_ID}
modalInstanceId={LEAVE_WORKSPACE_MODAL_ID}
title={t`Leave workspace`}
subtitle={
<>
@@ -109,7 +109,7 @@ export const DeleteAccount = () => {
<ConfirmationModal
confirmationValue={userEmail}
confirmationPlaceholder={userEmail ?? ''}
modalId={DELETE_ACCOUNT_MODAL_ID}
modalInstanceId={DELETE_ACCOUNT_MODAL_ID}
title={t`Account Deletion`}
subtitle={
<>
@@ -43,7 +43,7 @@ export const DeleteWorkspace = () => {
/>
<ConfirmationModal
modalId={DELETE_WORKSPACE_MODAL_ID}
modalInstanceId={DELETE_WORKSPACE_MODAL_ID}
confirmationPlaceholder={userEmail}
confirmationValue={userEmail}
title={t`Workspace Deletion`}
@@ -25,7 +25,7 @@ export const SettingsRoleAssignmentConfirmationModal = ({
return (
<ConfirmationModal
modalId={ROLE_ASSIGNMENT_CONFIRMATION_MODAL_ID}
modalInstanceId={ROLE_ASSIGNMENT_CONFIRMATION_MODAL_ID}
title={title}
subtitle={
selectedRoleTarget.role ? (
@@ -26,7 +26,7 @@ export const SettingsRoleSettingsDeleteRoleConfirmationModal = ({
return (
<ConfirmationModal
modalId={ROLE_SETTINGS_DELETE_ROLE_CONFIRMATION_MODAL_ID}
modalInstanceId={ROLE_SETTINGS_DELETE_ROLE_CONFIRMATION_MODAL_ID}
title={t`Delete Role Permanently`}
subtitle={
<SettingsRoleSettingsDeleteRoleConfirmationModalSubtitle
@@ -98,7 +98,7 @@ export const DeleteTwoFactorAuthentication = () => {
<ConfirmationModal
confirmationValue={userEmail}
confirmationPlaceholder={userEmail ?? ''}
modalId={DELETE_TWO_FACTOR_AUTHENTICATION_MODAL_ID}
modalInstanceId={DELETE_TWO_FACTOR_AUTHENTICATION_MODAL_ID}
title={t`2FA Method Reset`}
subtitle={
isTwoFactorAuthenticationEnforced ? (