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:
Thaïs
2024-01-12 08:10:42 -03:00
committed by GitHub
parent d0ed9ee2e0
commit 0dc39db314
4 changed files with 110 additions and 15 deletions

View File

@ -30,7 +30,7 @@ module.exports = {
patterns: [ patterns: [
{ {
group: ['@tabler/icons-react'], group: ['@tabler/icons-react'],
message: 'Icon imports are only allowed for `@/ui/icon`', message: 'Icon imports are only allowed for `@/ui/display/icon`',
}, },
{ {
group: ['react-hotkeys-web-hook'], group: ['react-hotkeys-web-hook'],

View File

@ -1,52 +1,146 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { css } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { LightIconButton, MenuItem } from 'tsup.ui.index';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { FieldDisplay } from '@/object-record/field/components/FieldDisplay'; import { FieldDisplay } from '@/object-record/field/components/FieldDisplay';
import { FieldContext } from '@/object-record/field/contexts/FieldContext'; 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 { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
import { useFieldContext } from '@/object-record/hooks/useFieldContext'; 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 { 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; align-items: center;
justify-content: space-between;
gap: ${({ theme }) => theme.spacing(1)};
display: flex; display: flex;
height: ${({ theme }) => theme.spacing(10)}; height: ${({ theme }) => theme.spacing(10)};
padding: ${({ theme }) => theme.spacing(0, 2, 0, 3)}; 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 = { type RecordRelationFieldCardContentProps = {
divider?: boolean; divider?: boolean;
relationRecordId: string; relationRecord: ObjectRecord;
}; };
export const RecordRelationFieldCardContent = ({ export const RecordRelationFieldCardContent = ({
divider, divider,
relationRecordId, relationRecord,
}: RecordRelationFieldCardContentProps) => { }: RecordRelationFieldCardContentProps) => {
const { fieldDefinition } = useContext(FieldContext); const { fieldDefinition } = useContext(FieldContext);
const { relationObjectMetadataNameSingular } = const {
fieldDefinition.metadata as FieldRelationMetadata; relationFieldMetadataId,
const { labelIdentifierFieldMetadata: relationLabelIdentifierFieldMetadata } = relationObjectMetadataNameSingular,
useObjectMetadataItem({ relationType,
objectNameSingular: relationObjectMetadataNameSingular, } = 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({ const { FieldContextProvider } = useFieldContext({
fieldMetadataName: relationLabelIdentifierFieldMetadata?.name || '', fieldMetadataName: relationLabelIdentifierFieldMetadata?.name || '',
fieldPosition: 0, fieldPosition: 0,
isLabelIdentifier: true, isLabelIdentifier: true,
objectNameSingular: relationObjectMetadataNameSingular, objectNameSingular: relationObjectMetadataNameSingular,
objectRecordId: relationRecordId, objectRecordId: relationRecord.id,
}); });
const dropdownScopeId = `record-field-card-menu-${relationRecord.id}`;
const { closeDropdown, isDropdownOpen } = useDropdown(dropdownScopeId);
if (!FieldContextProvider) return null; 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 ( return (
<StyledCardContent divider={divider}> <StyledCardContent isDropdownOpen={isDropdownOpen} divider={divider}>
<FieldContextProvider> <FieldContextProvider>
<FieldDisplay /> <FieldDisplay />
</FieldContextProvider> </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> </StyledCardContent>
); );
}; };

View File

@ -183,7 +183,7 @@ export const RecordRelationFieldCardSection = () => {
}, [setRelationPickerSearchFilter]); }, [setRelationPickerSearchFilter]);
const persistField = usePersistField(); const persistField = usePersistField();
const { updateOneRecord } = useUpdateOneRecord({ const { updateOneRecord: updateOneRelationRecord } = useUpdateOneRecord({
objectNameSingular: relationObjectMetadataNameSingular, objectNameSingular: relationObjectMetadataNameSingular,
}); });
@ -201,7 +201,7 @@ export const RecordRelationFieldCardSection = () => {
if (!relationFieldMetadataItem?.name) return; if (!relationFieldMetadataItem?.name) return;
updateOneRecord({ updateOneRelationRecord({
idToUpdate: selectedRelationEntity.id, idToUpdate: selectedRelationEntity.id,
updateOneRecordInput: { updateOneRecordInput: {
[`${relationFieldMetadataItem.name}Id`]: entityId, [`${relationFieldMetadataItem.name}Id`]: entityId,
@ -267,7 +267,7 @@ export const RecordRelationFieldCardSection = () => {
<RecordRelationFieldCardContent <RecordRelationFieldCardContent
key={`${relationRecord.id}${relationLabelIdentifierFieldMetadata?.id}`} key={`${relationRecord.id}${relationLabelIdentifierFieldMetadata?.id}`}
divider={index < relationRecords.length - 1} divider={index < relationRecords.length - 1}
relationRecordId={relationRecord.id} relationRecord={relationRecord}
/> />
))} ))}
</Card> </Card>

View File

@ -108,6 +108,7 @@ export {
IconTextSize, IconTextSize,
IconTimelineEvent, IconTimelineEvent,
IconTrash, IconTrash,
IconUnlink,
IconUpload, IconUpload,
IconUser, IconUser,
IconUserCircle, IconUserCircle,