Relations many in table view (#5842)
Closes #5924. Adding the "many" side of relations in the table view, and fixing some issues (glitch in Multi record select, cache update after update). --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -5,17 +5,17 @@ import { FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE } from '@/activities/calend
|
||||
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore';
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
|
||||
export const RightDrawerCalendarEvent = () => {
|
||||
const { setRecords } = useSetRecordInStore();
|
||||
const { upsertRecords } = useUpsertRecordsInStore();
|
||||
const viewableRecordId = useRecoilValue(viewableRecordIdState);
|
||||
const { record: calendarEvent } = useFindOneRecord<CalendarEvent>({
|
||||
objectNameSingular:
|
||||
FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE.objectNameSingular,
|
||||
objectRecordId: viewableRecordId ?? '',
|
||||
recordGqlFields: FIND_ONE_CALENDAR_EVENT_OPERATION_SIGNATURE.fields,
|
||||
onCompleted: (record) => setRecords([record]),
|
||||
onCompleted: (record) => upsertRecords([record]),
|
||||
});
|
||||
|
||||
if (!calendarEvent) {
|
||||
|
||||
@ -86,14 +86,6 @@ export const ActivityEditorFields = ({
|
||||
customUseUpdateOneObjectHook: useUpsertOneActivityMutation,
|
||||
});
|
||||
|
||||
const { FieldContextProvider: ActivityTargetsContextProvider } =
|
||||
useFieldContext({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
objectRecordId: activityId,
|
||||
fieldMetadataName: 'activityTargets',
|
||||
fieldPosition: 3,
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledPropertyBox>
|
||||
{activity.type === 'Task' &&
|
||||
@ -112,16 +104,12 @@ export const ActivityEditorFields = ({
|
||||
</AssigneeFieldContextProvider>
|
||||
</>
|
||||
)}
|
||||
{ActivityTargetsContextProvider &&
|
||||
isDefined(activityFromCache) &&
|
||||
isRightDrawerAnimationCompleted && (
|
||||
<ActivityTargetsContextProvider>
|
||||
<ActivityTargetsInlineCell
|
||||
activity={activityFromCache}
|
||||
maxWidth={340}
|
||||
/>
|
||||
</ActivityTargetsContextProvider>
|
||||
)}
|
||||
{isDefined(activityFromCache) && isRightDrawerAnimationCompleted && (
|
||||
<ActivityTargetsInlineCell
|
||||
activity={activityFromCache}
|
||||
maxWidth={340}
|
||||
/>
|
||||
)}
|
||||
</StyledPropertyBox>
|
||||
);
|
||||
};
|
||||
|
||||
@ -8,11 +8,11 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore';
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
|
||||
export const useRightDrawerEmailThread = () => {
|
||||
const viewableRecordId = useRecoilValue(viewableRecordIdState);
|
||||
const { setRecords } = useSetRecordInStore();
|
||||
const { upsertRecords } = useUpsertRecordsInStore();
|
||||
|
||||
const { record: thread } = useFindOneRecord<EmailThread>({
|
||||
objectNameSingular: CoreObjectNameSingular.MessageThread,
|
||||
@ -20,7 +20,7 @@ export const useRightDrawerEmailThread = () => {
|
||||
recordGqlFields: {
|
||||
id: true,
|
||||
},
|
||||
onCompleted: (record) => setRecords([record]),
|
||||
onCompleted: (record) => upsertRecords([record]),
|
||||
});
|
||||
|
||||
const FETCH_ALL_MESSAGES_OPERATION_SIGNATURE =
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
import { objectRecordsIdsMultiSelecComponentState } from '@/activities/states/objectRecordsIdsMultiSelectComponentState';
|
||||
import { objectRecordMultiSelectCheckedRecordsIdsComponentState } from '@/object-record/record-field/states/objectRecordMultiSelectCheckedRecordsIdsComponentState';
|
||||
import { objectRecordMultiSelectComponentFamilyState } from '@/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState';
|
||||
import { recordMultiSelectIsLoadingComponentState } from '@/object-record/record-field/states/recordMultiSelectIsLoadingComponentState';
|
||||
import { extractComponentFamilyState } from '@/ui/utilities/state/component-state/utils/extractComponentFamilyState';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
|
||||
export const useObjectRecordMultiSelectScopedStates = (scopeId: string) => {
|
||||
const objectRecordsIdsMultiSelectState = extractComponentState(
|
||||
objectRecordsIdsMultiSelecComponentState,
|
||||
scopeId,
|
||||
);
|
||||
|
||||
const objectRecordMultiSelectCheckedRecordsIdsState = extractComponentState(
|
||||
objectRecordMultiSelectCheckedRecordsIdsComponentState,
|
||||
scopeId,
|
||||
);
|
||||
|
||||
const objectRecordMultiSelectFamilyState = extractComponentFamilyState(
|
||||
objectRecordMultiSelectComponentFamilyState,
|
||||
scopeId,
|
||||
);
|
||||
|
||||
const recordMultiSelectIsLoadingState = extractComponentState(
|
||||
recordMultiSelectIsLoadingComponentState,
|
||||
scopeId,
|
||||
);
|
||||
|
||||
return {
|
||||
objectRecordsIdsMultiSelectState,
|
||||
objectRecordMultiSelectCheckedRecordsIdsState,
|
||||
objectRecordMultiSelectFamilyState,
|
||||
recordMultiSelectIsLoadingState,
|
||||
};
|
||||
};
|
||||
@ -1,9 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { isNonEmptyArray, isNull } from '@sniptt/guards';
|
||||
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { isNull } from '@sniptt/guards';
|
||||
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { useUpsertActivity } from '@/activities/hooks/useUpsertActivity';
|
||||
import { ActivityTargetObjectRecordEffect } from '@/activities/inline-cell/components/ActivityTargetObjectRecordEffect';
|
||||
import { isActivityInCreateModeState } from '@/activities/states/isActivityInCreateModeState';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { ActivityTarget } from '@/activities/types/ActivityTarget';
|
||||
@ -15,10 +16,17 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
||||
import { useCreateManyRecordsInCache } from '@/object-record/cache/hooks/useCreateManyRecordsInCache';
|
||||
import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords';
|
||||
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
|
||||
import { activityTargetObjectRecordFamilyState } from '@/object-record/record-field/states/activityTargetObjectRecordFamilyState';
|
||||
import { objectRecordMultiSelectCheckedRecordsIdsComponentState } from '@/object-record/record-field/states/objectRecordMultiSelectCheckedRecordsIdsComponentState';
|
||||
import {
|
||||
ObjectRecordAndSelected,
|
||||
objectRecordMultiSelectComponentFamilyState,
|
||||
} from '@/object-record/record-field/states/objectRecordMultiSelectComponentFamilyState';
|
||||
import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { MultipleObjectRecordSelect } from '@/object-record/relation-picker/components/MultipleObjectRecordSelect';
|
||||
import { ObjectRecordForSelect } from '@/object-record/relation-picker/hooks/useMultiObjectSearch';
|
||||
import { ActivityTargetInlineCellEditModeMultiRecordsEffect } from '@/object-record/relation-picker/components/ActivityTargetInlineCellEditModeMultiRecordsEffect';
|
||||
import { MultiRecordSelect } from '@/object-record/relation-picker/components/MultiRecordSelect';
|
||||
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
|
||||
import { prefillRecord } from '@/object-record/utils/prefillRecord';
|
||||
|
||||
const StyledSelectContainer = styled.div`
|
||||
@ -37,6 +45,7 @@ export const ActivityTargetInlineCellEditMode = ({
|
||||
activityTargetWithTargetRecords,
|
||||
}: ActivityTargetInlineCellEditModeProps) => {
|
||||
const [isActivityInCreateMode] = useRecoilState(isActivityInCreateModeState);
|
||||
const relationPickerScopeId = `relation-picker-${activity.id}`;
|
||||
|
||||
const selectedTargetObjectIds = activityTargetWithTargetRecords.map(
|
||||
(activityTarget) => ({
|
||||
@ -74,109 +83,181 @@ export const ActivityTargetInlineCellEditMode = ({
|
||||
objectNameSingular: CoreObjectNameSingular.ActivityTarget,
|
||||
});
|
||||
|
||||
const handleSubmit = async (selectedRecords: ObjectRecordForSelect[]) => {
|
||||
closeEditableField();
|
||||
const handleSubmit = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async () => {
|
||||
const activityTargetsAfterUpdate =
|
||||
activityTargetWithTargetRecords.filter((activityTarget) => {
|
||||
const record = snapshot
|
||||
.getLoadable(
|
||||
objectRecordMultiSelectComponentFamilyState({
|
||||
scopeId: relationPickerScopeId,
|
||||
familyKey: activityTarget.targetObject.id,
|
||||
}),
|
||||
)
|
||||
.getValue() as ObjectRecordAndSelected;
|
||||
|
||||
const activityTargetsToDelete = activityTargetWithTargetRecords.filter(
|
||||
(activityTargetObjectRecord) =>
|
||||
!selectedRecords.some(
|
||||
(selectedRecord) =>
|
||||
selectedRecord.recordIdentifier.id ===
|
||||
activityTargetObjectRecord.targetObject.id,
|
||||
),
|
||||
);
|
||||
return record.selected;
|
||||
});
|
||||
setActivityFromStore((currentActivity) => {
|
||||
if (isNull(currentActivity)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const selectedTargetObjectsToCreate = selectedRecords.filter(
|
||||
(selectedRecord) =>
|
||||
!activityTargetWithTargetRecords.some(
|
||||
(activityTargetWithTargetRecord) =>
|
||||
activityTargetWithTargetRecord.targetObject.id ===
|
||||
selectedRecord.recordIdentifier.id,
|
||||
),
|
||||
);
|
||||
|
||||
const existingActivityTargets = activityTargetWithTargetRecords.map(
|
||||
(activityTargetObjectRecord) => activityTargetObjectRecord.activityTarget,
|
||||
);
|
||||
|
||||
let activityTargetsAfterUpdate = Array.from(existingActivityTargets);
|
||||
|
||||
const activityTargetsToCreate = selectedTargetObjectsToCreate.map(
|
||||
(selectedRecord) => {
|
||||
const emptyActivityTarget = prefillRecord<ActivityTarget>({
|
||||
objectMetadataItem: objectMetadataItemActivityTarget,
|
||||
input: {
|
||||
id: v4(),
|
||||
activityId: activity.id,
|
||||
activity,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
[getActivityTargetObjectFieldName({
|
||||
nameSingular: selectedRecord.objectMetadataItem.nameSingular,
|
||||
})]: selectedRecord.record,
|
||||
[getActivityTargetObjectFieldIdName({
|
||||
nameSingular: selectedRecord.objectMetadataItem.nameSingular,
|
||||
})]: selectedRecord.recordIdentifier.id,
|
||||
},
|
||||
return {
|
||||
...currentActivity,
|
||||
activityTargets: activityTargetsAfterUpdate,
|
||||
};
|
||||
});
|
||||
|
||||
return emptyActivityTarget;
|
||||
closeEditableField();
|
||||
},
|
||||
);
|
||||
[
|
||||
activityTargetWithTargetRecords,
|
||||
closeEditableField,
|
||||
relationPickerScopeId,
|
||||
setActivityFromStore,
|
||||
],
|
||||
);
|
||||
|
||||
activityTargetsAfterUpdate.push(...activityTargetsToCreate);
|
||||
|
||||
if (isNonEmptyArray(activityTargetsToDelete)) {
|
||||
activityTargetsAfterUpdate = activityTargetsAfterUpdate.filter(
|
||||
(activityTarget) =>
|
||||
!activityTargetsToDelete.some(
|
||||
(activityTargetToDelete) =>
|
||||
activityTargetToDelete.activityTarget.id === activityTarget.id,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isActivityInCreateMode) {
|
||||
createManyActivityTargetsInCache(activityTargetsToCreate);
|
||||
upsertActivity({
|
||||
activity,
|
||||
input: {
|
||||
activityTargets: activityTargetsAfterUpdate,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
if (activityTargetsToCreate.length > 0) {
|
||||
await createManyActivityTargets(activityTargetsToCreate);
|
||||
}
|
||||
|
||||
if (activityTargetsToDelete.length > 0) {
|
||||
await deleteManyActivityTargets(
|
||||
activityTargetsToDelete.map(
|
||||
(activityTargetObjectRecord) =>
|
||||
activityTargetObjectRecord.activityTarget.id,
|
||||
),
|
||||
const handleChange = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (recordId: string) => {
|
||||
const existingActivityTargets = activityTargetWithTargetRecords.map(
|
||||
(activityTargetObjectRecord) =>
|
||||
activityTargetObjectRecord.activityTarget,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setActivityFromStore((currentActivity) => {
|
||||
if (isNull(currentActivity)) {
|
||||
return null;
|
||||
}
|
||||
let activityTargetsAfterUpdate = Array.from(existingActivityTargets);
|
||||
|
||||
return {
|
||||
...currentActivity,
|
||||
activityTargets: activityTargetsAfterUpdate,
|
||||
};
|
||||
});
|
||||
};
|
||||
const previouslyCheckedRecordsIds = snapshot
|
||||
.getLoadable(
|
||||
objectRecordMultiSelectCheckedRecordsIdsComponentState({
|
||||
scopeId: relationPickerScopeId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
const isNewlySelected = !previouslyCheckedRecordsIds.includes(recordId);
|
||||
|
||||
if (isNewlySelected) {
|
||||
const record = snapshot
|
||||
.getLoadable(
|
||||
objectRecordMultiSelectComponentFamilyState({
|
||||
scopeId: relationPickerScopeId,
|
||||
familyKey: recordId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!record) {
|
||||
throw new Error(
|
||||
`Could not find selected record with id ${recordId}`,
|
||||
);
|
||||
}
|
||||
|
||||
set(
|
||||
objectRecordMultiSelectCheckedRecordsIdsComponentState({
|
||||
scopeId: relationPickerScopeId,
|
||||
}),
|
||||
(prev) => [...prev, recordId],
|
||||
);
|
||||
|
||||
const newActivityTargetId = v4();
|
||||
const fieldName = getActivityTargetObjectFieldName({
|
||||
nameSingular: record.objectMetadataItem.nameSingular,
|
||||
});
|
||||
const fieldNameWithIdSuffix = getActivityTargetObjectFieldIdName({
|
||||
nameSingular: record.objectMetadataItem.nameSingular,
|
||||
});
|
||||
const newActivityTarget = prefillRecord<ActivityTarget>({
|
||||
objectMetadataItem: objectMetadataItemActivityTarget,
|
||||
input: {
|
||||
id: newActivityTargetId,
|
||||
activityId: activity.id,
|
||||
activity,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
[fieldName]: record.record,
|
||||
[fieldNameWithIdSuffix]: recordId,
|
||||
},
|
||||
});
|
||||
|
||||
activityTargetsAfterUpdate.push(newActivityTarget);
|
||||
|
||||
if (isActivityInCreateMode) {
|
||||
createManyActivityTargetsInCache([newActivityTarget]);
|
||||
upsertActivity({
|
||||
activity,
|
||||
input: {
|
||||
activityTargets: activityTargetsAfterUpdate,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await createManyActivityTargets([newActivityTarget]);
|
||||
}
|
||||
|
||||
set(activityTargetObjectRecordFamilyState(recordId), {
|
||||
activityTargetId: newActivityTargetId,
|
||||
});
|
||||
} else {
|
||||
const activityTargetToDeleteId = snapshot
|
||||
.getLoadable(activityTargetObjectRecordFamilyState(recordId))
|
||||
.getValue().activityTargetId;
|
||||
|
||||
if (!activityTargetToDeleteId) {
|
||||
throw new Error('Could not delete this activity target.');
|
||||
}
|
||||
|
||||
set(
|
||||
objectRecordMultiSelectCheckedRecordsIdsComponentState({
|
||||
scopeId: relationPickerScopeId,
|
||||
}),
|
||||
previouslyCheckedRecordsIds.filter((id) => id !== recordId),
|
||||
);
|
||||
activityTargetsAfterUpdate = activityTargetsAfterUpdate.filter(
|
||||
(activityTarget) => activityTarget.id !== activityTargetToDeleteId,
|
||||
);
|
||||
|
||||
if (isActivityInCreateMode) {
|
||||
upsertActivity({
|
||||
activity,
|
||||
input: {
|
||||
activityTargets: activityTargetsAfterUpdate,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await deleteManyActivityTargets([activityTargetToDeleteId]);
|
||||
}
|
||||
|
||||
set(activityTargetObjectRecordFamilyState(recordId), {
|
||||
activityTargetId: null,
|
||||
});
|
||||
}
|
||||
},
|
||||
[
|
||||
activity,
|
||||
activityTargetWithTargetRecords,
|
||||
createManyActivityTargets,
|
||||
createManyActivityTargetsInCache,
|
||||
deleteManyActivityTargets,
|
||||
isActivityInCreateMode,
|
||||
objectMetadataItemActivityTarget,
|
||||
relationPickerScopeId,
|
||||
upsertActivity,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledSelectContainer>
|
||||
<MultipleObjectRecordSelect
|
||||
selectedObjectRecordIds={selectedTargetObjectIds}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
<RelationPickerScope relationPickerScopeId={relationPickerScopeId}>
|
||||
<ActivityTargetObjectRecordEffect
|
||||
activityTargetWithTargetRecords={activityTargetWithTargetRecords}
|
||||
/>
|
||||
<ActivityTargetInlineCellEditModeMultiRecordsEffect
|
||||
selectedObjectRecordIds={selectedTargetObjectIds}
|
||||
/>
|
||||
<MultiRecordSelect onSubmit={handleSubmit} onChange={handleChange} />
|
||||
</RelationPickerScope>
|
||||
</StyledSelectContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { ActivityTargetWithTargetRecord } from '@/activities/types/ActivityTargetObject';
|
||||
import { activityTargetObjectRecordFamilyState } from '@/object-record/record-field/states/activityTargetObjectRecordFamilyState';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const ActivityTargetObjectRecordEffect = ({
|
||||
activityTargetWithTargetRecords,
|
||||
}: {
|
||||
activityTargetWithTargetRecords: ActivityTargetWithTargetRecord[];
|
||||
}) => {
|
||||
const updateActivityTargets = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
(newActivityTargets: ActivityTargetWithTargetRecord[]) => {
|
||||
for (const newActivityTarget of newActivityTargets) {
|
||||
const objectRecordId = newActivityTarget.targetObject.id;
|
||||
const record = snapshot
|
||||
.getLoadable(activityTargetObjectRecordFamilyState(objectRecordId))
|
||||
.getValue();
|
||||
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
record.activityTargetId,
|
||||
newActivityTarget.activityTarget.id,
|
||||
)
|
||||
) {
|
||||
set(activityTargetObjectRecordFamilyState(objectRecordId), {
|
||||
activityTargetId: newActivityTarget.activityTarget.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
updateActivityTargets(activityTargetWithTargetRecords);
|
||||
}, [activityTargetWithTargetRecords, updateActivityTargets]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -7,6 +7,8 @@ import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTa
|
||||
import { ActivityTargetInlineCellEditMode } from '@/activities/inline-cell/components/ActivityTargetInlineCellEditMode';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { ActivityEditorHotkeyScope } from '@/activities/types/ActivityEditorHotkeyScope';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { FieldFocusContextProvider } from '@/object-record/record-field/contexts/FieldFocusContextProvider';
|
||||
import { RecordFieldInputScope } from '@/object-record/record-field/scopes/RecordFieldInputScope';
|
||||
@ -41,33 +43,45 @@ export const ActivityTargetsInlineCell = ({
|
||||
ActivityEditorHotkeyScope.ActivityTargets,
|
||||
);
|
||||
|
||||
const { FieldContextProvider: ActivityTargetsContextProvider } =
|
||||
useFieldContext({
|
||||
objectNameSingular: CoreObjectNameSingular.Activity,
|
||||
objectRecordId: activity.id,
|
||||
fieldMetadataName: 'activityTargets',
|
||||
fieldPosition: 3,
|
||||
overridenIsFieldEmpty: activityTargetObjectRecords.length === 0,
|
||||
});
|
||||
|
||||
return (
|
||||
<RecordFieldInputScope recordFieldInputScopeId={activity?.id ?? ''}>
|
||||
<FieldFocusContextProvider>
|
||||
<RecordInlineCellContainer
|
||||
buttonIcon={IconPencil}
|
||||
customEditHotkeyScope={{
|
||||
scope: ActivityEditorHotkeyScope.ActivityTargets,
|
||||
}}
|
||||
IconLabel={showLabel ? IconArrowUpRight : undefined}
|
||||
showLabel={showLabel}
|
||||
readonly={readonly}
|
||||
labelWidth={fieldDefinition?.labelWidth}
|
||||
editModeContent={
|
||||
<ActivityTargetInlineCellEditMode
|
||||
activity={activity}
|
||||
activityTargetWithTargetRecords={activityTargetObjectRecords}
|
||||
{ActivityTargetsContextProvider && (
|
||||
<ActivityTargetsContextProvider>
|
||||
<RecordInlineCellContainer
|
||||
buttonIcon={IconPencil}
|
||||
customEditHotkeyScope={{
|
||||
scope: ActivityEditorHotkeyScope.ActivityTargets,
|
||||
}}
|
||||
IconLabel={showLabel ? IconArrowUpRight : undefined}
|
||||
showLabel={showLabel}
|
||||
readonly={readonly}
|
||||
labelWidth={fieldDefinition?.labelWidth}
|
||||
editModeContent={
|
||||
<ActivityTargetInlineCellEditMode
|
||||
activity={activity}
|
||||
activityTargetWithTargetRecords={activityTargetObjectRecords}
|
||||
/>
|
||||
}
|
||||
label="Relations"
|
||||
displayModeContent={
|
||||
<ActivityTargetChips
|
||||
activityTargetObjectRecords={activityTargetObjectRecords}
|
||||
maxWidth={maxWidth}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
label="Relations"
|
||||
displayModeContent={
|
||||
<ActivityTargetChips
|
||||
activityTargetObjectRecords={activityTargetObjectRecords}
|
||||
maxWidth={maxWidth}
|
||||
/>
|
||||
}
|
||||
isDisplayModeContentEmpty={activityTargetObjectRecords.length === 0}
|
||||
/>
|
||||
</ActivityTargetsContextProvider>
|
||||
)}
|
||||
</FieldFocusContextProvider>
|
||||
</RecordFieldInputScope>
|
||||
);
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
export const objectRecordsIdsMultiSelecComponentState = createComponentState<
|
||||
string[]
|
||||
>({
|
||||
key: 'objectRecordsIdsMultiSelectComponentState',
|
||||
defaultValue: [],
|
||||
});
|
||||
@ -4,7 +4,7 @@ import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { useActivities } from '@/activities/hooks/useActivities';
|
||||
import { FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY } from '@/activities/timeline/constants/FindManyTimelineActivitiesOrderBy';
|
||||
import { objectShowPageTargetableObjectState } from '@/activities/timeline/states/objectShowPageTargetableObjectIdState';
|
||||
import { timelineActivitiesFammilyState } from '@/activities/timeline/states/timelineActivitiesFamilyState';
|
||||
import { timelineActivitiesFamilyState } from '@/activities/timeline/states/timelineActivitiesFamilyState';
|
||||
import { timelineActivitiesForGroupState } from '@/activities/timeline/states/timelineActivitiesForGroupState';
|
||||
import { timelineActivityWithoutTargetsFamilyState } from '@/activities/timeline/states/timelineActivityWithoutTargetsFamilyState';
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
@ -68,11 +68,11 @@ export const TimelineQueryEffect = ({
|
||||
(newActivities: Activity[]) => {
|
||||
for (const newActivity of newActivities) {
|
||||
const currentActivity = snapshot
|
||||
.getLoadable(timelineActivitiesFammilyState(newActivity.id))
|
||||
.getLoadable(timelineActivitiesFamilyState(newActivity.id))
|
||||
.getValue();
|
||||
|
||||
if (!isDeeplyEqual(newActivity, currentActivity)) {
|
||||
set(timelineActivitiesFammilyState(newActivity.id), newActivity);
|
||||
set(timelineActivitiesFamilyState(newActivity.id), newActivity);
|
||||
}
|
||||
|
||||
const currentActivityWithoutTarget = snapshot
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { Activity } from '@/activities/types/Activity';
|
||||
import { createFamilyState } from '@/ui/utilities/state/utils/createFamilyState';
|
||||
|
||||
export const timelineActivitiesFammilyState = createFamilyState<
|
||||
export const timelineActivitiesFamilyState = createFamilyState<
|
||||
Activity | null,
|
||||
string
|
||||
>({
|
||||
key: 'timelineActivitiesFammilyState',
|
||||
key: 'timelineActivitiesFamilyState',
|
||||
defaultValue: null,
|
||||
});
|
||||
|
||||
@ -5,7 +5,7 @@ import { useOpenCalendarEventRightDrawer } from '@/activities/calendar/right-dra
|
||||
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore';
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import {
|
||||
formatToHumanReadableDay,
|
||||
formatToHumanReadableMonth,
|
||||
@ -85,7 +85,7 @@ export const EventCardCalendarEvent = ({
|
||||
}: {
|
||||
calendarEventId: string;
|
||||
}) => {
|
||||
const { setRecords } = useSetRecordInStore();
|
||||
const { upsertRecords } = useUpsertRecordsInStore();
|
||||
|
||||
const {
|
||||
record: calendarEvent,
|
||||
@ -101,7 +101,7 @@ export const EventCardCalendarEvent = ({
|
||||
endsAt: true,
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
setRecords([data]);
|
||||
upsertRecords([data]);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ import { EmailThreadMessage } from '@/activities/emails/types/EmailThreadMessage
|
||||
import { EventCardMessageNotShared } from '@/activities/timelineActivities/rows/message/components/EventCardMessageNotShared';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useFindOneRecord } from '@/object-record/hooks/useFindOneRecord';
|
||||
import { useSetRecordInStore } from '@/object-record/record-store/hooks/useSetRecordInStore';
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
const StyledEventCardMessageContainer = styled.div`
|
||||
@ -56,7 +56,7 @@ export const EventCardMessage = ({
|
||||
messageId: string;
|
||||
authorFullName: string;
|
||||
}) => {
|
||||
const { setRecords } = useSetRecordInStore();
|
||||
const { upsertRecords } = useUpsertRecordsInStore();
|
||||
|
||||
const {
|
||||
record: message,
|
||||
@ -75,7 +75,7 @@ export const EventCardMessage = ({
|
||||
},
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
setRecords([data]);
|
||||
upsertRecords([data]);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user