Implement select v1 (#3312)

* Implement select v1

* Implement select v1
This commit is contained in:
Charles Bochet
2024-01-08 20:55:45 +01:00
committed by GitHub
parent ea2cb8938f
commit 67b14824a4
12 changed files with 96 additions and 42 deletions

View File

@ -28,6 +28,7 @@ export const useMapFieldMetadataToGraphQLQuery = () => {
'EMAIL',
'NUMBER',
'BOOLEAN',
'SELECT',
] as FieldType[]
).includes(fieldType);

View File

@ -40,6 +40,7 @@ export const formatFieldMetadataItemAsColumnDefinition = ({
relationObjectMetadataNamePlural:
relationObjectMetadataItem?.namePlural ?? '',
objectMetadataNameSingular: objectMetadataItem.nameSingular ?? '',
options: field.options,
},
iconName: field.icon ?? 'Icon123',
isVisible: true,

View File

@ -15,7 +15,6 @@ import { RecordInlineCell } from '@/object-record/record-inline-cell/components/
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
import { RecordRelationFieldCardSection } from '@/object-record/record-relation-card/components/RecordRelationFieldCardSection';
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
import { isFieldMetadataItemAvailable } from '@/object-record/utils/isFieldMetadataItemAvailable';
import { IconBuildingSkyscraper } from '@/ui/display/icon';
import { PageBody } from '@/ui/layout/page/PageBody';
@ -51,12 +50,13 @@ export const RecordShowPage = () => {
throw new Error(`Object name is not defined`);
}
const { objectMetadataItem, labelIdentifierFieldMetadata } =
useObjectMetadataItem({
objectNameSingular,
});
const { identifiersMapper } = useRelationPicker();
const {
objectMetadataItem,
labelIdentifierFieldMetadata,
mapToObjectRecordIdentifier,
} = useObjectMetadataItem({
objectNameSingular,
});
const { favorites, createFavorite, deleteFavorite } = useFavorites();
@ -107,11 +107,6 @@ export const RecordShowPage = () => {
? record?.name.firstName + ' ' + record?.name.lastName
: record?.name;
const recordIdentifiers = identifiersMapper?.(
record,
objectMetadataItem?.nameSingular ?? '',
);
const onUploadPicture = async (file: File) => {
if (objectNameSingular !== 'person') {
return;
@ -201,8 +196,12 @@ export const RecordShowPage = () => {
<>
<ShowPageSummaryCard
id={record.id}
logoOrAvatar={recordIdentifiers?.avatarUrl}
avatarPlaceholder={recordIdentifiers?.name ?? ''}
logoOrAvatar={
mapToObjectRecordIdentifier(record).avatarUrl ?? ''
}
avatarPlaceholder={
mapToObjectRecordIdentifier(record).name ?? ''
}
date={record.createdAt ?? ''}
title={
<FieldContext.Provider
@ -232,7 +231,10 @@ export const RecordShowPage = () => {
<RecordInlineCell />
</FieldContext.Provider>
}
avatarType={recordIdentifiers?.avatarType ?? 'rounded'}
avatarType={
mapToObjectRecordIdentifier(record).avatarType ??
'rounded'
}
onUploadPicture={
objectNameSingular === 'person'
? onUploadPicture

View File

@ -1,7 +1,9 @@
import { useContext } from 'react';
import { FullNameFieldInput } from '@/object-record/field/meta-types/input/components/FullNameFieldInput';
import { SelectFieldInput } from '@/object-record/field/meta-types/input/components/SelectFieldInput';
import { isFieldFullName } from '@/object-record/field/types/guards/isFieldFullName';
import { isFieldSelect } from '@/object-record/field/types/guards/isFieldSelect';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { FieldContext } from '../contexts/FieldContext';
@ -120,6 +122,8 @@ export const FieldInput = ({
<BooleanFieldInput onSubmit={onSubmit} />
) : isFieldRating(fieldDefinition) ? (
<RatingFieldInput onSubmit={onSubmit} />
) : isFieldSelect(fieldDefinition) ? (
<SelectFieldInput onSubmit={onSubmit} />
) : (
<></>
)}

View File

@ -3,6 +3,8 @@ import { useRecoilCallback } from 'recoil';
import { isFieldFullName } from '@/object-record/field/types/guards/isFieldFullName';
import { isFieldFullNameValue } from '@/object-record/field/types/guards/isFieldFullNameValue';
import { isFieldSelect } from '@/object-record/field/types/guards/isFieldSelect';
import { isFieldSelectValue } from '@/object-record/field/types/guards/isFieldSelectValue';
import { FieldContext } from '../contexts/FieldContext';
import { entityFieldsFamilySelector } from '../states/selectors/entityFieldsFamilySelector';
@ -77,6 +79,9 @@ export const usePersistField = () => {
const fieldIsPhone =
isFieldPhone(fieldDefinition) && isFieldPhoneValue(valueToPersist);
const fieldIsSelect =
isFieldSelect(fieldDefinition) && isFieldSelectValue(valueToPersist);
if (fieldIsRelation) {
const fieldName = fieldDefinition.metadata.fieldName;
@ -104,7 +109,8 @@ export const usePersistField = () => {
fieldIsPhone ||
fieldIsLink ||
fieldIsCurrency ||
fieldIsFullName
fieldIsFullName ||
fieldIsSelect
) {
const fieldName = fieldDefinition.metadata.fieldName;
set(

View File

@ -3,7 +3,15 @@ import { Tag } from '@/ui/display/tag/components/Tag';
import { useSelectField } from '../../hooks/useSelectField';
export const SelectFieldDisplay = () => {
const { fieldValue } = useSelectField();
const { fieldValue, fieldDefinition } = useSelectField();
return <Tag color={fieldValue.color} text={fieldValue.label} />;
const selectedOption = fieldDefinition.metadata.options.find(
(option) => option.value === fieldValue,
);
return selectedOption ? (
<Tag color={selectedOption.color} text={selectedOption.label} />
) : (
<></>
);
};

View File

@ -1,7 +1,7 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { ThemeColor } from '@/ui/theme/constants/colors';
import { usePersistField } from '@/object-record/field/hooks/usePersistField';
import { FieldMetadataType } from '~/generated/graphql';
import { FieldContext } from '../../contexts/FieldContext';
@ -25,23 +25,18 @@ export const useSelectField = () => {
fieldName: fieldName,
}),
);
const fieldSelectValue = isFieldSelectValue(fieldValue)
? fieldValue
: { color: 'green' as ThemeColor, label: '' };
const fieldSelectValue = isFieldSelectValue(fieldValue) ? fieldValue : null;
const fieldInitialValue = useFieldInitialValue();
const initialValue = {
color: 'green' as ThemeColor,
label: fieldInitialValue?.isEmpty
? ''
: fieldInitialValue?.value ?? fieldSelectValue?.label ?? '',
};
const persistField = usePersistField();
return {
fieldDefinition,
persistField,
fieldValue: fieldSelectValue,
initialValue,
initialValue: fieldInitialValue,
setFieldValue,
hotkeyScope,
};

View File

@ -0,0 +1,38 @@
import styled from '@emotion/styled';
import { MenuItem } from 'tsup.ui.index';
import { useSelectField } from '@/object-record/field/meta-types/hooks/useSelectField';
import { FieldInputEvent } from '@/object-record/field/types/FieldInputEvent';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
const StyledRelationPickerContainer = styled.div`
left: -1px;
position: absolute;
top: -1px;
`;
export type SelectFieldInputProps = {
onSubmit?: FieldInputEvent;
};
export const SelectFieldInput = ({ onSubmit }: SelectFieldInputProps) => {
const { persistField, fieldDefinition } = useSelectField();
return (
<StyledRelationPickerContainer>
<DropdownMenu data-select-disable>
<DropdownMenuItemsContainer>
{fieldDefinition.metadata.options.map((option) => {
return (
<MenuItem
text={option.label}
onClick={() => onSubmit?.(() => persistField(option.value))}
/>
);
})}
</DropdownMenuItemsContainer>
</DropdownMenu>
</StyledRelationPickerContainer>
);
};

View File

@ -87,6 +87,7 @@ export type FieldRelationMetadata = {
export type FieldSelectMetadata = {
objectMetadataNameSingular?: string;
fieldName: string;
options: { label: string; color: ThemeColor; value: string }[];
};
export type FieldMetadata =
@ -119,6 +120,6 @@ export type FieldCurrencyValue = {
};
export type FieldFullNameValue = { firstName: string; lastName: string };
export type FieldRatingValue = '1' | '2' | '3' | '4' | '5';
export type FieldSelectValue = { color: ThemeColor; label: string };
export type FieldSelectValue = string | null;
export type FieldRelationValue = EntityForSelect | null;

View File

@ -1,13 +1,7 @@
import { z } from 'zod';
import { isString } from '@sniptt/guards';
import { themeColorSchema } from '@/ui/theme/utils/themeColorSchema';
const selectValueSchema = z.object({
color: themeColorSchema,
label: z.string(),
});
import { FieldSelectValue } from '@/object-record/field/types/FieldMetadata';
export const isFieldSelectValue = (
fieldValue: unknown,
): fieldValue is z.infer<typeof selectValueSchema> =>
selectValueSchema.safeParse(fieldValue).success;
): fieldValue is FieldSelectValue => isString(fieldValue);

View File

@ -14,6 +14,7 @@ import { isFieldRating } from '@/object-record/field/types/guards/isFieldRating'
import { isFieldRelation } from '@/object-record/field/types/guards/isFieldRelation';
import { isFieldRelationValue } from '@/object-record/field/types/guards/isFieldRelationValue';
import { isFieldSelect } from '@/object-record/field/types/guards/isFieldSelect';
import { isFieldSelectValue } from '@/object-record/field/types/guards/isFieldSelectValue';
import { isFieldText } from '@/object-record/field/types/guards/isFieldText';
import { isFieldUuid } from '@/object-record/field/types/guards/isFieldUuid';
import { assertNotNull } from '~/utils/assert';
@ -34,8 +35,7 @@ export const isFieldValueEmpty = ({
isFieldNumber(fieldDefinition) ||
isFieldRating(fieldDefinition) ||
isFieldEmail(fieldDefinition) ||
isFieldBoolean(fieldDefinition) ||
isFieldSelect(fieldDefinition)
isFieldBoolean(fieldDefinition)
//|| isFieldPhone(fieldDefinition)
) {
return isValueEmpty(fieldValue);
@ -45,6 +45,10 @@ export const isFieldValueEmpty = ({
return isFieldRelationValue(fieldValue) && isValueEmpty(fieldValue);
}
if (isFieldSelect(fieldDefinition)) {
return isFieldSelectValue(fieldValue) && !assertNotNull(fieldValue);
}
if (isFieldCurrency(fieldDefinition)) {
return (
!isFieldCurrencyValue(fieldValue) ||

View File

@ -41,7 +41,7 @@ class Support {
@ObjectType()
class Sentry {
@Field(() => String)
@Field(() => String, { nullable: true })
dsn: string | undefined;
}