feat: detach records from Relation field card in Show Page (#3350)
* feat: detach records from Relation field card in Show Page Closes #3128 * Fix TS --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -1,52 +1,146 @@
|
||||
import { useContext } from 'react';
|
||||
import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { LightIconButton, MenuItem } from 'tsup.ui.index';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { FieldDisplay } from '@/object-record/field/components/FieldDisplay';
|
||||
import { FieldContext } from '@/object-record/field/contexts/FieldContext';
|
||||
import { usePersistField } from '@/object-record/field/hooks/usePersistField';
|
||||
import { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
|
||||
import { useFieldContext } from '@/object-record/hooks/useFieldContext';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { IconDotsVertical, IconUnlink } from '@/ui/display/icon';
|
||||
import { CardContent } from '@/ui/layout/card/components/CardContent';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
|
||||
const StyledCardContent = styled(CardContent)`
|
||||
const StyledCardContent = styled(CardContent)<{
|
||||
isDropdownOpen?: boolean;
|
||||
}>`
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
display: flex;
|
||||
height: ${({ theme }) => theme.spacing(10)};
|
||||
padding: ${({ theme }) => theme.spacing(0, 2, 0, 3)};
|
||||
|
||||
${({ isDropdownOpen, theme }) =>
|
||||
isDropdownOpen
|
||||
? ''
|
||||
: css`
|
||||
.displayOnHover {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity ${theme.animation.duration.instant}s ease;
|
||||
}
|
||||
`}
|
||||
|
||||
&:hover {
|
||||
.displayOnHover {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
type RecordRelationFieldCardContentProps = {
|
||||
divider?: boolean;
|
||||
relationRecordId: string;
|
||||
relationRecord: ObjectRecord;
|
||||
};
|
||||
|
||||
export const RecordRelationFieldCardContent = ({
|
||||
divider,
|
||||
relationRecordId,
|
||||
relationRecord,
|
||||
}: RecordRelationFieldCardContentProps) => {
|
||||
const { fieldDefinition } = useContext(FieldContext);
|
||||
const { relationObjectMetadataNameSingular } =
|
||||
fieldDefinition.metadata as FieldRelationMetadata;
|
||||
const { labelIdentifierFieldMetadata: relationLabelIdentifierFieldMetadata } =
|
||||
useObjectMetadataItem({
|
||||
objectNameSingular: relationObjectMetadataNameSingular,
|
||||
});
|
||||
const {
|
||||
relationFieldMetadataId,
|
||||
relationObjectMetadataNameSingular,
|
||||
relationType,
|
||||
} = fieldDefinition.metadata as FieldRelationMetadata;
|
||||
const isToOneObject = relationType === 'TO_ONE_OBJECT';
|
||||
const {
|
||||
labelIdentifierFieldMetadata: relationLabelIdentifierFieldMetadata,
|
||||
objectMetadataItem: relationObjectMetadataItem,
|
||||
} = useObjectMetadataItem({
|
||||
objectNameSingular: relationObjectMetadataNameSingular,
|
||||
});
|
||||
const persistField = usePersistField();
|
||||
const { updateOneRecord: updateOneRelationRecord } = useUpdateOneRecord({
|
||||
objectNameSingular: relationObjectMetadataNameSingular,
|
||||
});
|
||||
|
||||
const { FieldContextProvider } = useFieldContext({
|
||||
fieldMetadataName: relationLabelIdentifierFieldMetadata?.name || '',
|
||||
fieldPosition: 0,
|
||||
isLabelIdentifier: true,
|
||||
objectNameSingular: relationObjectMetadataNameSingular,
|
||||
objectRecordId: relationRecordId,
|
||||
objectRecordId: relationRecord.id,
|
||||
});
|
||||
|
||||
const dropdownScopeId = `record-field-card-menu-${relationRecord.id}`;
|
||||
|
||||
const { closeDropdown, isDropdownOpen } = useDropdown(dropdownScopeId);
|
||||
|
||||
if (!FieldContextProvider) return null;
|
||||
|
||||
const handleDetach = () => {
|
||||
closeDropdown();
|
||||
|
||||
const relationFieldMetadataItem = relationObjectMetadataItem.fields.find(
|
||||
({ id }) => id === relationFieldMetadataId,
|
||||
);
|
||||
|
||||
if (!relationFieldMetadataItem?.name) return;
|
||||
|
||||
if (isToOneObject) {
|
||||
persistField(null);
|
||||
return;
|
||||
}
|
||||
|
||||
updateOneRelationRecord({
|
||||
idToUpdate: relationRecord.id,
|
||||
updateOneRecordInput: {
|
||||
[`${relationFieldMetadataItem.name}Id`]: null,
|
||||
[relationFieldMetadataItem.name]: null,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledCardContent divider={divider}>
|
||||
<StyledCardContent isDropdownOpen={isDropdownOpen} divider={divider}>
|
||||
<FieldContextProvider>
|
||||
<FieldDisplay />
|
||||
</FieldContextProvider>
|
||||
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||
<Dropdown
|
||||
dropdownId={dropdownScopeId}
|
||||
dropdownPlacement="right-start"
|
||||
clickableComponent={
|
||||
<LightIconButton
|
||||
className="displayOnHover"
|
||||
Icon={IconDotsVertical}
|
||||
accent="tertiary"
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
LeftIcon={IconUnlink}
|
||||
text="Detach"
|
||||
onClick={handleDetach}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: dropdownScopeId,
|
||||
}}
|
||||
/>
|
||||
</DropdownScope>
|
||||
</StyledCardContent>
|
||||
);
|
||||
};
|
||||
|
||||
@ -183,7 +183,7 @@ export const RecordRelationFieldCardSection = () => {
|
||||
}, [setRelationPickerSearchFilter]);
|
||||
|
||||
const persistField = usePersistField();
|
||||
const { updateOneRecord } = useUpdateOneRecord({
|
||||
const { updateOneRecord: updateOneRelationRecord } = useUpdateOneRecord({
|
||||
objectNameSingular: relationObjectMetadataNameSingular,
|
||||
});
|
||||
|
||||
@ -201,7 +201,7 @@ export const RecordRelationFieldCardSection = () => {
|
||||
|
||||
if (!relationFieldMetadataItem?.name) return;
|
||||
|
||||
updateOneRecord({
|
||||
updateOneRelationRecord({
|
||||
idToUpdate: selectedRelationEntity.id,
|
||||
updateOneRecordInput: {
|
||||
[`${relationFieldMetadataItem.name}Id`]: entityId,
|
||||
@ -267,7 +267,7 @@ export const RecordRelationFieldCardSection = () => {
|
||||
<RecordRelationFieldCardContent
|
||||
key={`${relationRecord.id}${relationLabelIdentifierFieldMetadata?.id}`}
|
||||
divider={index < relationRecords.length - 1}
|
||||
relationRecordId={relationRecord.id}
|
||||
relationRecord={relationRecord}
|
||||
/>
|
||||
))}
|
||||
</Card>
|
||||
|
||||
@ -108,6 +108,7 @@ export {
|
||||
IconTextSize,
|
||||
IconTimelineEvent,
|
||||
IconTrash,
|
||||
IconUnlink,
|
||||
IconUpload,
|
||||
IconUser,
|
||||
IconUserCircle,
|
||||
|
||||
Reference in New Issue
Block a user