Added new view to select types for objects (#6700)

Issue #6496 
Hi team,

Is this the right approach for handling type selection with states and
conditional rendering, or should these be managed on separate pages
altogether? Please let me know Ill make changes accordingly :)

I’m also working on styling the buttons according to the Figma design
and will be moving constants like categoryDescriptions and categories to
the constants folder.

Thanks for your guidance!



https://github.com/user-attachments/assets/452bea9f-4d0a-4472-9941-421b54cda47f

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
nitin
2024-09-07 02:17:40 +05:30
committed by GitHub
parent 99f8f8fedb
commit 79aba75649
17 changed files with 597 additions and 264 deletions

View File

@ -1,5 +1,4 @@
import { useApolloClient } from '@apollo/client';
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import omit from 'lodash.omit';
import pick from 'lodash.pick';
@ -22,9 +21,9 @@ import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength';
import { SettingsDataModelFieldAboutForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldAboutForm';
import { SettingsDataModelFieldDescriptionForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldDescriptionForm';
import { SettingsDataModelFieldIconLabelForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm';
import { SettingsDataModelFieldSettingsFormCard } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard';
import { SettingsDataModelFieldTypeSelect } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldTypeSelect';
import { settingsFieldFormSchema } from '@/settings/data-model/fields/forms/validation-schemas/settingsFieldFormSchema';
import { AppPath } from '@/types/AppPath';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
@ -40,12 +39,6 @@ type SettingsDataModelFieldEditFormValues = z.infer<
ReturnType<typeof settingsFieldFormSchema>
>;
const StyledSettingsObjectFieldTypeSelect = styled(
SettingsDataModelFieldTypeSelect,
)`
margin-bottom: ${({ theme }) => theme.spacing(4)};
`;
const canPersistFieldMetadataItemUpdate = (
fieldMetadataItem: FieldMetadataItem,
) => {
@ -204,34 +197,33 @@ export const SettingsObjectFieldEdit = () => {
<SettingsPageContainer>
<Section>
<H2Title
title="Name and description"
description="The name and description of this field"
title="Icon and Name"
description="The name and icon of this field"
/>
<SettingsDataModelFieldAboutForm
<SettingsDataModelFieldIconLabelForm
disabled={!activeMetadataField.isCustom}
fieldMetadataItem={activeMetadataField}
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
/>
</Section>
<Section>
<H2Title
title="Type and values"
description="The field's type and values."
/>
<StyledSettingsObjectFieldTypeSelect
disabled
fieldMetadataItem={activeMetadataField}
excludedFieldTypes={[
FieldMetadataType.Link,
FieldMetadataType.Email,
]}
/>
<H2Title title="Values" description="The values of this field" />
<SettingsDataModelFieldSettingsFormCard
disableCurrencyForm
fieldMetadataItem={activeMetadataField}
objectMetadataItem={activeObjectMetadataItem}
/>
</Section>
<Section>
<H2Title
title="Description"
description="The description of this field"
/>
<SettingsDataModelFieldDescriptionForm
disabled={!activeMetadataField.isCustom}
fieldMetadataItem={activeMetadataField}
/>
</Section>
{!isLabelIdentifier && (
<Section>
<H2Title

View File

@ -1,7 +1,7 @@
import styled from '@emotion/styled';
import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { H2Title, IconPlus, IconSettings } from 'twenty-ui';
import { H2Title, IconHierarchy2, IconPlus } from 'twenty-ui';
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
@ -85,7 +85,7 @@ export const SettingsObjectNewFieldStep1 = () => {
return (
<SubMenuTopBarContainer
Icon={IconSettings}
Icon={IconHierarchy2}
title={
<Breadcrumb
links={[

View File

@ -1,13 +1,3 @@
import { useApolloClient } from '@apollo/client';
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import pick from 'lodash.pick';
import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { H2Title, IconSettings } from 'twenty-ui';
import { z } from 'zod';
import { useCreateOneRelationMetadataItem } from '@/object-metadata/hooks/useCreateOneRelationMetadataItem';
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
@ -15,10 +5,11 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsDataModelNewFieldBreadcrumbDropDown } from '@/settings/data-model/components/SettingsDataModelNewFieldBreadcrumbDropDown';
import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength';
import { SettingsDataModelFieldAboutForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldAboutForm';
import { SettingsDataModelFieldDescriptionForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldDescriptionForm';
import { SettingsDataModelFieldIconLabelForm } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldIconLabelForm';
import { SettingsDataModelFieldSettingsFormCard } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldSettingsFormCard';
import { SettingsDataModelFieldTypeSelect } from '@/settings/data-model/fields/forms/components/SettingsDataModelFieldTypeSelect';
import { settingsFieldFormSchema } from '@/settings/data-model/fields/forms/validation-schemas/settingsFieldFormSchema';
@ -31,6 +22,15 @@ import { Section } from '@/ui/layout/section/components/Section';
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
import { View } from '@/views/types/View';
import { ViewType } from '@/views/types/ViewType';
import { useApolloClient } from '@apollo/client';
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import pick from 'lodash.pick';
import { useEffect, useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { H1Title, H1TitleFontColor, H2Title, IconHierarchy2 } from 'twenty-ui';
import { z } from 'zod';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isDefined } from '~/utils/isDefined';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
@ -39,12 +39,9 @@ type SettingsDataModelNewFieldFormValues = z.infer<
ReturnType<typeof settingsFieldFormSchema>
>;
const StyledSettingsObjectFieldTypeSelect = styled(
SettingsDataModelFieldTypeSelect,
)`
margin-bottom: ${({ theme }) => theme.spacing(4)};
const StyledH1Title = styled(H1Title)`
margin-bottom: 0;
`;
export const SettingsObjectNewFieldStep2 = () => {
const navigate = useNavigate();
const { objectSlug = '' } = useParams();
@ -52,6 +49,7 @@ export const SettingsObjectNewFieldStep2 = () => {
const fieldType = searchParams.get('fieldType') as SettingsSupportedFieldType;
const { enqueueSnackBar } = useSnackBar();
const [isConfigureStep, setIsConfigureStep] = useState(false);
const { findActiveObjectMetadataItemBySlug } =
useFilteredObjectMetadataItems();
@ -176,62 +174,102 @@ export const SettingsObjectNewFieldStep2 = () => {
<FormProvider // eslint-disable-next-line react/jsx-props-no-spreading
{...formConfig}
>
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
<SubMenuTopBarContainer
Icon={IconHierarchy2}
title={
<Breadcrumb
links={[
{
children: 'Objects',
href: '/settings/objects',
styles: { minWidth: 'max-content' },
},
{
children: activeObjectMetadataItem.labelPlural,
href: `/settings/objects/${objectSlug}`,
styles: { maxWidth: '50%' },
},
{
children: (
<SettingsDataModelNewFieldBreadcrumbDropDown
isConfigureStep={isConfigureStep}
onBreadcrumbClick={setIsConfigureStep}
/>
),
},
]}
/>
}
actionButton={
!activeObjectMetadataItem.isRemote && (
<SaveAndCancelButtons
isSaveDisabled={!canSave}
isCancelDisabled={isSubmitting}
onCancel={() => {
if (!isConfigureStep) {
navigate(`/settings/objects/${objectSlug}`);
} else {
setIsConfigureStep(false);
}
}}
onSave={formConfig.handleSubmit(handleSave)}
/>
)
}
>
<SettingsPageContainer>
<SettingsHeaderContainer>
<Breadcrumb
links={[
{
children: 'Objects',
href: '/settings/objects',
styles: { minWidth: 'max-content' },
},
{
children: activeObjectMetadataItem.labelPlural,
href: `/settings/objects/${objectSlug}`,
styles: { maxWidth: '50%' },
},
{ children: 'New Field' },
]}
/>
{!activeObjectMetadataItem.isRemote && (
<SaveAndCancelButtons
isSaveDisabled={!canSave}
isCancelDisabled={isSubmitting}
onCancel={() => navigate(`/settings/objects/${objectSlug}`)}
onSave={formConfig.handleSubmit(handleSave)}
/>
)}
</SettingsHeaderContainer>
<Section>
<H2Title
title="Name and description"
description="The name and description of this field"
/>
<SettingsDataModelFieldAboutForm
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
/>
</Section>
<Section>
<H2Title
title="Type and values"
description="The field's type and values."
/>
<StyledSettingsObjectFieldTypeSelect
<StyledH1Title
title={
!isConfigureStep
? '1. Select a field type'
: '2. Configure field'
}
fontColor={H1TitleFontColor.Primary}
/>
{!isConfigureStep ? (
<SettingsDataModelFieldTypeSelect
excludedFieldTypes={excludedFieldTypes}
fieldMetadataItem={{
type: fieldType,
}}
onFieldTypeSelect={() => setIsConfigureStep(true)}
/>
<SettingsDataModelFieldSettingsFormCard
fieldMetadataItem={{
icon: formConfig.watch('icon'),
label: formConfig.watch('label') || 'Employees',
type: formConfig.watch('type'),
}}
objectMetadataItem={activeObjectMetadataItem}
/>
</Section>
) : (
<>
<Section>
<H2Title
title="Icon and Name"
description="The name and icon of this field"
/>
<SettingsDataModelFieldIconLabelForm
maxLength={FIELD_NAME_MAXIMUM_LENGTH}
/>
</Section>
<Section>
<H2Title
title="Values"
description="The values of this field"
/>
<SettingsDataModelFieldSettingsFormCard
fieldMetadataItem={{
icon: formConfig.watch('icon'),
label: formConfig.watch('label') || 'Employees',
type: formConfig.watch('type'),
}}
objectMetadataItem={activeObjectMetadataItem}
/>
</Section>
<Section>
<H2Title
title="Description"
description="The description of this field"
/>
<SettingsDataModelFieldDescriptionForm />
</Section>
</>
)}
</SettingsPageContainer>
</SubMenuTopBarContainer>
</FormProvider>