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:
@ -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
|
||||
|
||||
@ -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={[
|
||||
|
||||
@ -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>
|
||||
|
||||
Reference in New Issue
Block a user