Files
twenty/packages/twenty-front/src/modules/settings/data-model/components/SettingsDataModelNewFieldBreadcrumbDropDown.tsx
T
Paul Rastoin 9ad8287dbc [REFACTOR] twenty-shared multi barrel and CJS/ESM build with preconstruct (#11083)
# Introduction

In this PR we've migrated `twenty-shared` from a `vite` app
[libary-mode](https://vite.dev/guide/build#library-mode) to a
[preconstruct](https://preconstruct.tools/) "atomic" application ( in
the future would like to introduce preconstruct to handle of all our
atomic dependencies such as `twenty-emails` `twenty-ui` etc it will be
integrated at the monorepo's root directly, would be to invasive in the
first, starting incremental via `twenty-shared`)

For more information regarding the motivations please refer to nor:
- https://github.com/twentyhq/core-team-issues/issues/587
-
https://github.com/twentyhq/core-team-issues/issues/281#issuecomment-2630949682

close https://github.com/twentyhq/core-team-issues/issues/589
close https://github.com/twentyhq/core-team-issues/issues/590

## How to test
In order to ease the review this PR will ship all the codegen at the
very end, the actual meaning full diff is `+2,411 −114`
In order to migrate existing dependent packages to `twenty-shared` multi
barrel new arch you need to run in local:
```sh
yarn tsx packages/twenty-shared/scripts/migrateFromSingleToMultiBarrelImport.ts && \
npx nx run-many -t lint --fix -p twenty-front twenty-ui twenty-server twenty-emails twenty-shared twenty-zapier
```
Note that `migrateFromSingleToMultiBarrelImport` is idempotent, it's atm
included in the PR but should not be merged. ( such as codegen will be
added before merging this script will be removed )

## Misc
- related opened issue preconstruct
https://github.com/preconstruct/preconstruct/issues/617

## Closed related PR
- https://github.com/twentyhq/twenty/pull/11028
- https://github.com/twentyhq/twenty/pull/10993
- https://github.com/twentyhq/twenty/pull/10960

## Upcoming enhancement: ( in others dedicated PRs )
- 1/ refactor generate barrel to export atomic module instead of `*`
- 2/ generate barrel own package with several files and tests
- 3/ Migration twenty-ui the same way
- 4/ Use `preconstruct` at monorepo global level

## Conclusion
As always any suggestions are welcomed !
2025-03-22 19:16:06 +01:00

136 lines
4.5 KiB
TypeScript

import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType';
import { SettingsPath } from '@/types/SettingsPath';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useLocation, useParams, useSearchParams } from 'react-router-dom';
import { Button, IconChevronDown, MenuItem } from 'twenty-ui';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { t } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
const StyledContainer = styled.div`
align-items: center;
color: ${({ theme }) => theme.font.color.tertiary};
cursor: default;
display: flex;
font-size: ${({ theme }) => theme.font.size.md};
`;
const StyledButtonContainer = styled.div`
position: relative;
width: 100%;
`;
const StyledDownChevron = styled(IconChevronDown)`
color: ${({ theme }) => theme.font.color.primary};
position: absolute;
right: ${({ theme }) => theme.spacing(1.5)};
top: 50%;
transform: translateY(-50%);
`;
const StyledMenuItemWrapper = styled.div<{ disabled?: boolean }>`
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
width: 100%;
`;
const StyledMenuItem = styled(MenuItem)<{
selected?: boolean;
disabled?: boolean;
}>`
background: ${({ theme, selected }) =>
selected ? theme.background.quaternary : 'transparent'};
opacity: ${({ disabled }) => (disabled ? 0.5 : 1)};
pointer-events: ${({ disabled }) => (disabled ? 'none' : 'auto')};
&:hover {
background: ${({ theme, disabled }) =>
disabled ? 'transparent' : theme.background.tertiary};
}
`;
const StyledSpan = styled.span`
margin-left: ${({ theme }) => theme.spacing(2)};
`;
const StyledButton = styled(Button)`
color: ${({ theme }) => theme.font.color.primary};
padding-right: ${({ theme }) => theme.spacing(6)};
`;
export const SettingsDataModelNewFieldBreadcrumbDropDown = () => {
const dropdownId = `settings-object-new-field-breadcrumb-dropdown`;
const { closeDropdown } = useDropdown(dropdownId);
const navigate = useNavigateSettings();
const location = useLocation();
const { objectNamePlural = '' } = useParams();
const [searchParams] = useSearchParams();
const theme = useTheme();
const fieldType = searchParams.get('fieldType') as SettingsFieldType;
const isConfigureStep = location.pathname.includes('/configure');
const handleClick = (step: 'select' | 'configure') => {
if (step === 'configure' && isDefined(fieldType)) {
navigate(
SettingsPath.ObjectNewFieldConfigure,
{ objectNamePlural },
{ fieldType },
);
} else {
navigate(
SettingsPath.ObjectNewFieldSelect,
{ objectNamePlural },
fieldType ? { fieldType } : undefined,
);
}
closeDropdown();
};
return (
<StyledContainer>
New Field <StyledSpan>-</StyledSpan>
<Dropdown
dropdownPlacement="bottom-start"
dropdownId={dropdownId}
clickableComponent={
<StyledButtonContainer>
<StyledDownChevron size={theme.icon.size.md} />
{isConfigureStep ? (
<StyledButton variant="tertiary" title={t`2. Configure`} />
) : (
<StyledButton variant="tertiary" title={t`1. Type`} />
)}
</StyledButtonContainer>
}
dropdownComponents={
<DropdownMenu>
<DropdownMenuItemsContainer>
<StyledMenuItemWrapper>
<StyledMenuItem
text={t`1. Type`}
onClick={() => handleClick('select')}
selected={!isConfigureStep}
/>
</StyledMenuItemWrapper>
<StyledMenuItemWrapper disabled={!isDefined(fieldType)}>
<StyledMenuItem
text={t`2. Configure`}
onClick={() => handleClick('configure')}
selected={isConfigureStep}
disabled={!isDefined(fieldType)}
/>
</StyledMenuItemWrapper>
</DropdownMenuItemsContainer>
</DropdownMenu>
}
dropdownHotkeyScope={{ scope: dropdownId }}
/>
</StyledContainer>
);
};