mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-18 17:12:53 +03:00
Added generic relation cell (#969)
* Added generic relation cell * Deactivated debug * Added default warning * Put back display component * Removed unused types
This commit is contained in:
parent
3b796ee68c
commit
f4b8a3decb
60
front/src/modules/companies/components/CompanyPickerCell.tsx
Normal file
60
front/src/modules/companies/components/CompanyPickerCell.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
import { useFilteredSearchCompanyQuery } from '@/companies/queries';
|
||||
import { useSetHotkeyScope } from '@/ui/hotkey/hooks/useSetHotkeyScope';
|
||||
import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { SingleEntitySelect } from '@/ui/relation-picker/components/SingleEntitySelect';
|
||||
import { relationPickerSearchFilterScopedState } from '@/ui/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { isCreateModeScopedState } from '@/ui/table/editable-cell/states/isCreateModeScopedState';
|
||||
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
|
||||
|
||||
import { EntityForSelect } from '../../ui/relation-picker/types/EntityForSelect';
|
||||
|
||||
export type OwnProps = {
|
||||
companyId: string | null;
|
||||
onSubmit: (newCompany: EntityForSelect | null) => void;
|
||||
onCancel?: () => void;
|
||||
createModeEnabled?: boolean;
|
||||
};
|
||||
|
||||
export function CompanyPickerCell({
|
||||
companyId,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
createModeEnabled,
|
||||
}: OwnProps) {
|
||||
const [, setIsCreating] = useRecoilScopedState(isCreateModeScopedState);
|
||||
|
||||
const [searchFilter] = useRecoilScopedState(
|
||||
relationPickerSearchFilterScopedState,
|
||||
);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const companies = useFilteredSearchCompanyQuery({
|
||||
searchFilter,
|
||||
selectedIds: [companyId ?? ''],
|
||||
});
|
||||
|
||||
async function handleEntitySelected(
|
||||
entity: EntityForSelect | null | undefined,
|
||||
) {
|
||||
onSubmit(entity ?? null);
|
||||
}
|
||||
|
||||
function handleCreate() {
|
||||
setIsCreating(true);
|
||||
setHotkeyScope(TableHotkeyScope.CellDoubleTextInput);
|
||||
}
|
||||
|
||||
return (
|
||||
<SingleEntitySelect
|
||||
onCreate={createModeEnabled ? handleCreate : undefined}
|
||||
onCancel={onCancel}
|
||||
onEntitySelected={handleEntitySelected}
|
||||
entities={{
|
||||
entitiesToSelect: companies.entitiesToSelect,
|
||||
selectedEntity: companies.selectedEntities[0],
|
||||
loading: companies.loading,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useFilteredSearchCompanyQuery } from '@/companies/queries';
|
||||
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
|
||||
import { useSetHotkeyScope } from '@/ui/hotkey/hooks/useSetHotkeyScope';
|
||||
import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { SingleEntitySelect } from '@/ui/relation-picker/components/SingleEntitySelect';
|
||||
import { relationPickerSearchFilterScopedState } from '@/ui/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { RelationPickerHotkeyScope } from '@/ui/relation-picker/types/RelationPickerHotkeyScope';
|
||||
import { useEditableCell } from '@/ui/table/editable-cell/hooks/useEditableCell';
|
||||
import { isCreateModeScopedState } from '@/ui/table/editable-cell/states/isCreateModeScopedState';
|
||||
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
|
||||
@ -63,13 +59,6 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
|
||||
addToScopeStack(TableHotkeyScope.CellDoubleTextInput);
|
||||
}
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.Escape,
|
||||
() => closeEditableCell(),
|
||||
RelationPickerHotkeyScope.RelationPicker,
|
||||
[closeEditableCell],
|
||||
);
|
||||
|
||||
return (
|
||||
<SingleEntitySelect
|
||||
onCreate={handleCreate}
|
||||
|
55
front/src/modules/people/components/PeoplePicker.tsx
Normal file
55
front/src/modules/people/components/PeoplePicker.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||
import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { SingleEntitySelect } from '@/ui/relation-picker/components/SingleEntitySelect';
|
||||
import { relationPickerSearchFilterScopedState } from '@/ui/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { EntityForSelect } from '@/ui/relation-picker/types/EntityForSelect';
|
||||
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
|
||||
import { useSearchPeopleQuery } from '~/generated/graphql';
|
||||
|
||||
export type OwnProps = {
|
||||
personId: string;
|
||||
onSubmit: (newPersonId: string | null) => void;
|
||||
onCancel?: () => void;
|
||||
};
|
||||
|
||||
type PersonForSelect = EntityForSelect & {
|
||||
entityType: Entity.Person;
|
||||
};
|
||||
|
||||
export function PeoplePicker({ personId, onSubmit, onCancel }: OwnProps) {
|
||||
const [searchFilter] = useRecoilScopedState(
|
||||
relationPickerSearchFilterScopedState,
|
||||
);
|
||||
|
||||
const people = useFilteredSearchEntityQuery({
|
||||
queryHook: useSearchPeopleQuery,
|
||||
selectedIds: [personId],
|
||||
searchFilter: searchFilter,
|
||||
mappingFunction: (person) => ({
|
||||
entityType: Entity.Person,
|
||||
id: person.id,
|
||||
name: person.firstName + ' ' + person.lastName,
|
||||
avatarType: 'rounded',
|
||||
}),
|
||||
orderByField: 'firstName',
|
||||
searchOnFields: ['firstName', 'lastName'],
|
||||
});
|
||||
|
||||
async function handleEntitySelected(
|
||||
selectedPerson: PersonForSelect | null | undefined,
|
||||
) {
|
||||
onSubmit(selectedPerson?.id ?? null);
|
||||
}
|
||||
|
||||
return (
|
||||
<SingleEntitySelect
|
||||
onEntitySelected={handleEntitySelected}
|
||||
onCancel={onCancel}
|
||||
entities={{
|
||||
loading: people.loading,
|
||||
entitiesToSelect: people.entitiesToSelect,
|
||||
selectedEntity: people.selectedEntities[0],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -1,5 +1,10 @@
|
||||
import { IconBriefcase, IconMap } from '@tabler/icons-react';
|
||||
import {
|
||||
IconBriefcase,
|
||||
IconBuildingSkyscraper,
|
||||
IconMap,
|
||||
} from '@tabler/icons-react';
|
||||
|
||||
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
|
||||
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
|
||||
|
||||
export const peopleFieldMetadataArray: EntityFieldMetadata[] = [
|
||||
@ -17,4 +22,12 @@ export const peopleFieldMetadataArray: EntityFieldMetadata[] = [
|
||||
columnSize: 150,
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
fieldName: 'company',
|
||||
label: 'Company',
|
||||
icon: <IconBuildingSkyscraper size={16} />,
|
||||
columnSize: 150,
|
||||
type: 'relation',
|
||||
relationType: Entity.Company,
|
||||
},
|
||||
];
|
||||
|
65
front/src/modules/people/hooks/useUpdateEntityField.ts
Normal file
65
front/src/modules/people/hooks/useUpdateEntityField.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { EntityForSelect } from '@/ui/relation-picker/types/EntityForSelect';
|
||||
import { entityFieldMetadataArrayState } from '@/ui/table/states/entityFieldMetadataArrayState';
|
||||
import { EntityUpdateMutationHookContext } from '@/ui/table/states/EntityUpdateMutationHookContext';
|
||||
|
||||
export function useUpdateEntityField() {
|
||||
const useUpdateEntityMutation = useContext(EntityUpdateMutationHookContext);
|
||||
|
||||
const [updateEntity] = useUpdateEntityMutation();
|
||||
|
||||
const entityFieldMetadataArray = useRecoilValue(
|
||||
entityFieldMetadataArrayState,
|
||||
);
|
||||
|
||||
return function updatePeopleField(
|
||||
currentEntityId: string,
|
||||
fieldName: string,
|
||||
newFieldValue: unknown,
|
||||
) {
|
||||
const fieldMetadata = entityFieldMetadataArray.find(
|
||||
(metadata) => metadata.fieldName === fieldName,
|
||||
);
|
||||
|
||||
if (!fieldMetadata) {
|
||||
throw new Error(`Field metadata not found for field ${fieldName}`);
|
||||
}
|
||||
|
||||
if (fieldMetadata.type === 'relation') {
|
||||
const newSelectedEntity = newFieldValue as EntityForSelect | null;
|
||||
|
||||
if (!newSelectedEntity) {
|
||||
updateEntity({
|
||||
variables: {
|
||||
where: { id: currentEntityId },
|
||||
data: {
|
||||
[fieldName]: {
|
||||
disconnect: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
updateEntity({
|
||||
variables: {
|
||||
where: { id: currentEntityId },
|
||||
data: {
|
||||
[fieldName]: {
|
||||
connect: { id: newSelectedEntity.id },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
updateEntity({
|
||||
variables: {
|
||||
where: { id: currentEntityId },
|
||||
data: { [fieldName]: newFieldValue },
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { useUpdateOnePersonMutation } from '~/generated/graphql';
|
||||
|
||||
export function useUpdatePeopleField() {
|
||||
const [updatePeople] = useUpdateOnePersonMutation();
|
||||
|
||||
return function updatePeopleField(
|
||||
peopleId: string,
|
||||
fieldName: string,
|
||||
fieldValue: unknown,
|
||||
) {
|
||||
updatePeople({
|
||||
variables: {
|
||||
where: { id: peopleId },
|
||||
data: { [fieldName]: fieldValue },
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
@ -3,7 +3,6 @@ import { useCallback, useMemo, useState } from 'react';
|
||||
import { defaultOrderBy } from '@/companies/queries';
|
||||
import { GenericEntityTableData } from '@/people/components/GenericEntityTableData';
|
||||
import { peopleFieldMetadataArray } from '@/people/constants/peopleFieldMetadataArray';
|
||||
import { useUpdatePeopleField } from '@/people/hooks/useUpdatePeopleField';
|
||||
import { PeopleSelectedSortType } from '@/people/queries';
|
||||
import { reduceSortsToOrderBy } from '@/ui/filter-n-sort/helpers';
|
||||
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
||||
@ -15,6 +14,7 @@ import { TableContext } from '@/ui/table/states/TableContext';
|
||||
import {
|
||||
PersonOrderByWithRelationInput,
|
||||
useGetPeopleQuery,
|
||||
useUpdateOnePersonMutation,
|
||||
} from '~/generated/graphql';
|
||||
import { availableSorts } from '~/pages/people/people-sorts';
|
||||
|
||||
@ -46,7 +46,7 @@ export function PeopleTable() {
|
||||
viewIcon={<IconList size={16} />}
|
||||
availableSorts={availableSorts}
|
||||
onSortsUpdate={updateSorts}
|
||||
useUpdateField={useUpdatePeopleField}
|
||||
useUpdateEntityMutation={useUpdateOnePersonMutation}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -3,6 +3,8 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { internalHotkeysEnabledScopesState } from '../states/internal/internalHotkeysEnabledScopesState';
|
||||
|
||||
const DEBUG_HOTKEY_SCOPE = false;
|
||||
|
||||
export function useScopedHotkeyCallback() {
|
||||
return useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
@ -24,9 +26,31 @@ export function useScopedHotkeyCallback() {
|
||||
.valueOrThrow();
|
||||
|
||||
if (!currentHotkeyScopes.includes(scope)) {
|
||||
if (DEBUG_HOTKEY_SCOPE) {
|
||||
console.debug(
|
||||
`%cI can't call hotkey (${
|
||||
hotkeysEvent.keys
|
||||
}) because I'm in scope [${scope}] and the active scopes are : [${currentHotkeyScopes.join(
|
||||
', ',
|
||||
)}]`,
|
||||
'color: gray; ',
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG_HOTKEY_SCOPE) {
|
||||
console.debug(
|
||||
`%cI can call hotkey (${
|
||||
hotkeysEvent.keys
|
||||
}) because I'm in scope [${scope}] and the active scopes are : [${currentHotkeyScopes.join(
|
||||
', ',
|
||||
)}]`,
|
||||
'color: green;',
|
||||
);
|
||||
}
|
||||
|
||||
if (preventDefault) {
|
||||
keyboardEvent.stopPropagation();
|
||||
keyboardEvent.preventDefault();
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { GenericEditableCell } from '@/people/table/components/GenericEditableCell';
|
||||
import { GenericEditableCell } from '@/ui/table/components/GenericEditableCell';
|
||||
|
||||
import { RecoilScope } from '../../recoil-scope/components/RecoilScope';
|
||||
import { useCurrentRowSelected } from '../hooks/useCurrentRowSelected';
|
||||
|
@ -6,9 +6,8 @@ import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
|
||||
import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus';
|
||||
import { useMapKeyboardToSoftFocus } from '../hooks/useMapKeyboardToSoftFocus';
|
||||
import { EntityUpdateFieldHookContext } from '../states/EntityUpdateFieldHookContext';
|
||||
import { EntityUpdateMutationHookContext } from '../states/EntityUpdateMutationHookContext';
|
||||
import { TableHeader } from '../table-header/components/TableHeader';
|
||||
import { EntityUpdateFieldHook } from '../types/CellUpdateFieldHook';
|
||||
|
||||
import { EntityTableBody } from './EntityTableBodyV2';
|
||||
import { EntityTableHeader } from './EntityTableHeaderV2';
|
||||
@ -90,7 +89,7 @@ type OwnProps<SortField> = {
|
||||
availableSorts?: Array<SortType<SortField>>;
|
||||
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
|
||||
onRowSelectionChange?: (rowSelection: string[]) => void;
|
||||
useUpdateField: EntityUpdateFieldHook;
|
||||
useUpdateEntityMutation: any;
|
||||
};
|
||||
|
||||
export function EntityTable<SortField>({
|
||||
@ -98,7 +97,7 @@ export function EntityTable<SortField>({
|
||||
viewIcon,
|
||||
availableSorts,
|
||||
onSortsUpdate,
|
||||
useUpdateField,
|
||||
useUpdateEntityMutation,
|
||||
}: OwnProps<SortField>) {
|
||||
const tableBodyRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
@ -114,7 +113,7 @@ export function EntityTable<SortField>({
|
||||
});
|
||||
|
||||
return (
|
||||
<EntityUpdateFieldHookContext.Provider value={useUpdateField}>
|
||||
<EntityUpdateMutationHookContext.Provider value={useUpdateEntityMutation}>
|
||||
<StyledTableWithHeader>
|
||||
<StyledTableContainer ref={tableBodyRef}>
|
||||
<TableHeader
|
||||
@ -131,6 +130,6 @@ export function EntityTable<SortField>({
|
||||
</StyledTableWrapper>
|
||||
</StyledTableContainer>
|
||||
</StyledTableWithHeader>
|
||||
</EntityUpdateFieldHookContext.Provider>
|
||||
</EntityUpdateMutationHookContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
|
||||
|
||||
import { GenericEditableRelationCell } from './GenericEditableRelationCell';
|
||||
import { GenericEditableTextCell } from './GenericEditableTextCell';
|
||||
|
||||
type OwnProps = {
|
||||
@ -16,8 +17,15 @@ export function GenericEditableCell({ entityFieldMetadata }: OwnProps) {
|
||||
editModeHorizontalAlign="left"
|
||||
/>
|
||||
);
|
||||
|
||||
case 'relation': {
|
||||
return (
|
||||
<GenericEditableRelationCell fieldMetadata={entityFieldMetadata} />
|
||||
);
|
||||
}
|
||||
default:
|
||||
console.warn(
|
||||
`Unknown field type: ${entityFieldMetadata.type} in GenericEditableCell`,
|
||||
);
|
||||
return <></>;
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
import { RelationPickerHotkeyScope } from '@/ui/relation-picker/types/RelationPickerHotkeyScope';
|
||||
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
|
||||
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
|
||||
|
||||
import { GenericEditableRelationCellDisplayMode } from './GenericEditableRelationCellDisplayMode';
|
||||
import { GenericEditableRelationCellEditMode } from './GenericEditableRelationCellEditMode';
|
||||
|
||||
type OwnProps = {
|
||||
fieldMetadata: EntityFieldMetadata;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
export function GenericEditableRelationCell({
|
||||
fieldMetadata,
|
||||
editModeHorizontalAlign,
|
||||
placeholder,
|
||||
}: OwnProps) {
|
||||
return (
|
||||
<EditableCell
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
editHotkeyScope={{ scope: RelationPickerHotkeyScope.RelationPicker }}
|
||||
editModeContent={
|
||||
<GenericEditableRelationCellEditMode fieldMetadata={fieldMetadata} />
|
||||
}
|
||||
nonEditModeContent={
|
||||
<GenericEditableRelationCellDisplayMode
|
||||
fieldMetadata={fieldMetadata}
|
||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
}
|
||||
></EditableCell>
|
||||
);
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { CompanyChip } from '@/companies/components/CompanyChip';
|
||||
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
|
||||
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
|
||||
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
|
||||
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
|
||||
import { getLogoUrlFromDomainName } from '~/utils';
|
||||
|
||||
type OwnProps = {
|
||||
fieldMetadata: EntityFieldMetadata;
|
||||
editModeHorizontalAlign?: 'left' | 'right';
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
export function GenericEditableRelationCellDisplayMode({
|
||||
fieldMetadata,
|
||||
}: OwnProps) {
|
||||
const currentRowEntityId = useCurrentRowEntityId();
|
||||
|
||||
const fieldValue = useRecoilValue<any | null>(
|
||||
tableEntityFieldFamilySelector({
|
||||
entityId: currentRowEntityId ?? '',
|
||||
fieldName: fieldMetadata.fieldName,
|
||||
}),
|
||||
);
|
||||
|
||||
switch (fieldMetadata.relationType) {
|
||||
case Entity.Company: {
|
||||
return (
|
||||
<CompanyChip
|
||||
id={fieldValue?.id ?? ''}
|
||||
name={fieldValue?.name ?? ''}
|
||||
pictureUrl={getLogoUrlFromDomainName(fieldValue?.domainName)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
default:
|
||||
console.warn(
|
||||
`Unknown relation type: "${fieldMetadata.relationType}" in GenericEditableRelationCellEditMode`,
|
||||
);
|
||||
return <> </>;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { CompanyPickerCell } from '@/companies/components/CompanyPickerCell';
|
||||
import { useUpdateEntityField } from '@/people/hooks/useUpdateEntityField';
|
||||
import { EntityForSelect } from '@/ui/relation-picker/types/EntityForSelect';
|
||||
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
|
||||
import { useEditableCell } from '@/ui/table/editable-cell/hooks/useEditableCell';
|
||||
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
|
||||
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
|
||||
import { EntityFieldMetadata } from '@/ui/table/types/EntityFieldMetadata';
|
||||
|
||||
type OwnProps = {
|
||||
fieldMetadata: EntityFieldMetadata;
|
||||
};
|
||||
|
||||
export function GenericEditableRelationCellEditMode({
|
||||
fieldMetadata,
|
||||
}: OwnProps) {
|
||||
const currentRowEntityId = useCurrentRowEntityId();
|
||||
|
||||
const { closeEditableCell } = useEditableCell();
|
||||
|
||||
const [fieldValueEntity] = useRecoilState<any | null>(
|
||||
tableEntityFieldFamilySelector({
|
||||
entityId: currentRowEntityId ?? '',
|
||||
fieldName: fieldMetadata.fieldName,
|
||||
}),
|
||||
);
|
||||
|
||||
const updateEntityField = useUpdateEntityField();
|
||||
|
||||
function handleEntitySubmit(newFieldEntity: EntityForSelect | null) {
|
||||
if (
|
||||
newFieldEntity?.id !== fieldValueEntity?.id &&
|
||||
currentRowEntityId &&
|
||||
updateEntityField
|
||||
) {
|
||||
updateEntityField(
|
||||
currentRowEntityId,
|
||||
fieldMetadata.fieldName,
|
||||
newFieldEntity,
|
||||
);
|
||||
}
|
||||
|
||||
closeEditableCell();
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
closeEditableCell();
|
||||
}
|
||||
|
||||
switch (fieldMetadata.relationType) {
|
||||
case Entity.Company: {
|
||||
return (
|
||||
<CompanyPickerCell
|
||||
companyId={fieldValueEntity?.id ?? null}
|
||||
onSubmit={handleEntitySubmit}
|
||||
onCancel={handleCancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
default:
|
||||
console.warn(
|
||||
`Unknown relation type: "${fieldMetadata.relationType}" in GenericEditableRelationCellEditMode`,
|
||||
);
|
||||
return <></>;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useUpdateEntityField } from '@/people/hooks/useUpdateEntityField';
|
||||
import { InplaceInputTextEditMode } from '@/ui/inplace-input/components/InplaceInputTextEditMode';
|
||||
import { useEntityUpdateFieldHook } from '@/ui/table/hooks/useCellUpdateFieldHook';
|
||||
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
|
||||
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
|
||||
|
||||
@ -23,8 +23,7 @@ export function GenericEditableTextCellEditMode({
|
||||
}),
|
||||
);
|
||||
|
||||
const useUpdateField = useEntityUpdateFieldHook();
|
||||
const updateField = useUpdateField?.();
|
||||
const updateField = useUpdateEntityField();
|
||||
|
||||
function handleSubmit(newText: string) {
|
||||
if (newText === fieldValue) return;
|
@ -1,7 +0,0 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { EntityUpdateFieldHookContext } from '../states/EntityUpdateFieldHookContext';
|
||||
|
||||
export function useEntityUpdateFieldHook() {
|
||||
return useContext(EntityUpdateFieldHookContext);
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { EntityUpdateFieldHook } from '../types/CellUpdateFieldHook';
|
||||
|
||||
export const EntityUpdateFieldHookContext =
|
||||
createContext<EntityUpdateFieldHook | null>(null);
|
@ -0,0 +1,3 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const EntityUpdateMutationHookContext = createContext<any | null>(null);
|
@ -1,10 +1,6 @@
|
||||
export type EntityFieldType =
|
||||
| 'text'
|
||||
| 'number'
|
||||
| 'date'
|
||||
| 'select'
|
||||
| 'checkbox'
|
||||
| 'icon';
|
||||
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
|
||||
|
||||
export type EntityFieldType = 'text' | 'relation';
|
||||
|
||||
export type EntityFieldMetadata = {
|
||||
fieldName: string;
|
||||
@ -13,4 +9,5 @@ export type EntityFieldMetadata = {
|
||||
icon: JSX.Element;
|
||||
columnSize: number;
|
||||
filterIcon?: JSX.Element;
|
||||
relationType?: Entity; // TODO: condition this type with type === "relation"
|
||||
};
|
||||
|
56
front/src/modules/users/components/UserPicker.tsx
Normal file
56
front/src/modules/users/components/UserPicker.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||
import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { SingleEntitySelect } from '@/ui/relation-picker/components/SingleEntitySelect';
|
||||
import { relationPickerSearchFilterScopedState } from '@/ui/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||
import { EntityForSelect } from '@/ui/relation-picker/types/EntityForSelect';
|
||||
import { Entity } from '@/ui/relation-picker/types/EntityTypeForSelect';
|
||||
import { useSearchUserQuery } from '~/generated/graphql';
|
||||
|
||||
export type OwnProps = {
|
||||
userId: string;
|
||||
onSubmit: (newUserId: string) => void;
|
||||
onCancel?: () => void;
|
||||
};
|
||||
|
||||
type UserForSelect = EntityForSelect & {
|
||||
entityType: Entity.User;
|
||||
};
|
||||
|
||||
export function UserPicker({ userId, onSubmit, onCancel }: OwnProps) {
|
||||
const [searchFilter] = useRecoilScopedState(
|
||||
relationPickerSearchFilterScopedState,
|
||||
);
|
||||
|
||||
const users = useFilteredSearchEntityQuery({
|
||||
queryHook: useSearchUserQuery,
|
||||
selectedIds: [userId],
|
||||
searchFilter: searchFilter,
|
||||
mappingFunction: (user) => ({
|
||||
entityType: Entity.User,
|
||||
id: user.id,
|
||||
name: user.displayName,
|
||||
avatarType: 'rounded',
|
||||
avatarUrl: user.avatarUrl ?? '',
|
||||
}),
|
||||
orderByField: 'firstName',
|
||||
searchOnFields: ['firstName', 'lastName'],
|
||||
});
|
||||
|
||||
async function handleEntitySelected(
|
||||
selectedUser: UserForSelect | null | undefined,
|
||||
) {
|
||||
onSubmit(selectedUser?.id ?? '');
|
||||
}
|
||||
|
||||
return (
|
||||
<SingleEntitySelect
|
||||
onEntitySelected={handleEntitySelected}
|
||||
onCancel={onCancel}
|
||||
entities={{
|
||||
loading: users.loading,
|
||||
entitiesToSelect: users.entitiesToSelect,
|
||||
selectedEntity: users.selectedEntities[0],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user