mirror of
https://github.com/twentyhq/twenty.git
synced 2025-01-09 02:11:55 +03:00
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:
parent
b3d9bed91d
commit
985c2f321e
@ -117,6 +117,7 @@
|
||||
"pg-boss": "^9.0.3",
|
||||
"prettier": "^3.0.3",
|
||||
"prism-react-renderer": "^2.1.0",
|
||||
"qs": "^6.11.2",
|
||||
"react": "^18.2.0",
|
||||
"react-data-grid": "7.0.0-beta.13",
|
||||
"react-datepicker": "^4.11.0",
|
||||
|
@ -83,12 +83,14 @@ export const useObjectMetadataItem = (
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
const findManyRecordsQuery = useGenerateFindManyRecordsQuery({
|
||||
const generateFindManyRecordsQuery = useGenerateFindManyRecordsQuery();
|
||||
const findManyRecordsQuery = generateFindManyRecordsQuery({
|
||||
objectMetadataItem,
|
||||
depth,
|
||||
});
|
||||
|
||||
const findOneRecordQuery = useGenerateFindOneRecordQuery({
|
||||
const generateFindOneRecordQuery = useGenerateFindOneRecordQuery();
|
||||
const findOneRecordQuery = generateFindOneRecordQuery({
|
||||
objectMetadataItem,
|
||||
depth,
|
||||
});
|
||||
|
@ -38,7 +38,7 @@ export const formatFieldMetadataItemsAsFilterDefinitions = ({
|
||||
return [...acc, formatFieldMetadataItemAsFilterDefinition({ field })];
|
||||
}, [] as FilterDefinition[]);
|
||||
|
||||
const formatFieldMetadataItemAsFilterDefinition = ({
|
||||
export const formatFieldMetadataItemAsFilterDefinition = ({
|
||||
field,
|
||||
}: {
|
||||
field: ObjectMetadataItem['fields'][0];
|
||||
|
@ -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(
|
||||
|
@ -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')}
|
||||
}
|
||||
}
|
||||
`;
|
||||
`;
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -0,0 +1,39 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useFiltersFromQueryParams } from '@/views/hooks/internal/useFiltersFromQueryParams';
|
||||
import { useViewScopedStates } from '@/views/hooks/internal/useViewScopedStates';
|
||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||
|
||||
export const FilterQueryParamsEffect = () => {
|
||||
const { hasFiltersQueryParams, getFiltersFromQueryParams } =
|
||||
useFiltersFromQueryParams();
|
||||
const { currentViewFiltersState, onViewFiltersChangeState } =
|
||||
useViewScopedStates();
|
||||
const setCurrentViewFilters = useSetRecoilState(currentViewFiltersState);
|
||||
const onViewFiltersChange = useRecoilValue(onViewFiltersChangeState);
|
||||
const { resetViewBar } = useViewBar();
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasFiltersQueryParams) return;
|
||||
|
||||
getFiltersFromQueryParams().then((filtersFromParams) => {
|
||||
if (Array.isArray(filtersFromParams)) {
|
||||
setCurrentViewFilters(filtersFromParams);
|
||||
onViewFiltersChange?.(filtersFromParams);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
resetViewBar();
|
||||
};
|
||||
}, [
|
||||
getFiltersFromQueryParams,
|
||||
hasFiltersQueryParams,
|
||||
onViewFiltersChange,
|
||||
resetViewBar,
|
||||
setCurrentViewFilters,
|
||||
]);
|
||||
|
||||
return null;
|
||||
};
|
@ -1,10 +1,12 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { ObjectFilterDropdownButton } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownButton';
|
||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
import { ObjectSortDropdownButton } from '@/object-record/object-sort-dropdown/components/ObjectSortDropdownButton';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { TopBar } from '@/ui/layout/top-bar/TopBar';
|
||||
import { FilterQueryParamsEffect } from '@/views/components/FilterQueryParamsEffect';
|
||||
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
||||
import { ViewBarSortEffect } from '@/views/components/ViewBarSortEffect';
|
||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||
@ -45,6 +47,7 @@ export const ViewBar = ({
|
||||
const { upsertViewSort, upsertViewFilter } = useViewBar({
|
||||
viewBarId: viewBarId,
|
||||
});
|
||||
const { objectNamePlural } = useParams();
|
||||
|
||||
const filterDropdownId = 'view-filter';
|
||||
const sortDropdownId = 'view-sort';
|
||||
@ -65,6 +68,7 @@ export const ViewBar = ({
|
||||
sortDropdownId={sortDropdownId}
|
||||
onSortSelect={upsertViewSort}
|
||||
/>
|
||||
{!!objectNamePlural && <FilterQueryParamsEffect />}
|
||||
|
||||
<TopBar
|
||||
className={className}
|
||||
|
@ -5,6 +5,7 @@ import { useRecoilValue } from 'recoil';
|
||||
import { AddObjectFilterFromDetailsButton } from '@/object-record/object-filter-dropdown/components/AddObjectFilterFromDetailsButton';
|
||||
import { ObjectFilterDropdownScope } from '@/object-record/object-filter-dropdown/scopes/ObjectFilterDropdownScope';
|
||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { EditableFilterDropdownButton } from '@/views/components/EditableFilterDropdownButton';
|
||||
import { EditableSortChip } from '@/views/components/EditableSortChip';
|
||||
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
||||
@ -132,19 +133,20 @@ export const ViewBarDetails = ({
|
||||
<StyledBar>
|
||||
<StyledFilterContainer>
|
||||
<StyledChipcontainer>
|
||||
{currentViewSorts?.map((sort) => {
|
||||
return <EditableSortChip viewSort={sort} />;
|
||||
})}
|
||||
{currentViewSorts?.map((sort) => (
|
||||
<EditableSortChip key={sort.id} viewSort={sort} />
|
||||
))}
|
||||
{!!currentViewSorts?.length && !!currentViewFilters?.length && (
|
||||
<StyledSeperatorContainer>
|
||||
<StyledSeperator />
|
||||
</StyledSeperatorContainer>
|
||||
)}
|
||||
{currentViewFilters?.map((viewFilter) => {
|
||||
return (
|
||||
<ObjectFilterDropdownScope
|
||||
filterScopeId={viewFilter.fieldMetadataId}
|
||||
>
|
||||
{currentViewFilters?.map((viewFilter) => (
|
||||
<ObjectFilterDropdownScope
|
||||
key={viewFilter.id}
|
||||
filterScopeId={viewFilter.fieldMetadataId}
|
||||
>
|
||||
<DropdownScope dropdownScopeId={viewFilter.fieldMetadataId}>
|
||||
<ViewBarFilterEffect
|
||||
filterDropdownId={viewFilter.fieldMetadataId}
|
||||
onFilterSelect={upsertViewFilter}
|
||||
@ -156,9 +158,9 @@ export const ViewBarDetails = ({
|
||||
}}
|
||||
viewFilterDropdownId={viewFilter.fieldMetadataId}
|
||||
/>
|
||||
</ObjectFilterDropdownScope>
|
||||
);
|
||||
})}
|
||||
</DropdownScope>
|
||||
</ObjectFilterDropdownScope>
|
||||
))}
|
||||
</StyledChipcontainer>
|
||||
{hasFilterButton && (
|
||||
<StyledAddFilterContainer>
|
||||
|
@ -27,7 +27,7 @@ export const ViewBarFilterEffect = ({
|
||||
filterDefinitionUsedInDropdown,
|
||||
setObjectFilterDropdownSelectedRecordIds,
|
||||
isObjectFilterDropdownUnfolded,
|
||||
} = useFilterDropdown({ filterDropdownId: filterDropdownId });
|
||||
} = useFilterDropdown({ filterDropdownId });
|
||||
|
||||
useEffect(() => {
|
||||
if (availableFilterDefinitions) {
|
||||
|
@ -0,0 +1,160 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useParams, useSearchParams } from 'react-router-dom';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import qs from 'qs';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import z from 'zod';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||
import { formatFieldMetadataItemAsFilterDefinition } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier';
|
||||
import { useGenerateFindManyRecordsQuery } from '@/object-record/hooks/useGenerateFindManyRecordsQuery';
|
||||
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { assertNotNull } from '~/utils/assert';
|
||||
|
||||
const filterQueryParamsSchema = z.object({
|
||||
filter: z.record(
|
||||
z.record(
|
||||
z.nativeEnum(ViewFilterOperand),
|
||||
z.string().or(z.array(z.string())),
|
||||
),
|
||||
),
|
||||
});
|
||||
|
||||
export type FilterQueryParams = z.infer<typeof filterQueryParamsSchema>;
|
||||
|
||||
export const useFiltersFromQueryParams = () => {
|
||||
const apolloClient = useApolloClient();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { objectNamePlural = '' } = useParams();
|
||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||
objectNamePlural,
|
||||
});
|
||||
const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular });
|
||||
const generateFindManyRecordsQuery = useGenerateFindManyRecordsQuery();
|
||||
|
||||
const filterParamsValidation = filterQueryParamsSchema.safeParse(
|
||||
qs.parse(searchParams.toString()),
|
||||
);
|
||||
const filterQueryParams = useMemo(
|
||||
() =>
|
||||
filterParamsValidation.success ? filterParamsValidation.data.filter : {},
|
||||
[filterParamsValidation],
|
||||
);
|
||||
const hasFiltersQueryParams = filterParamsValidation.success;
|
||||
|
||||
const getFiltersFromQueryParams = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async () => {
|
||||
if (!hasFiltersQueryParams) return [];
|
||||
|
||||
return (
|
||||
await Promise.all(
|
||||
Object.entries(filterQueryParams).map<Promise<ViewFilter | null>>(
|
||||
async ([fieldName, filterFromURL]) => {
|
||||
const [filterOperandFromURL, filterValueFromURL] =
|
||||
Object.entries(filterFromURL)[0];
|
||||
const fieldMetadataItem = objectMetadataItem.fields.find(
|
||||
(field) => field.name === fieldName,
|
||||
);
|
||||
|
||||
if (!fieldMetadataItem) return null;
|
||||
|
||||
const filterDefinition =
|
||||
formatFieldMetadataItemAsFilterDefinition({
|
||||
field: fieldMetadataItem,
|
||||
});
|
||||
|
||||
if (!filterDefinition) return null;
|
||||
|
||||
const relationObjectMetadataNameSingular =
|
||||
fieldMetadataItem.toRelationMetadata?.fromObjectMetadata
|
||||
.nameSingular;
|
||||
|
||||
const relationObjectMetadataNamePlural =
|
||||
fieldMetadataItem.toRelationMetadata?.fromObjectMetadata
|
||||
.namePlural;
|
||||
|
||||
const relationObjectMetadataItem =
|
||||
relationObjectMetadataNameSingular
|
||||
? snapshot
|
||||
.getLoadable(
|
||||
objectMetadataItemFamilySelector({
|
||||
objectName: relationObjectMetadataNameSingular,
|
||||
objectNameType: 'singular',
|
||||
}),
|
||||
)
|
||||
.getValue()
|
||||
: null;
|
||||
|
||||
const relationRecordNames = [];
|
||||
|
||||
if (
|
||||
relationObjectMetadataNamePlural &&
|
||||
relationObjectMetadataItem &&
|
||||
Array.isArray(filterValueFromURL)
|
||||
) {
|
||||
const queryResult = await apolloClient.query<
|
||||
Record<string, { edges: { node: ObjectRecord }[] }>
|
||||
>({
|
||||
query: generateFindManyRecordsQuery({
|
||||
objectMetadataItem: relationObjectMetadataItem,
|
||||
}),
|
||||
variables: {
|
||||
filter: { id: { in: filterValueFromURL } },
|
||||
},
|
||||
});
|
||||
|
||||
const relationRecordNamesFromQuery = queryResult.data?.[
|
||||
relationObjectMetadataNamePlural
|
||||
]?.edges.map(
|
||||
({ node: record }) =>
|
||||
getObjectRecordIdentifier({
|
||||
objectMetadataItem: relationObjectMetadataItem,
|
||||
record,
|
||||
}).name,
|
||||
);
|
||||
|
||||
relationRecordNames.push(...relationRecordNamesFromQuery);
|
||||
}
|
||||
|
||||
const filterValueAsString = Array.isArray(filterValueFromURL)
|
||||
? JSON.stringify(filterValueFromURL)
|
||||
: filterValueFromURL;
|
||||
|
||||
return {
|
||||
id: `tmp-${[
|
||||
fieldName,
|
||||
filterOperandFromURL,
|
||||
filterValueFromURL,
|
||||
].join('-')}`,
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
operand: filterOperandFromURL as ViewFilterOperand,
|
||||
value: filterValueAsString,
|
||||
displayValue:
|
||||
relationRecordNames?.join(', ') ?? filterValueAsString,
|
||||
definition: filterDefinition,
|
||||
};
|
||||
},
|
||||
),
|
||||
)
|
||||
).filter(assertNotNull);
|
||||
},
|
||||
[
|
||||
apolloClient,
|
||||
filterQueryParams,
|
||||
generateFindManyRecordsQuery,
|
||||
hasFiltersQueryParams,
|
||||
objectMetadataItem.fields,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
hasFiltersQueryParams,
|
||||
getFiltersFromQueryParams,
|
||||
};
|
||||
};
|
@ -43,13 +43,7 @@ export const useViewFilters = (viewScopeId: string) => {
|
||||
viewScopeId,
|
||||
});
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
if (!currentViewFilters) {
|
||||
return;
|
||||
}
|
||||
if (!savedViewFiltersByKey) {
|
||||
if (!currentViewId || !currentViewFilters || !savedViewFiltersByKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,10 @@ export const useViewBar = (props?: UseViewProps) => {
|
||||
|
||||
const changeViewInUrl = useCallback(
|
||||
(viewId: string) => {
|
||||
setSearchParams({ view: viewId });
|
||||
setSearchParams((previousSearchParams) => {
|
||||
previousSearchParams.set('view', viewId);
|
||||
return previousSearchParams;
|
||||
});
|
||||
},
|
||||
[setSearchParams],
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user