mirror of
https://github.com/twentyhq/twenty.git
synced 2025-01-05 10:54:15 +03:00
feat: add Url field preview in settings (#2402)
* feat: add Url field preview in settings Closes #2326 * feat: add Date field type in settings (#2414) Closes #2331
This commit is contained in:
parent
588091d3dd
commit
b28ff9c97e
@ -6,6 +6,7 @@ import { logError } from '~/utils/logError';
|
||||
|
||||
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
|
||||
import { PaginatedObjectType } from '../types/PaginatedObjectType';
|
||||
import { PaginatedObjectTypeResults } from '../types/PaginatedObjectTypeResults';
|
||||
import { formatPagedObjectsToObjects } from '../utils/formatPagedObjectsToObjects';
|
||||
|
||||
import { useFindOneObjectMetadataItem } from './useFindOneObjectMetadataItem';
|
||||
@ -23,7 +24,7 @@ export const useFindManyObjects = <
|
||||
}: Pick<ObjectMetadataItemIdentifier, 'objectNamePlural'> & {
|
||||
filter?: any;
|
||||
orderBy?: any;
|
||||
onCompleted?: (data: any) => void;
|
||||
onCompleted?: (data: PaginatedObjectTypeResults<ObjectType>) => void;
|
||||
skip?: boolean;
|
||||
}) => {
|
||||
const { foundObjectMetadataItem, objectNotFoundInMetadata, findManyQuery } =
|
||||
|
@ -64,7 +64,9 @@ export const SettingsObjectFieldTypeSelectSection = ({
|
||||
}),
|
||||
)}
|
||||
/>
|
||||
{['BOOLEAN', 'MONEY', 'NUMBER', 'TEXT'].includes(fieldType) && (
|
||||
{['BOOLEAN', 'DATE', 'MONEY', 'NUMBER', 'TEXT', 'URL'].includes(
|
||||
fieldType,
|
||||
) && (
|
||||
<StyledSettingsObjectFieldTypeCard
|
||||
preview={
|
||||
<SettingsObjectFieldPreview
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||
@ -40,6 +41,29 @@ export const Currency: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Date: Story = {
|
||||
args: {
|
||||
fieldIconKey: 'IconCalendarEvent',
|
||||
fieldLabel: 'Registration Date',
|
||||
fieldType: 'DATE',
|
||||
},
|
||||
};
|
||||
|
||||
export const Link: Story = {
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<MemoryRouter>
|
||||
<Story />
|
||||
</MemoryRouter>
|
||||
),
|
||||
],
|
||||
args: {
|
||||
fieldIconKey: 'IconWorldWww',
|
||||
fieldLabel: 'Website',
|
||||
fieldType: 'URL',
|
||||
},
|
||||
};
|
||||
|
||||
export const Number: Story = {
|
||||
args: {
|
||||
fieldIconKey: 'IconUsers',
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {
|
||||
IconCalendarEvent,
|
||||
IconCheck,
|
||||
IconCoins,
|
||||
IconLink,
|
||||
@ -11,23 +12,35 @@ import { Currency } from '~/generated-metadata/graphql';
|
||||
|
||||
import { MetadataFieldDataType } from '../types/ObjectFieldDataType';
|
||||
|
||||
const defaultDateValue = new Date();
|
||||
defaultDateValue.setFullYear(defaultDateValue.getFullYear() + 2);
|
||||
|
||||
export const dataTypes: Record<
|
||||
MetadataFieldDataType,
|
||||
{ label: string; Icon: IconComponent; defaultValue?: unknown }
|
||||
> = {
|
||||
BOOLEAN: { label: 'True/False', Icon: IconCheck, defaultValue: true },
|
||||
MONEY: {
|
||||
label: 'Currency',
|
||||
Icon: IconCoins,
|
||||
defaultValue: { amount: 2000, currency: Currency.Usd },
|
||||
},
|
||||
NUMBER: { label: 'Number', Icon: IconNumbers, defaultValue: 2000 },
|
||||
RELATION: { label: 'Relation', Icon: IconPlug },
|
||||
TEXT: {
|
||||
label: 'Text',
|
||||
Icon: IconTextSize,
|
||||
defaultValue:
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum magna enim, dapibus non enim in, lacinia faucibus nunc. Sed interdum ante sed felis facilisis, eget ultricies neque molestie. Mauris auctor, justo eu volutpat cursus, libero erat tempus nulla, non sodales lorem lacus a est.',
|
||||
},
|
||||
URL: { label: 'Link', Icon: IconLink },
|
||||
NUMBER: { label: 'Number', Icon: IconNumbers, defaultValue: 2000 },
|
||||
URL: {
|
||||
label: 'Link',
|
||||
Icon: IconLink,
|
||||
defaultValue: { link: 'www.twenty.com', text: '' },
|
||||
},
|
||||
BOOLEAN: { label: 'True/False', Icon: IconCheck, defaultValue: true },
|
||||
DATE: {
|
||||
label: 'Date',
|
||||
Icon: IconCalendarEvent,
|
||||
defaultValue: defaultDateValue.toISOString(),
|
||||
},
|
||||
MONEY: {
|
||||
label: 'Currency',
|
||||
Icon: IconCoins,
|
||||
defaultValue: { amount: 2000, currency: Currency.Usd },
|
||||
},
|
||||
RELATION: { label: 'Relation', Icon: IconPlug },
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
export type MetadataFieldDataType =
|
||||
| 'BOOLEAN'
|
||||
| 'DATE'
|
||||
| 'MONEY'
|
||||
| 'NUMBER'
|
||||
| 'RELATION'
|
||||
|
@ -50,7 +50,7 @@ export const URLV2Display = ({ value }: URLV2DisplayProps) => {
|
||||
: 'https://' + value.link
|
||||
: '';
|
||||
|
||||
const displayedValue = value?.text ?? '';
|
||||
const displayedValue = value?.text || value?.link || '';
|
||||
|
||||
const type = checkUrlType(absoluteUrl);
|
||||
|
||||
|
@ -9,6 +9,7 @@ import { usePersistField } from '../../hooks/usePersistField';
|
||||
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
|
||||
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
|
||||
import { isFieldURL } from '../../types/guards/isFieldURL';
|
||||
import { isFieldURLValue } from '../../types/guards/isFieldURLValue';
|
||||
|
||||
export const useURLField = () => {
|
||||
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
|
||||
@ -23,12 +24,13 @@ export const useURLField = () => {
|
||||
fieldName: fieldName,
|
||||
}),
|
||||
);
|
||||
const fieldUrlValue = isFieldURLValue(fieldValue) ? fieldValue : '';
|
||||
|
||||
const fieldInitialValue = useFieldInitialValue();
|
||||
|
||||
const initialValue = fieldInitialValue?.isEmpty
|
||||
? ''
|
||||
: fieldInitialValue?.value ?? fieldValue;
|
||||
: fieldInitialValue?.value ?? fieldUrlValue;
|
||||
|
||||
const persistField = usePersistField();
|
||||
|
||||
@ -42,7 +44,7 @@ export const useURLField = () => {
|
||||
|
||||
return {
|
||||
fieldDefinition,
|
||||
fieldValue,
|
||||
fieldValue: fieldUrlValue,
|
||||
initialValue,
|
||||
setFieldValue,
|
||||
hotkeyScope,
|
||||
|
@ -28,7 +28,9 @@ export const useURLV2Field = () => {
|
||||
|
||||
const initialValue: FieldURLV2Value = fieldInitialValue?.isEmpty
|
||||
? { link: '', text: '' }
|
||||
: { link: fieldInitialValue?.value ?? '', text: '' } ?? fieldValue;
|
||||
: fieldInitialValue?.value
|
||||
? { link: fieldInitialValue.value, text: '' }
|
||||
: fieldValue;
|
||||
|
||||
const persistField = usePersistField();
|
||||
|
||||
|
@ -19,6 +19,8 @@ import { isFieldRelation } from '../../types/guards/isFieldRelation';
|
||||
import { isFieldRelationValue } from '../../types/guards/isFieldRelationValue';
|
||||
import { isFieldText } from '../../types/guards/isFieldText';
|
||||
import { isFieldURL } from '../../types/guards/isFieldURL';
|
||||
import { isFieldURLV2 } from '../../types/guards/isFieldURLV2';
|
||||
import { isFieldURLV2Value } from '../../types/guards/isFieldURLV2Value';
|
||||
import { entityFieldsFamilyState } from '../entityFieldsFamilyState';
|
||||
|
||||
const isValueEmpty = (value: unknown) => !assertNotNull(value) || value === '';
|
||||
@ -104,6 +106,13 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
|
||||
);
|
||||
}
|
||||
|
||||
if (isFieldURLV2(fieldDefinition)) {
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
|
||||
|
||||
return !isFieldURLV2Value(fieldValue) || isValueEmpty(fieldValue?.link);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Entity field type not supported in isEntityFieldEmptyFamilySelector : ${fieldDefinition.type}}`,
|
||||
);
|
||||
|
@ -18,7 +18,7 @@ export const SettingsExperience = () => {
|
||||
|
||||
return (
|
||||
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
|
||||
<SettingsPageContainer width={350}>
|
||||
<SettingsPageContainer>
|
||||
<StyledH1Title title="Experience" />
|
||||
<Section>
|
||||
<H2Title title="Appearance" />
|
||||
|
Loading…
Reference in New Issue
Block a user