Introduce main identifier to power RelationFieldDisplay (#2577)
* Introduce main identifier to power RelationFieldDisplay, FilterDrodown, TableFirstColumn * Apply to RelationPicker
This commit is contained in:
@ -10,6 +10,13 @@ export type GenericFieldContextType = {
|
||||
entityId: string;
|
||||
recoilScopeId?: string;
|
||||
hotkeyScope: string;
|
||||
isMainIdentifier: boolean;
|
||||
mainIdentifierMapper?: (record: any) => {
|
||||
name: string;
|
||||
avatarUrl?: string;
|
||||
avatarType: string;
|
||||
};
|
||||
basePathToShowPage?: string;
|
||||
};
|
||||
|
||||
export const FieldContext = createContext<GenericFieldContextType>(
|
||||
|
||||
@ -10,10 +10,8 @@ export const useIsFieldEmpty = () => {
|
||||
const isFieldEmpty = useRecoilValue(
|
||||
isEntityFieldEmptyFamilySelector({
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: fieldDefinition.fieldMetadataId,
|
||||
label: fieldDefinition.label,
|
||||
type: fieldDefinition.type,
|
||||
metadata: fieldDefinition.metadata,
|
||||
metadata: { ...fieldDefinition.metadata, mainIdentifierMapper: null },
|
||||
},
|
||||
entityId,
|
||||
}),
|
||||
|
||||
@ -18,6 +18,7 @@ export const FieldContextProvider = ({
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: entityId ?? '1',
|
||||
isMainIdentifier: false,
|
||||
recoilScopeId: '1',
|
||||
hotkeyScope: 'hotkey-scope',
|
||||
fieldDefinition,
|
||||
|
||||
@ -2,14 +2,12 @@ import { useChipField } from '../../hooks/useChipField';
|
||||
import { ChipDisplay } from '../content-display/components/ChipDisplay';
|
||||
|
||||
export const ChipFieldDisplay = () => {
|
||||
const { avatarFieldValue, contentFieldValue, entityType, entityId } =
|
||||
useChipField();
|
||||
const { avatarFieldValue, contentFieldValue, entityId } = useChipField();
|
||||
|
||||
return (
|
||||
<ChipDisplay
|
||||
displayName={contentFieldValue}
|
||||
avatarUrlValue={avatarFieldValue}
|
||||
entityType={entityType}
|
||||
entityId={entityId}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -2,7 +2,7 @@ import { useDoubleTextChipField } from '../../hooks/useDoubleTextChipField';
|
||||
import { ChipDisplay } from '../content-display/components/ChipDisplay';
|
||||
|
||||
export const DoubleTextChipFieldDisplay = () => {
|
||||
const { avatarUrl, firstValue, secondValue, entityType, entityId } =
|
||||
const { avatarUrl, firstValue, secondValue, entityId } =
|
||||
useDoubleTextChipField();
|
||||
|
||||
const content = [firstValue, secondValue].filter(Boolean).join(' ');
|
||||
@ -11,7 +11,6 @@ export const DoubleTextChipFieldDisplay = () => {
|
||||
<ChipDisplay
|
||||
displayName={content}
|
||||
avatarUrlValue={avatarUrl}
|
||||
entityType={entityType}
|
||||
entityId={entityId}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,22 +1,23 @@
|
||||
import { EntityChip } from '@/ui/display/chip/components/EntityChip';
|
||||
import { getEntityChipFromFieldMetadata } from '@/ui/object/field/meta-types/display/utils/getEntityChipFromFieldMetadata';
|
||||
|
||||
import { useRelationField } from '../../hooks/useRelationField';
|
||||
|
||||
export const RelationFieldDisplay = () => {
|
||||
const { fieldValue, fieldDefinition } = useRelationField();
|
||||
|
||||
const entityChipProps = getEntityChipFromFieldMetadata(
|
||||
fieldDefinition,
|
||||
fieldValue,
|
||||
);
|
||||
if (!fieldValue || !fieldDefinition) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const mainIdentifierMapped =
|
||||
fieldDefinition.metadata.mainIdentifierMapper(fieldValue);
|
||||
|
||||
return (
|
||||
<EntityChip
|
||||
entityId={entityChipProps.entityId}
|
||||
name={entityChipProps.name}
|
||||
pictureUrl={entityChipProps.pictureUrl}
|
||||
avatarType={entityChipProps.avatarType}
|
||||
entityId={fieldValue.id}
|
||||
name={mainIdentifierMapped.name}
|
||||
avatarUrl={mainIdentifierMapped.avatarUrl}
|
||||
avatarType={mainIdentifierMapped.avatarType}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -26,6 +26,7 @@ const meta: Meta = {
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
isMainIdentifier: false,
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'date',
|
||||
label: 'Date',
|
||||
|
||||
@ -25,6 +25,7 @@ const meta: Meta = {
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
isMainIdentifier: false,
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'email',
|
||||
label: 'Email',
|
||||
|
||||
@ -25,6 +25,7 @@ const meta: Meta = {
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
isMainIdentifier: false,
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'enum',
|
||||
label: 'Enum',
|
||||
|
||||
@ -24,6 +24,7 @@ const meta: Meta = {
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
isMainIdentifier: false,
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'money',
|
||||
label: 'Money',
|
||||
|
||||
@ -24,6 +24,7 @@ const meta: Meta = {
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
isMainIdentifier: false,
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'number',
|
||||
label: 'Number',
|
||||
|
||||
@ -25,6 +25,7 @@ const meta: Meta = {
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
isMainIdentifier: false,
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'phone',
|
||||
label: 'Phone',
|
||||
|
||||
@ -24,6 +24,7 @@ const meta: Meta = {
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
isMainIdentifier: false,
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'text',
|
||||
label: 'Text',
|
||||
|
||||
@ -25,6 +25,7 @@ const meta: Meta = {
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
isMainIdentifier: false,
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'URL',
|
||||
label: 'URL',
|
||||
|
||||
@ -1,45 +1,34 @@
|
||||
import { CompanyChip } from '@/companies/components/CompanyChip';
|
||||
import { PersonChip } from '@/people/components/PersonChip';
|
||||
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||
import { getLogoUrlFromDomainName } from '~/utils';
|
||||
import { logError } from '~/utils/logError';
|
||||
|
||||
type ChipDisplayProps = {
|
||||
entityType: Entity;
|
||||
displayName: string;
|
||||
entityId: string | null;
|
||||
avatarUrlValue?: string;
|
||||
};
|
||||
|
||||
export const ChipDisplay = ({
|
||||
entityType,
|
||||
displayName,
|
||||
entityId,
|
||||
avatarUrlValue,
|
||||
}: ChipDisplayProps) => {
|
||||
switch (entityType) {
|
||||
case Entity.Company: {
|
||||
return (
|
||||
<CompanyChip
|
||||
id={entityId ?? ''}
|
||||
name={displayName}
|
||||
pictureUrl={getLogoUrlFromDomainName(avatarUrlValue)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case Entity.Person: {
|
||||
return (
|
||||
<PersonChip
|
||||
id={entityId ?? ''}
|
||||
name={displayName}
|
||||
pictureUrl={avatarUrlValue}
|
||||
/>
|
||||
);
|
||||
}
|
||||
switch (true) {
|
||||
// case Entity.Company: {
|
||||
// return (
|
||||
// <CompanyChip
|
||||
// id={entityId ?? ''}
|
||||
// name={displayName}
|
||||
// avatarUrl={getLogoUrlFromDomainName(avatarUrlValue)}
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
// case Entity.Person: {
|
||||
// return (
|
||||
// <PersonChip
|
||||
// id={entityId ?? ''}
|
||||
// name={displayName}
|
||||
// avatarUrl={avatarUrlValue}
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
default:
|
||||
logError(
|
||||
`Unknown relation type: "${entityType}" in DoubleTextChipDisplay`,
|
||||
);
|
||||
return <> </>;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
import { EntityChipProps } from '@/ui/display/chip/components/EntityChip';
|
||||
import { FieldDefinition } from '@/ui/object/field/types/FieldDefinition';
|
||||
import { FieldRelationMetadata } from '@/ui/object/field/types/FieldMetadata';
|
||||
import { getLogoUrlFromDomainName } from '~/utils';
|
||||
|
||||
export const getEntityChipFromFieldMetadata = (
|
||||
fieldDefinition: FieldDefinition<FieldRelationMetadata>,
|
||||
fieldValue: any,
|
||||
) => {
|
||||
const { entityChipDisplayMapper } = fieldDefinition;
|
||||
const { fieldName } = fieldDefinition.metadata;
|
||||
|
||||
const defaultChipValue: Pick<
|
||||
EntityChipProps,
|
||||
'name' | 'pictureUrl' | 'avatarType' | 'entityId'
|
||||
> = {
|
||||
name: '',
|
||||
pictureUrl: '',
|
||||
avatarType: 'rounded',
|
||||
entityId: fieldValue?.id,
|
||||
};
|
||||
|
||||
if (['accountOwner', 'person'].includes(fieldName) && fieldValue) {
|
||||
return {
|
||||
...defaultChipValue,
|
||||
name: `${fieldValue.firstName} ${fieldValue.lastName}`,
|
||||
};
|
||||
}
|
||||
|
||||
if (fieldName === 'company' && fieldValue) {
|
||||
return {
|
||||
...defaultChipValue,
|
||||
name: fieldValue.name,
|
||||
pictureUrl: getLogoUrlFromDomainName(fieldValue.domainName),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...defaultChipValue,
|
||||
...entityChipDisplayMapper?.(fieldValue),
|
||||
};
|
||||
};
|
||||
@ -29,8 +29,6 @@ export const useChipField = () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const entityType = fieldDefinition.metadata.relationType;
|
||||
|
||||
const fieldInitialValue = useFieldInitialValue();
|
||||
|
||||
const initialContentValue = fieldInitialValue?.isEmpty
|
||||
@ -51,7 +49,6 @@ export const useChipField = () => {
|
||||
avatarFieldValue,
|
||||
initialAvatarValue,
|
||||
setAvatarFieldValue,
|
||||
entityType,
|
||||
entityId,
|
||||
hotkeyScope,
|
||||
};
|
||||
|
||||
@ -39,8 +39,6 @@ export const useDoubleTextChipField = () => {
|
||||
|
||||
const fullValue = [firstValue, secondValue].filter(Boolean).join(' ');
|
||||
|
||||
const entityType = fieldDefinition.metadata.entityType;
|
||||
|
||||
const fieldInitialValue = useFieldInitialValue();
|
||||
|
||||
const initialFirstValue = fieldInitialValue?.isEmpty
|
||||
@ -68,7 +66,6 @@ export const useDoubleTextChipField = () => {
|
||||
firstValue,
|
||||
setFirstValue,
|
||||
fullValue,
|
||||
entityType,
|
||||
entityId,
|
||||
hotkeyScope,
|
||||
initialAvatarUrl,
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
import { useEffect } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { CompanyPicker } from '@/companies/components/CompanyPicker';
|
||||
import { PeoplePicker } from '@/people/components/PeoplePicker';
|
||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||
import { WorkspaceMemberPicker } from '@/workspace-member/components/WorkspaceMemberPicker';
|
||||
import { RelationPicker } from '@/ui/object/field/meta-types/input/components/internal/RelationPicker';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useRelationField } from '../../hooks/useRelationField';
|
||||
@ -32,14 +30,21 @@ export const RelationFieldInput = ({
|
||||
const persistField = usePersistField();
|
||||
|
||||
const handleSubmit = (newEntity: EntityForSelect | null) => {
|
||||
onSubmit?.(() => persistField(newEntity?.originalEntity ?? null));
|
||||
onSubmit?.(() => persistField(newEntity?.record ?? null));
|
||||
};
|
||||
|
||||
useEffect(() => {}, [initialSearchValue]);
|
||||
|
||||
return (
|
||||
<StyledRelationPickerContainer>
|
||||
{fieldDefinition.metadata.fieldName === 'person' ? (
|
||||
<RelationPicker
|
||||
fieldDefinition={fieldDefinition}
|
||||
recordId={initialValue?.id ?? ''}
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={onCancel}
|
||||
initialSearchFilter={initialSearchValue}
|
||||
/>
|
||||
{/* {fieldDefinition.metadata.fieldName === 'person' ? (
|
||||
<PeoplePicker
|
||||
personId={initialValue?.id ?? ''}
|
||||
companyId={initialValue?.companyId ?? ''}
|
||||
@ -47,13 +52,6 @@ export const RelationFieldInput = ({
|
||||
onCancel={onCancel}
|
||||
initialSearchFilter={initialSearchValue}
|
||||
/>
|
||||
) : fieldDefinition.metadata.fieldName === 'accountOwner' ? (
|
||||
<WorkspaceMemberPicker
|
||||
userId={initialValue?.id ?? ''}
|
||||
onSubmit={handleSubmit}
|
||||
onCancel={onCancel}
|
||||
initialSearchFilter={initialSearchValue}
|
||||
/>
|
||||
) : fieldDefinition.metadata.fieldName === 'company' ? (
|
||||
<CompanyPicker
|
||||
companyId={initialValue?.id ?? ''}
|
||||
@ -61,7 +59,7 @@ export const RelationFieldInput = ({
|
||||
onCancel={onCancel}
|
||||
initialSearchFilter={initialSearchValue}
|
||||
/>
|
||||
) : null}
|
||||
) : null} */}
|
||||
</StyledRelationPickerContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,7 +3,6 @@ import { expect, jest } from '@storybook/jest';
|
||||
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
|
||||
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
|
||||
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||
@ -52,7 +51,6 @@ const ChipFieldInputWithContext = ({
|
||||
contentFieldName: 'name',
|
||||
urlFieldName: 'xURL',
|
||||
placeHolder: 'X URL',
|
||||
relationType: Entity.Person,
|
||||
},
|
||||
}}
|
||||
entityId={entityId}
|
||||
|
||||
@ -3,7 +3,6 @@ import { expect, jest } from '@storybook/jest';
|
||||
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
|
||||
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
|
||||
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||
@ -67,7 +66,7 @@ const DoubleTextChipFieldInputWithContext = ({
|
||||
secondValueFieldName: 'Second-text',
|
||||
secondValuePlaceholder: 'Second-text',
|
||||
avatarUrlFieldName: 'avatarUrl',
|
||||
entityType: Entity.Person,
|
||||
fieldName: '',
|
||||
},
|
||||
}}
|
||||
entityId={entityId}
|
||||
|
||||
@ -3,7 +3,6 @@ import { expect, jest } from '@storybook/jest';
|
||||
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
|
||||
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
@ -52,7 +51,6 @@ const RelationFieldInputWithContext = ({
|
||||
iconName: 'IconLink',
|
||||
metadata: {
|
||||
fieldName: 'Relation',
|
||||
relationType: Entity.Person,
|
||||
},
|
||||
}}
|
||||
entityId={entityId}
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
|
||||
import { useFindOneObjectMetadataItem } from '@/object-metadata/hooks/useFindOneObjectMetadataItem';
|
||||
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||
import { IconUserCircle } from '@/ui/display/icon';
|
||||
import { SingleEntitySelect } from '@/ui/input/relation-picker/components/SingleEntitySelect';
|
||||
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||
import { FieldDefinition } from '@/ui/object/field/types/FieldDefinition';
|
||||
import { FieldRelationMetadata } from '@/ui/object/field/types/FieldMetadata';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
export type RelationPickerProps = {
|
||||
recordId: string;
|
||||
onSubmit: (newUser: EntityForSelect | null) => void;
|
||||
onCancel?: () => void;
|
||||
width?: number;
|
||||
initialSearchFilter?: string | null;
|
||||
fieldDefinition: FieldDefinition<FieldRelationMetadata>;
|
||||
};
|
||||
|
||||
export const RelationPicker = ({
|
||||
recordId,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
width,
|
||||
initialSearchFilter,
|
||||
fieldDefinition,
|
||||
}: RelationPickerProps) => {
|
||||
const [relationPickerSearchFilter, setRelationPickerSearchFilter] =
|
||||
useRecoilScopedState(relationPickerSearchFilterScopedState);
|
||||
|
||||
useEffect(() => {
|
||||
setRelationPickerSearchFilter(initialSearchFilter ?? '');
|
||||
}, [initialSearchFilter, setRelationPickerSearchFilter]);
|
||||
|
||||
const { findManyQuery } = useFindOneObjectMetadataItem({
|
||||
objectNameSingular: fieldDefinition.metadata.objectMetadataNameSingular,
|
||||
});
|
||||
|
||||
const useFindManyQuery = (options: any) => useQuery(findManyQuery, options);
|
||||
|
||||
const workspaceMembers = useFilteredSearchEntityQuery({
|
||||
queryHook: useFindManyQuery,
|
||||
filters: [
|
||||
{
|
||||
fieldNames: fieldDefinition.metadata.searchFields,
|
||||
filter: relationPickerSearchFilter,
|
||||
},
|
||||
],
|
||||
orderByField: 'createdAt',
|
||||
mappingFunction: fieldDefinition.metadata.mainIdentifierMapper,
|
||||
selectedIds: recordId ? [recordId] : [],
|
||||
objectNamePlural: fieldDefinition.metadata.objectMetadataNamePlural,
|
||||
});
|
||||
|
||||
const handleEntitySelected = async (selectedUser: any | null | undefined) => {
|
||||
onSubmit(selectedUser ?? null);
|
||||
};
|
||||
|
||||
return (
|
||||
<SingleEntitySelect
|
||||
EmptyIcon={IconUserCircle}
|
||||
emptyLabel="No Owner"
|
||||
entitiesToSelect={workspaceMembers.entitiesToSelect}
|
||||
loading={workspaceMembers.loading}
|
||||
onCancel={onCancel}
|
||||
onEntitySelected={handleEntitySelected}
|
||||
selectedEntity={workspaceMembers.selectedEntities[0]}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -34,10 +34,9 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
|
||||
fieldDefinition,
|
||||
entityId,
|
||||
}: {
|
||||
fieldDefinition: Pick<
|
||||
FieldDefinition<FieldMetadata>,
|
||||
'type' | 'metadata' | 'fieldMetadataId' | 'label'
|
||||
>;
|
||||
fieldDefinition: Pick<FieldDefinition<FieldMetadata>, 'type'> & {
|
||||
metadata: Omit<FieldMetadata, 'mainIdentifierMapper'>;
|
||||
};
|
||||
entityId: string;
|
||||
}) => {
|
||||
return ({ get }) => {
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import { AvatarType } from '@/users/components/Avatar';
|
||||
|
||||
import { FieldMetadata } from './FieldMetadata';
|
||||
import { FieldType } from './FieldType';
|
||||
|
||||
@ -15,12 +13,5 @@ export type FieldDefinition<T extends FieldMetadata> = {
|
||||
iconName: string;
|
||||
type: FieldType;
|
||||
metadata: T;
|
||||
basePathToShowPage?: string;
|
||||
infoTooltipContent?: string;
|
||||
entityChipDisplayMapper?: (dataObject: any) => {
|
||||
name: string;
|
||||
pictureUrl?: string;
|
||||
avatarType: AvatarType;
|
||||
};
|
||||
relationType?: FieldDefinitionRelationType;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
|
||||
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||
import { MainIdentifierMapper } from '@/ui/object/field/types/MainIdentifierMapper';
|
||||
import { ThemeColor } from '@/ui/theme/constants/colors';
|
||||
|
||||
export type FieldUuidMetadata = {
|
||||
@ -58,14 +58,23 @@ export type FieldEmailMetadata = {
|
||||
placeHolder: string;
|
||||
};
|
||||
|
||||
export type FieldDefinitionRelationType =
|
||||
| 'FROM_MANY_OBJECTS'
|
||||
| 'FROM_ONE_OBJECT'
|
||||
| 'TO_MANY_OBJECTS'
|
||||
| 'TO_ONE_OBJECT';
|
||||
|
||||
export type FieldRelationMetadata = {
|
||||
relationType: Entity;
|
||||
fieldName: string;
|
||||
useEditButton?: boolean;
|
||||
relationType?: FieldDefinitionRelationType;
|
||||
mainIdentifierMapper: MainIdentifierMapper;
|
||||
searchFields: string[];
|
||||
objectMetadataNameSingular: string;
|
||||
objectMetadataNamePlural: string;
|
||||
};
|
||||
|
||||
export type FieldChipMetadata = {
|
||||
relationType: Entity;
|
||||
contentFieldName: string;
|
||||
urlFieldName: string;
|
||||
placeHolder: string;
|
||||
@ -84,7 +93,6 @@ export type FieldDoubleTextChipMetadata = {
|
||||
secondValueFieldName: string;
|
||||
secondValuePlaceholder: string;
|
||||
avatarUrlFieldName: string;
|
||||
entityType: Entity;
|
||||
};
|
||||
|
||||
export type FieldProbabilityMetadata = {
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
import { AvatarType } from '@/users/components/Avatar';
|
||||
|
||||
export type MainIdentifierMapper = (record: any) => {
|
||||
id: string;
|
||||
name: string;
|
||||
avatarUrl?: string;
|
||||
avatarType: AvatarType;
|
||||
record: any;
|
||||
};
|
||||
@ -0,0 +1,14 @@
|
||||
import { MainIdentifierMapper } from '@/ui/object/field/types/MainIdentifierMapper';
|
||||
|
||||
export type FieldDefinitionRelationType =
|
||||
| 'FROM_MANY_OBJECTS'
|
||||
| 'FROM_ONE_OBJECT'
|
||||
| 'TO_MANY_OBJECTS'
|
||||
| 'TO_ONE_OBJECT';
|
||||
|
||||
export type RelationFieldConfig = {
|
||||
relationType?: FieldDefinitionRelationType;
|
||||
mainIdentifierMapper: MainIdentifierMapper;
|
||||
searchFields: string[];
|
||||
objectMetadataNameSingular: string;
|
||||
};
|
||||
@ -16,7 +16,7 @@ export const GenericEntityFilterChip = ({
|
||||
entityId={filter.value}
|
||||
name={filter.displayValue}
|
||||
avatarType="rounded"
|
||||
pictureUrl={filter.displayAvatarUrl}
|
||||
avatarUrl={filter.displayAvatarUrl}
|
||||
LeftIcon={Icon}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
|
||||
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
|
||||
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
|
||||
import { useRecordTableScopedStates } from '@/ui/object/record-table/hooks/internal/useRecordTableScopedStates';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
|
||||
import { FieldContext } from '../../field/contexts/FieldContext';
|
||||
@ -20,6 +21,9 @@ export const RecordTableCell = ({ cellIndex }: { cellIndex: number }) => {
|
||||
const setContextMenuPosition = useSetRecoilState(contextMenuPositionState);
|
||||
const setContextMenuOpenState = useSetRecoilState(contextMenuIsOpenState);
|
||||
const currentRowId = useContext(RowIdContext);
|
||||
const { objectMetadataConfigState } = useRecordTableScopedStates();
|
||||
|
||||
const objectMetadataConfig = useRecoilValue(objectMetadataConfigState);
|
||||
|
||||
const { setCurrentRowSelected } = useCurrentRowSelected();
|
||||
|
||||
@ -56,6 +60,10 @@ export const RecordTableCell = ({ cellIndex }: { cellIndex: number }) => {
|
||||
fieldDefinition: columnDefinition,
|
||||
useUpdateEntityMutation: () => [updateEntityMutation, {}],
|
||||
hotkeyScope: customHotkeyScope,
|
||||
isMainIdentifier:
|
||||
columnDefinition.fieldMetadataId ===
|
||||
objectMetadataConfig?.mainIdentifierFieldMetadataId,
|
||||
mainIdentifierMapper: objectMetadataConfig?.mainIdentifierMapper,
|
||||
}}
|
||||
>
|
||||
<TableCell customHotkeyScope={{ scope: customHotkeyScope }} />
|
||||
|
||||
@ -18,6 +18,7 @@ export const useRecordTableScopedStates = (args?: {
|
||||
tableFiltersState,
|
||||
tableSortsState,
|
||||
tableColumnsState,
|
||||
objectMetadataConfigState,
|
||||
tableColumnsByKeySelector,
|
||||
hiddenTableColumnsSelector,
|
||||
visibleTableColumnsSelector,
|
||||
@ -33,6 +34,7 @@ export const useRecordTableScopedStates = (args?: {
|
||||
tableFiltersState,
|
||||
tableSortsState,
|
||||
tableColumnsState,
|
||||
objectMetadataConfigState,
|
||||
tableColumnsByKeySelector,
|
||||
hiddenTableColumnsSelector,
|
||||
visibleTableColumnsSelector,
|
||||
|
||||
@ -43,6 +43,7 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
||||
tableFiltersState,
|
||||
tableSortsState,
|
||||
tableColumnsState,
|
||||
objectMetadataConfigState,
|
||||
onEntityCountChangeState,
|
||||
} = useRecordTableScopedStates({
|
||||
customRecordTableScopeId: scopeId,
|
||||
@ -54,6 +55,7 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
||||
|
||||
const setOnEntityCountChange = useSetRecoilState(onEntityCountChangeState);
|
||||
const setTableFilters = useSetRecoilState(tableFiltersState);
|
||||
const setObjectMetadataConfig = useSetRecoilState(objectMetadataConfigState);
|
||||
|
||||
const setTableSorts = useSetRecoilState(tableSortsState);
|
||||
|
||||
@ -301,6 +303,7 @@ export const useRecordTable = (props?: useRecordTableProps) => {
|
||||
setAvailableTableColumns,
|
||||
setTableFilters,
|
||||
setTableSorts,
|
||||
setObjectMetadataConfig,
|
||||
setOnEntityCountChange,
|
||||
setRecordTableData,
|
||||
setTableColumns,
|
||||
|
||||
@ -37,7 +37,8 @@ export const useTableCell = () => {
|
||||
|
||||
const isEmpty = useIsFieldEmpty();
|
||||
|
||||
const { entityId, fieldDefinition } = useContext(FieldContext);
|
||||
const { entityId, fieldDefinition, basePathToShowPage } =
|
||||
useContext(FieldContext);
|
||||
|
||||
const [, setFieldInitialValue] = useRecoilState(
|
||||
entityFieldInitialValueFamilyState({
|
||||
@ -47,8 +48,8 @@ export const useTableCell = () => {
|
||||
);
|
||||
|
||||
const openTableCell = (options?: { initialValue?: FieldInitialValue }) => {
|
||||
if (isFirstColumnCell && !isEmpty && fieldDefinition.basePathToShowPage) {
|
||||
navigate(`${fieldDefinition.basePathToShowPage}${entityId}`);
|
||||
if (isFirstColumnCell && !isEmpty && basePathToShowPage) {
|
||||
navigate(`${basePathToShowPage}${entityId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import { ObjectMetadataConfig } from '@/ui/object/record-table/types/ObjectMetadataConfig';
|
||||
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||
|
||||
export const objectMetadataConfigScopedState =
|
||||
createScopedState<ObjectMetadataConfig | null>({
|
||||
key: 'objectMetadataConfigScopedState',
|
||||
defaultValue: null,
|
||||
});
|
||||
@ -0,0 +1,11 @@
|
||||
import { AvatarType } from '@/users/components/Avatar';
|
||||
|
||||
export type ObjectMetadataConfig = {
|
||||
mainIdentifierFieldMetadataId: string;
|
||||
mainIdentifierMapper: (record: any) => {
|
||||
name: string;
|
||||
avatarUrl?: string;
|
||||
avatarType: AvatarType;
|
||||
};
|
||||
basePathToShowPage: string;
|
||||
};
|
||||
@ -1,3 +1,4 @@
|
||||
import { objectMetadataConfigScopedState } from '@/ui/object/record-table/states/objectMetadataConfigScopedState';
|
||||
import { getScopedState } from '@/ui/utilities/recoil-scope/utils/getScopedState';
|
||||
|
||||
import { availableTableColumnsScopedState } from '../states/availableTableColumnsScopedState';
|
||||
@ -36,6 +37,11 @@ export const getRecordTableScopedStates = ({
|
||||
recordTableScopeId,
|
||||
);
|
||||
|
||||
const objectMetadataConfigState = getScopedState(
|
||||
objectMetadataConfigScopedState,
|
||||
recordTableScopeId,
|
||||
);
|
||||
|
||||
const tableColumnsByKeySelector =
|
||||
tableColumnsByKeyScopedSelector(recordTableScopeId);
|
||||
|
||||
@ -60,6 +66,7 @@ export const getRecordTableScopedStates = ({
|
||||
tableFiltersState,
|
||||
tableSortsState,
|
||||
tableColumnsState,
|
||||
objectMetadataConfigState,
|
||||
tableColumnsByKeySelector,
|
||||
hiddenTableColumnsSelector,
|
||||
visibleTableColumnsSelector,
|
||||
|
||||
Reference in New Issue
Block a user