Breadcrumb DropDown improvement (#7546)
context - https://github.com/twentyhq/twenty/pull/7397#pullrequestreview-2356581785 P.S. Apologies for the background music in the screen recording—I didn’t realize my mic was on while capturing it. 😅 https://github.com/user-attachments/assets/0cd31aa7-9ce2-4577-a79a-73c9890f2905 --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -1,3 +1,4 @@
|
|||||||
|
import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType';
|
||||||
import { Button } from '@/ui/input/button/components/Button';
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||||
@ -6,13 +7,18 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|||||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
import {
|
||||||
import { IconChevronDown } from 'twenty-ui';
|
useLocation,
|
||||||
|
useNavigate,
|
||||||
|
useParams,
|
||||||
|
useSearchParams,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import { IconChevronDown, isDefined } from 'twenty-ui';
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: ${({ theme }) => theme.font.color.tertiary};
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
cursor: pointer;
|
cursor: default;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: ${({ theme }) => theme.font.size.md};
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
`;
|
`;
|
||||||
@ -30,10 +36,24 @@ const StyledDownChevron = styled(IconChevronDown)`
|
|||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledMenuItem = styled(MenuItem)<{ selected?: boolean }>`
|
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 }) =>
|
background: ${({ theme, selected }) =>
|
||||||
selected ? theme.background.quaternary : 'transparent'};
|
selected ? theme.background.quaternary : 'transparent'};
|
||||||
cursor: pointer;
|
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`
|
const StyledSpan = styled.span`
|
||||||
@ -51,16 +71,23 @@ export const SettingsDataModelNewFieldBreadcrumbDropDown = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { objectSlug = '' } = useParams();
|
const { objectSlug = '' } = useParams();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const fieldType = searchParams.get('fieldType') as SettingsFieldType;
|
||||||
const isConfigureStep = location.pathname.includes('/configure');
|
const isConfigureStep = location.pathname.includes('/configure');
|
||||||
|
|
||||||
const handleClick = (isConfigureStep: boolean) => {
|
const handleClick = (step: 'select' | 'configure') => {
|
||||||
if (isConfigureStep) {
|
if (step === 'configure' && isDefined(fieldType)) {
|
||||||
navigate(`/settings/objects/${objectSlug}/new-field/configure`);
|
navigate(
|
||||||
} else {
|
`/settings/objects/${objectSlug}/new-field/configure?fieldType=${fieldType}`,
|
||||||
navigate(`/settings/objects/${objectSlug}/new-field/select`);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
navigate(
|
||||||
|
`/settings/objects/${objectSlug}/new-field/select${fieldType ? `?fieldType=${fieldType}` : ''}`,
|
||||||
|
);
|
||||||
closeDropdown();
|
closeDropdown();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -83,16 +110,21 @@ export const SettingsDataModelNewFieldBreadcrumbDropDown = () => {
|
|||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
<StyledMenuItem
|
<StyledMenuItemWrapper>
|
||||||
text="1. Type"
|
<StyledMenuItem
|
||||||
onClick={() => handleClick(false)}
|
text="1. Type"
|
||||||
selected={!isConfigureStep}
|
onClick={() => handleClick('select')}
|
||||||
/>
|
selected={!isConfigureStep}
|
||||||
<StyledMenuItem
|
/>
|
||||||
text="2. Configure"
|
</StyledMenuItemWrapper>
|
||||||
onClick={() => handleClick(true)}
|
<StyledMenuItemWrapper disabled={!isDefined(fieldType)}>
|
||||||
selected={isConfigureStep}
|
<StyledMenuItem
|
||||||
/>
|
text="2. Configure"
|
||||||
|
onClick={() => handleClick('configure')}
|
||||||
|
selected={isConfigureStep}
|
||||||
|
disabled={!isDefined(fieldType)}
|
||||||
|
/>
|
||||||
|
</StyledMenuItemWrapper>
|
||||||
</DropdownMenuItemsContainer>
|
</DropdownMenuItemsContainer>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { SETTINGS_FIELD_TYPE_CATEGORIES } from '@/settings/data-model/constants/
|
|||||||
import { SETTINGS_FIELD_TYPE_CATEGORY_DESCRIPTIONS } from '@/settings/data-model/constants/SettingsFieldTypeCategoryDescriptions';
|
import { SETTINGS_FIELD_TYPE_CATEGORY_DESCRIPTIONS } from '@/settings/data-model/constants/SettingsFieldTypeCategoryDescriptions';
|
||||||
import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
|
import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
|
||||||
import { SettingsFieldTypeConfig } from '@/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs';
|
import { SettingsFieldTypeConfig } from '@/settings/data-model/constants/SettingsNonCompositeFieldTypeConfigs';
|
||||||
|
|
||||||
import { useBooleanSettingsFormInitialValues } from '@/settings/data-model/fields/forms/boolean/hooks/useBooleanSettingsFormInitialValues';
|
import { useBooleanSettingsFormInitialValues } from '@/settings/data-model/fields/forms/boolean/hooks/useBooleanSettingsFormInitialValues';
|
||||||
import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues';
|
import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues';
|
||||||
import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues';
|
import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues';
|
||||||
@ -63,7 +62,8 @@ export const SettingsObjectNewFieldSelector = ({
|
|||||||
objectSlug,
|
objectSlug,
|
||||||
}: SettingsObjectNewFieldSelectorProps) => {
|
}: SettingsObjectNewFieldSelectorProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { control } = useFormContext<SettingsDataModelFieldTypeFormValues>();
|
const { control, setValue } =
|
||||||
|
useFormContext<SettingsDataModelFieldTypeFormValues>();
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const fieldTypeConfigs = Object.entries<SettingsFieldTypeConfig<any>>(
|
const fieldTypeConfigs = Object.entries<SettingsFieldTypeConfig<any>>(
|
||||||
SETTINGS_FIELD_TYPE_CONFIGS,
|
SETTINGS_FIELD_TYPE_CONFIGS,
|
||||||
@ -131,9 +131,10 @@ export const SettingsObjectNewFieldSelector = ({
|
|||||||
<UndecoratedLink
|
<UndecoratedLink
|
||||||
to={`/settings/objects/${objectSlug}/new-field/configure?fieldType=${key}`}
|
to={`/settings/objects/${objectSlug}/new-field/configure?fieldType=${key}`}
|
||||||
fullWidth
|
fullWidth
|
||||||
onClick={() =>
|
onClick={() => {
|
||||||
resetDefaultValueField(key as SettingsFieldType)
|
setValue('type', key as SettingsFieldType);
|
||||||
}
|
resetDefaultValueField(key as SettingsFieldType);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<SettingsCard
|
<SettingsCard
|
||||||
key={key}
|
key={key}
|
||||||
|
|||||||
@ -178,7 +178,9 @@ export const SettingsObjectNewFieldConfigure = () => {
|
|||||||
isSaveDisabled={!canSave}
|
isSaveDisabled={!canSave}
|
||||||
isCancelDisabled={isSubmitting}
|
isCancelDisabled={isSubmitting}
|
||||||
onCancel={() =>
|
onCancel={() =>
|
||||||
navigate(`/settings/objects/${objectSlug}/new-field/select`)
|
navigate(
|
||||||
|
`/settings/objects/${objectSlug}/new-field/select?fieldType=${fieldType}`,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
onSave={formConfig.handleSubmit(handleSave)}
|
onSave={formConfig.handleSubmit(handleSave)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user