feat: add link to relation filtered table in Record Show Page (#3261)

* feat: add link to relation filtered table in Record Show Page

Closes #3125

* refactor: use generateFindManyRecordsQuery for optimization

* Fixes from review

* Minor fixes

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Thaïs
2024-01-11 16:51:06 -03:00
committed by GitHub
parent b3d9bed91d
commit 985c2f321e
14 changed files with 960 additions and 122 deletions

View File

@ -4,16 +4,16 @@ import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMa
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { capitalize } from '~/utils/string/capitalize';
export const useGenerateFindManyRecordsQuery = ({
objectMetadataItem,
depth,
}: {
objectMetadataItem: ObjectMetadataItem;
depth?: number;
}) => {
export const useGenerateFindManyRecordsQuery = () => {
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
return gql`
return ({
objectMetadataItem,
depth,
}: {
objectMetadataItem: ObjectMetadataItem;
depth?: number;
}) => gql`
query FindMany${capitalize(
objectMetadataItem.namePlural,
)}($filter: ${capitalize(

View File

@ -1,34 +1,30 @@
import { gql } from '@apollo/client';
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
import { EMPTY_QUERY } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
export const useGenerateFindOneRecordQuery = ({
objectMetadataItem,
depth,
}: {
objectMetadataItem: ObjectMetadataItem;
depth?: number;
}) => {
export const useGenerateFindOneRecordQuery = () => {
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
if (!objectMetadataItem) {
return EMPTY_QUERY;
}
return gql`
query FindOne${objectMetadataItem.nameSingular}($objectRecordId: UUID!) {
${objectMetadataItem.nameSingular}(filter: {
id: {
eq: $objectRecordId
return ({
objectMetadataItem,
depth,
}: {
objectMetadataItem: Pick<ObjectMetadataItem, 'nameSingular' | 'fields'>;
depth?: number;
}) =>
gql`
query FindOne${objectMetadataItem.nameSingular}($objectRecordId: UUID!) {
${objectMetadataItem.nameSingular}(filter: {
id: {
eq: $objectRecordId
}
}){
id
${objectMetadataItem.fields
.map((field) => mapFieldMetadataToGraphQLQuery(field, depth))
.join('\n')}
}
}){
id
${objectMetadataItem.fields
.map((field) => mapFieldMetadataToGraphQLQuery(field, depth))
.join('\n')}
}
}
`;
`;
};

View File

@ -1,9 +1,12 @@
import { useCallback, useContext, useEffect, useMemo } from 'react';
import { Link } from 'react-router-dom';
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import qs from 'qs';
import { useRecoilValue } from 'recoil';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { parseFieldRelationType } from '@/object-metadata/utils/parseFieldRelationType';
import { FieldContext } from '@/object-record/field/contexts/FieldContext';
import { usePersistField } from '@/object-record/field/hooks/usePersistField';
import { entityFieldsFamilyState } from '@/object-record/field/states/entityFieldsFamilyState';
@ -23,7 +26,10 @@ import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { Card } from '@/ui/layout/card/components/Card';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { Section } from '@/ui/layout/section/components/Section';
import { FilterQueryParams } from '@/views/hooks/internal/useFiltersFromQueryParams';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
const StyledAddDropdown = styled(Dropdown)`
margin-left: auto;
@ -54,8 +60,23 @@ const StyledHeader = styled.header<{ isDropdownOpen?: boolean }>`
`;
const StyledTitle = styled.div`
align-items: flex-end;
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
`;
const StyledTitleLabel = styled.div`
font-weight: ${({ theme }) => theme.font.weight.medium};
padding: ${({ theme }) => theme.spacing(0, 1)};
`;
const StyledLink = styled(Link)`
color: ${({ theme }) => theme.font.color.light};
text-decoration: none;
font-size: ${({ theme }) => theme.font.size.sm};
:hover {
color: ${({ theme }) => theme.font.color.secondary};
}
`;
export const RecordRelationFieldCardSection = () => {
@ -191,33 +212,54 @@ export const RecordRelationFieldCardSection = () => {
if (!relationLabelIdentifierFieldMetadata) return null;
const filterQueryParams: FilterQueryParams = {
filter: {
[relationFieldMetadataItem?.name || '']: {
[ViewFilterOperand.Is]: [entityId],
},
},
};
const filterLinkHref = `/objects/${
relationObjectMetadataItem.namePlural
}?${qs.stringify(filterQueryParams)}`;
return (
<Section>
<StyledHeader isDropdownOpen={isDropdownOpen}>
<StyledTitle>{fieldDefinition.label}</StyledTitle>
<StyledAddDropdown
dropdownId={dropdownId}
dropdownPlacement="right-start"
onClose={handleCloseRelationPickerDropdown}
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconPlus}
accent="tertiary"
/>
}
dropdownComponents={
<SingleEntitySelectMenuItemsWithSearch
EmptyIcon={IconForbid}
entitiesToSelect={entities.entitiesToSelect}
loading={entities.loading}
onEntitySelected={handleRelationPickerEntitySelected}
/>
}
dropdownHotkeyScope={{
scope: dropdownId,
}}
/>
<StyledTitle>
<StyledTitleLabel>{fieldDefinition.label}</StyledTitleLabel>
{parseFieldRelationType(relationFieldMetadataItem) ===
'TO_ONE_OBJECT' && (
<StyledLink to={filterLinkHref}>
All ({relationRecords.length})
</StyledLink>
)}
</StyledTitle>
<DropdownScope dropdownScopeId={dropdownId}>
<StyledAddDropdown
dropdownId={dropdownId}
dropdownPlacement="right-start"
onClose={handleCloseRelationPickerDropdown}
clickableComponent={
<LightIconButton
className="displayOnHover"
Icon={IconPlus}
accent="tertiary"
/>
}
dropdownComponents={
<SingleEntitySelectMenuItemsWithSearch
EmptyIcon={IconForbid}
entitiesToSelect={entities.entitiesToSelect}
loading={entities.loading}
onEntitySelected={handleRelationPickerEntitySelected}
/>
}
dropdownHotkeyScope={{
scope: dropdownId,
}}
/>
</DropdownScope>
</StyledHeader>
{!!relationRecords.length && (
<Card>