Complete labelIdentifer, relationPicker first implementation (#2618)

* Fix first column main identifier

* Fixes
This commit is contained in:
Charles Bochet
2023-11-21 18:32:36 +01:00
committed by GitHub
parent dd125ddfcc
commit 726e375616
27 changed files with 165 additions and 91 deletions

View File

@ -239,7 +239,7 @@ export const CompanyBoardCard = () => {
value={{ value={{
entityId: boardCardId, entityId: boardCardId,
recoilScopeId: boardCardId + viewField.fieldMetadataId, recoilScopeId: boardCardId + viewField.fieldMetadataId,
isMainIdentifier: false, isLabelIdentifier: false,
fieldDefinition: { fieldDefinition: {
fieldMetadataId: viewField.fieldMetadataId, fieldMetadataId: viewField.fieldMetadataId,
label: viewField.label, label: viewField.label,

View File

@ -2,9 +2,22 @@ import { useEffect } from 'react';
import { useRelationPicker } from '@/ui/input/components/internal/relation-picker/hooks/useRelationPicker'; import { useRelationPicker } from '@/ui/input/components/internal/relation-picker/hooks/useRelationPicker';
import { IdentifiersMapper } from '@/ui/input/components/internal/relation-picker/types/IdentifiersMapper'; import { IdentifiersMapper } from '@/ui/input/components/internal/relation-picker/types/IdentifiersMapper';
import { getLogoUrlFromDomainName } from '~/utils';
export const ObjectMetadataItemsRelationPickerEffect = () => { export const ObjectMetadataItemsRelationPickerEffect = () => {
const { setIdentifiersMapper } = useRelationPicker(); const { setIdentifiersMapper, setSearchQuery } = useRelationPicker();
const computeFilterFields = (relationPickerType: string) => {
if (relationPickerType === 'company') {
return ['name'];
}
if (['workspaceMember', 'person'].includes(relationPickerType)) {
return ['name.firstName', 'name.lastName'];
}
return ['name'];
};
const identifierMapper: IdentifiersMapper = ( const identifierMapper: IdentifiersMapper = (
record: any, record: any,
@ -18,13 +31,15 @@ export const ObjectMetadataItemsRelationPickerEffect = () => {
return { return {
id: record.id, id: record.id,
name: record.name, name: record.name,
avatarUrl: record.avatarUrl, avatarUrl: getLogoUrlFromDomainName(record.domainName ?? ''),
avatarType: 'squared', avatarType: 'squared',
record: record, record: record,
}; };
} }
if (objectMetadataItemSingularName === 'workspaceMember') { if (
['workspaceMember', 'person'].includes(objectMetadataItemSingularName)
) {
return { return {
id: record.id, id: record.id,
name: record.name.firstName + ' ' + record.name.lastName, name: record.name.firstName + ' ' + record.name.lastName,
@ -34,6 +49,16 @@ export const ObjectMetadataItemsRelationPickerEffect = () => {
}; };
} }
if (['opportunity'].includes(objectMetadataItemSingularName)) {
return {
id: record.id,
name: record.company.name,
avatarUrl: record.avatarUrl,
avatarType: 'rounded',
record: record,
};
}
return { return {
id: record.id, id: record.id,
name: record.name, name: record.name,
@ -45,7 +70,10 @@ export const ObjectMetadataItemsRelationPickerEffect = () => {
useEffect(() => { useEffect(() => {
setIdentifiersMapper(() => identifierMapper); setIdentifiersMapper(() => identifierMapper);
}, [setIdentifiersMapper]); setSearchQuery({
computeFilterFields,
});
}, [setIdentifiersMapper, setSearchQuery]);
return <></>; return <></>;
}; };

View File

@ -22,13 +22,16 @@ export const useComputeDefinitionsFromFieldMetadata = (
const columnDefinitions: ColumnDefinition<FieldMetadata>[] = useMemo( const columnDefinitions: ColumnDefinition<FieldMetadata>[] = useMemo(
() => () =>
activeFieldMetadataItems.map((field, index) => objectMetadataItem
formatFieldMetadataItemAsColumnDefinition({ ? activeFieldMetadataItems.map((field, index) =>
position: index, formatFieldMetadataItemAsColumnDefinition({
field, position: index,
}), field,
), objectMetadataItem,
[activeFieldMetadataItems], }),
)
: [],
[activeFieldMetadataItems, objectMetadataItem],
); );
const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({ const filterDefinitions = formatFieldMetadataItemsAsFilterDefinitions({

View File

@ -1,21 +0,0 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { Nullable } from '~/types/Nullable';
export const useObjectMainIdentifier = (
objectMetadataItem?: Nullable<ObjectMetadataItem>,
) => {
if (!objectMetadataItem) {
return {};
}
const labelIdentifierFieldMetadataId = objectMetadataItem.fields.find(
({ name }) => name === 'name',
)?.id;
const basePathToShowPage = `/object/${objectMetadataItem.nameSingular}/`;
return {
labelIdentifierFieldMetadataId,
basePathToShowPage,
};
};

View File

@ -56,7 +56,15 @@ export const useObjectMetadataItem = ({
objectMetadataItem, objectMetadataItem,
}); });
const labelIdentifierFieldMetadataId = objectMetadataItem?.fields.find(
({ name }) => name === 'name',
)?.id;
const basePathToShowPage = `/object/${objectMetadataItem?.nameSingular}/`;
return { return {
labelIdentifierFieldMetadataId,
basePathToShowPage,
objectMetadataItem, objectMetadataItem,
objectNotFoundInMetadata, objectNotFoundInMetadata,
findManyQuery, findManyQuery,

View File

@ -1,3 +1,4 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { parseFieldRelationType } from '@/object-metadata/utils/parseFieldRelationType'; import { parseFieldRelationType } from '@/object-metadata/utils/parseFieldRelationType';
import { FieldMetadata } from '@/ui/object/field/types/FieldMetadata'; import { FieldMetadata } from '@/ui/object/field/types/FieldMetadata';
import { ColumnDefinition } from '@/ui/object/record-table/types/ColumnDefinition'; import { ColumnDefinition } from '@/ui/object/record-table/types/ColumnDefinition';
@ -9,9 +10,11 @@ import { parseFieldType } from './parseFieldType';
export const formatFieldMetadataItemAsColumnDefinition = ({ export const formatFieldMetadataItemAsColumnDefinition = ({
position, position,
field, field,
objectMetadataItem,
}: { }: {
position: number; position: number;
field: FieldMetadataItem; field: FieldMetadataItem;
objectMetadataItem: ObjectMetadataItem;
}): ColumnDefinition<FieldMetadata> => { }): ColumnDefinition<FieldMetadata> => {
const relationObjectMetadataItem = const relationObjectMetadataItem =
field.toRelationMetadata?.fromObjectMetadata; field.toRelationMetadata?.fromObjectMetadata;
@ -26,9 +29,11 @@ export const formatFieldMetadataItemAsColumnDefinition = ({
fieldName: field.name, fieldName: field.name,
placeHolder: field.label, placeHolder: field.label,
relationType: parseFieldRelationType(field), relationType: parseFieldRelationType(field),
objectMetadataNameSingular: relationObjectMetadataNameSingular:
relationObjectMetadataItem?.nameSingular ?? '', relationObjectMetadataItem?.nameSingular ?? '',
objectMetadataNamePlural: relationObjectMetadataItem?.namePlural ?? '', relationObjectMetadataNamePlural:
relationObjectMetadataItem?.namePlural ?? '',
objectMetadataNameSingular: objectMetadataItem.nameSingular ?? '',
}, },
iconName: field.icon ?? 'Icon123', iconName: field.icon ?? 'Icon123',
isVisible: true, isVisible: true,

View File

@ -166,11 +166,12 @@ export const RecordShowPage = () => {
value={{ value={{
entityId: object.id, entityId: object.id,
recoilScopeId: object.id + metadataField.id, recoilScopeId: object.id + metadataField.id,
isMainIdentifier: false, isLabelIdentifier: false,
fieldDefinition: fieldDefinition:
formatFieldMetadataItemAsColumnDefinition({ formatFieldMetadataItemAsColumnDefinition({
field: metadataField, field: metadataField,
position: index, position: index,
objectMetadataItem,
}), }),
useUpdateEntityMutation: useUpdateOneObjectMutation, useUpdateEntityMutation: useUpdateOneObjectMutation,
hotkeyScope: InlineCellHotkeyScope.InlineCell, hotkeyScope: InlineCellHotkeyScope.InlineCell,

View File

@ -1,7 +1,6 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useComputeDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useComputeDefinitionsFromFieldMetadata'; import { useComputeDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useComputeDefinitionsFromFieldMetadata';
import { useObjectMainIdentifier } from '@/object-metadata/hooks/useObjectMainIdentifier';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useRecordTableContextMenuEntries } from '@/object-record/hooks/useRecordTableContextMenuEntries'; import { useRecordTableContextMenuEntries } from '@/object-record/hooks/useRecordTableContextMenuEntries';
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns'; import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
@ -17,13 +16,14 @@ export const RecordTableEffect = () => {
setObjectMetadataConfig, setObjectMetadataConfig,
} = useRecordTable(); } = useRecordTable();
const { objectMetadataItem } = useObjectMetadataItem({ const {
objectMetadataItem,
basePathToShowPage,
labelIdentifierFieldMetadataId,
} = useObjectMetadataItem({
objectNamePlural, objectNamePlural,
}); });
const { basePathToShowPage, labelIdentifierFieldMetadataId } =
useObjectMainIdentifier(objectMetadataItem);
const { columnDefinitions, filterDefinitions, sortDefinitions } = const { columnDefinitions, filterDefinitions, sortDefinitions } =
useComputeDefinitionsFromFieldMetadata(objectMetadataItem); useComputeDefinitionsFromFieldMetadata(objectMetadataItem);

View File

@ -90,11 +90,12 @@ export const SettingsObjectFieldPreview = ({
objectMetadataId, objectMetadataId,
}); });
const { defaultValue: relationDefaultValue } = useRelationFieldPreview({ const { defaultValue: relationDefaultValue, relationObjectMetadataItem } =
relationObjectMetadataId, useRelationFieldPreview({
skipDefaultValue: relationObjectMetadataId,
fieldMetadata.type !== FieldMetadataType.Relation || hasValue, skipDefaultValue:
}); fieldMetadata.type !== FieldMetadataType.Relation || hasValue,
});
const defaultValue = const defaultValue =
fieldMetadata.type === FieldMetadataType.Relation fieldMetadata.type === FieldMetadataType.Relation
@ -137,7 +138,7 @@ export const SettingsObjectFieldPreview = ({
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
entityId, entityId,
isMainIdentifier: false, isLabelIdentifier: false,
fieldDefinition: { fieldDefinition: {
type: parseFieldType(fieldMetadata.type), type: parseFieldType(fieldMetadata.type),
iconName: 'FieldIcon', iconName: 'FieldIcon',
@ -145,6 +146,8 @@ export const SettingsObjectFieldPreview = ({
label: fieldMetadata.label, label: fieldMetadata.label,
metadata: { metadata: {
fieldName, fieldName,
relationObjectMetadataNameSingular:
relationObjectMetadataItem?.nameSingular,
}, },
}, },
hotkeyScope: 'field-preview', hotkeyScope: 'field-preview',

View File

@ -26,7 +26,10 @@ export const useFieldPreview = ({
const fieldName = fieldMetadata.id const fieldName = fieldMetadata.id
? objectMetadataItem?.fields.find(({ id }) => id === fieldMetadata.id)?.name ? objectMetadataItem?.fields.find(({ id }) => id === fieldMetadata.id)?.name
: undefined; : undefined;
const value = fieldName ? firstRecord?.[fieldName] : undefined; const value =
fieldMetadata.type !== 'RELATION' && fieldName
? firstRecord?.[fieldName]
: undefined;
return { return {
entityId: firstRecord?.id || `${objectMetadataId}-no-records`, entityId: firstRecord?.id || `${objectMetadataId}-no-records`,

View File

@ -1,5 +1,6 @@
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings'; import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords'; import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
import { capitalize } from '~/utils/string/capitalize';
export const useRelationFieldPreview = ({ export const useRelationFieldPreview = ({
relationObjectMetadataId, relationObjectMetadataId,
@ -20,6 +21,9 @@ export const useRelationFieldPreview = ({
}); });
return { return {
defaultValue: relationObjects?.[0], relationObjectMetadataItem,
defaultValue: relationObjects?.[0] ?? {
name: capitalize(relationObjectMetadataItem?.nameSingular ?? ''),
},
}; };
}; };

View File

@ -37,7 +37,8 @@ export const RelationPicker = ({
}, [initialSearchFilter, setRelationPickerSearchFilter]); }, [initialSearchFilter, setRelationPickerSearchFilter]);
const { findManyQuery } = useObjectMetadataItem({ const { findManyQuery } = useObjectMetadataItem({
objectNameSingular: fieldDefinition.metadata.objectMetadataNameSingular, objectNameSingular:
fieldDefinition.metadata.relationObjectMetadataNameSingular,
}); });
const useFindManyQuery = (options: any) => useQuery(findManyQuery, options); const useFindManyQuery = (options: any) => useQuery(findManyQuery, options);
@ -49,8 +50,8 @@ export const RelationPicker = ({
filters: [ filters: [
{ {
fieldNames: fieldNames:
searchQuery?.filterFields?.( searchQuery?.computeFilterFields?.(
fieldDefinition.metadata.objectMetadataNameSingular, fieldDefinition.metadata.relationObjectMetadataNameSingular,
) ?? [], ) ?? [],
filter: relationPickerSearchFilter, filter: relationPickerSearchFilter,
}, },
@ -59,10 +60,10 @@ export const RelationPicker = ({
mappingFunction: (record: any) => mappingFunction: (record: any) =>
identifiersMapper?.( identifiersMapper?.(
record, record,
fieldDefinition.metadata.objectMetadataNameSingular, fieldDefinition.metadata.relationObjectMetadataNameSingular,
), ),
selectedIds: recordId ? [recordId] : [], selectedIds: recordId ? [recordId] : [],
objectNamePlural: fieldDefinition.metadata.objectMetadataNamePlural, objectNamePlural: fieldDefinition.metadata.relationObjectMetadataNamePlural,
}); });
const handleEntitySelected = async (selectedUser: any | null | undefined) => { const handleEntitySelected = async (selectedUser: any | null | undefined) => {

View File

@ -1,3 +1,3 @@
export type SearchQuery = { export type SearchQuery = {
filterFields: (relationPickerType: string) => string[]; computeFilterFields: (relationPickerType: string) => string[];
}; };

View File

@ -1,5 +1,6 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { ChipFieldDisplay } from '@/ui/object/field/meta-types/display/components/ChipFieldDisplay';
import { FullNameFieldDisplay } from '@/ui/object/field/meta-types/display/components/FullNameFieldDisplay'; import { FullNameFieldDisplay } from '@/ui/object/field/meta-types/display/components/FullNameFieldDisplay';
import { LinkFieldDisplay } from '@/ui/object/field/meta-types/display/components/LinkFieldDisplay'; import { LinkFieldDisplay } from '@/ui/object/field/meta-types/display/components/LinkFieldDisplay';
import { RelationFieldDisplay } from '@/ui/object/field/meta-types/display/components/RelationFieldDisplay'; import { RelationFieldDisplay } from '@/ui/object/field/meta-types/display/components/RelationFieldDisplay';
@ -24,8 +25,14 @@ import { isFieldRelation } from '../types/guards/isFieldRelation';
import { isFieldText } from '../types/guards/isFieldText'; import { isFieldText } from '../types/guards/isFieldText';
export const FieldDisplay = () => { export const FieldDisplay = () => {
const { fieldDefinition } = useContext(FieldContext); const { fieldDefinition, isLabelIdentifier } = useContext(FieldContext);
if (
isLabelIdentifier &&
(isFieldText(fieldDefinition) || isFieldFullName(fieldDefinition))
) {
return <ChipFieldDisplay />;
}
return ( return (
<> <>
{isFieldRelation(fieldDefinition) ? ( {isFieldRelation(fieldDefinition) ? (

View File

@ -10,12 +10,7 @@ export type GenericFieldContextType = {
entityId: string; entityId: string;
recoilScopeId?: string; recoilScopeId?: string;
hotkeyScope: string; hotkeyScope: string;
isMainIdentifier: boolean; isLabelIdentifier: boolean;
mainIdentifierMapper?: (record: any) => {
name: string;
avatarUrl?: string;
avatarType: string;
};
basePathToShowPage?: string; basePathToShowPage?: string;
}; };

View File

@ -18,7 +18,7 @@ export const FieldContextProvider = ({
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
entityId: entityId ?? '1', entityId: entityId ?? '1',
isMainIdentifier: false, isLabelIdentifier: false,
recoilScopeId: '1', recoilScopeId: '1',
hotkeyScope: 'hotkey-scope', hotkeyScope: 'hotkey-scope',
fieldDefinition, fieldDefinition,

View File

@ -1,10 +1,24 @@
import { EntityChip } from '@/ui/display/chip/components/EntityChip';
import { useChipField } from '@/ui/object/field/meta-types/hooks/useChipField';
export const ChipFieldDisplay = () => { export const ChipFieldDisplay = () => {
// const { avatarFieldValue, contentFieldValue, entityId } = useChipField(); const {
// return ( record,
// <ChipDisplay entityId,
// displayName={contentFieldValue} identifiersMapper,
// avatarUrlValue={avatarFieldValue} objectNameSingular,
// entityId={entityId} basePathToShowPage,
// /> } = useChipField();
// );
const identifiers = identifiersMapper?.(record, objectNameSingular ?? '');
return (
<EntityChip
name={identifiers?.name ?? ''}
avatarUrl={identifiers?.avatarUrl}
avatarType={identifiers?.avatarType}
entityId={entityId}
linkToEntity={basePathToShowPage + entityId}
/>
);
}; };

View File

@ -1,11 +0,0 @@
export const DoubleTextChipFieldDisplay = () => {
// const {} = useFullNameField();
// const content = [firstValue, secondValue].filter(Boolean).join(' ');
// return (
// <ChipDisplay
// displayName={content}
// avatarUrlValue={avatarUrl}
// entityId={entityId}
// />
// );
};

View File

@ -13,7 +13,7 @@ export const RelationFieldDisplay = () => {
const objectIdentifiers = identifiersMapper( const objectIdentifiers = identifiersMapper(
fieldValue, fieldValue,
fieldDefinition.metadata.objectMetadataNameSingular, fieldDefinition.metadata.relationObjectMetadataNameSingular,
); );
return ( return (

View File

@ -26,7 +26,7 @@ const meta: Meta = {
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
entityId: '', entityId: '',
isMainIdentifier: false, isLabelIdentifier: false,
fieldDefinition: { fieldDefinition: {
fieldMetadataId: 'date', fieldMetadataId: 'date',
label: 'Date', label: 'Date',

View File

@ -25,7 +25,7 @@ const meta: Meta = {
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
entityId: '', entityId: '',
isMainIdentifier: false, isLabelIdentifier: false,
fieldDefinition: { fieldDefinition: {
fieldMetadataId: 'email', fieldMetadataId: 'email',
label: 'Email', label: 'Email',

View File

@ -24,7 +24,7 @@ const meta: Meta = {
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
entityId: '', entityId: '',
isMainIdentifier: false, isLabelIdentifier: false,
fieldDefinition: { fieldDefinition: {
fieldMetadataId: 'number', fieldMetadataId: 'number',
label: 'Number', label: 'Number',

View File

@ -25,7 +25,7 @@ const meta: Meta = {
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
entityId: '', entityId: '',
isMainIdentifier: false, isLabelIdentifier: false,
fieldDefinition: { fieldDefinition: {
fieldMetadataId: 'phone', fieldMetadataId: 'phone',
label: 'Phone', label: 'Phone',

View File

@ -24,7 +24,7 @@ const meta: Meta = {
<FieldContext.Provider <FieldContext.Provider
value={{ value={{
entityId: '', entityId: '',
isMainIdentifier: false, isLabelIdentifier: false,
fieldDefinition: { fieldDefinition: {
fieldMetadataId: 'text', fieldMetadataId: 'text',
label: 'Text', label: 'Text',

View File

@ -0,0 +1,31 @@
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { useRelationPicker } from '@/ui/input/components/internal/relation-picker/hooks/useRelationPicker';
import { entityFieldsFamilyState } from '@/ui/object/field/states/entityFieldsFamilyState';
import { isFieldFullName } from '@/ui/object/field/types/guards/isFieldFullName';
import { isFieldText } from '@/ui/object/field/types/guards/isFieldText';
import { FieldContext } from '../../contexts/FieldContext';
export const useChipField = () => {
const { entityId, fieldDefinition, basePathToShowPage } =
useContext(FieldContext);
const objectNameSingular =
isFieldText(fieldDefinition) || isFieldFullName(fieldDefinition)
? fieldDefinition.metadata.objectMetadataNameSingular
: undefined;
const record = useRecoilValue<any | null>(entityFieldsFamilyState(entityId));
const { identifiersMapper } = useRelationPicker();
return {
basePathToShowPage,
entityId,
objectNameSingular,
record,
identifiersMapper,
};
};

View File

@ -9,6 +9,7 @@ export type FieldBooleanMetadata = {
}; };
export type FieldTextMetadata = { export type FieldTextMetadata = {
objectMetadataNameSingular: string;
placeHolder: string; placeHolder: string;
fieldName: string; fieldName: string;
}; };
@ -36,6 +37,7 @@ export type FieldCurrencyMetadata = {
}; };
export type FieldFullNameMetadata = { export type FieldFullNameMetadata = {
objectMetadataNameSingular: string;
placeHolder: string; placeHolder: string;
fieldName: string; fieldName: string;
}; };
@ -64,8 +66,8 @@ export type FieldRelationMetadata = {
fieldName: string; fieldName: string;
useEditButton?: boolean; useEditButton?: boolean;
relationType?: FieldDefinitionRelationType; relationType?: FieldDefinitionRelationType;
objectMetadataNameSingular: string; relationObjectMetadataNameSingular: string;
objectMetadataNamePlural: string; relationObjectMetadataNamePlural: string;
}; };
export type FieldMetadata = export type FieldMetadata =

View File

@ -60,7 +60,8 @@ export const RecordTableCell = ({ cellIndex }: { cellIndex: number }) => {
fieldDefinition: columnDefinition, fieldDefinition: columnDefinition,
useUpdateEntityMutation: () => [updateEntityMutation, {}], useUpdateEntityMutation: () => [updateEntityMutation, {}],
hotkeyScope: customHotkeyScope, hotkeyScope: customHotkeyScope,
isMainIdentifier: basePathToShowPage: objectMetadataConfig?.basePathToShowPage,
isLabelIdentifier:
columnDefinition.fieldMetadataId === columnDefinition.fieldMetadataId ===
objectMetadataConfig?.labelIdentifierFieldMetadataId, objectMetadataConfig?.labelIdentifierFieldMetadataId,
}} }}