catalog-graph: fix navigation in catalog graph page

Signed-off-by: Mahendra Suthar <mahendra.suthar.1290@gmail.com>
This commit is contained in:
Mahendra Suthar
2024-08-07 17:35:35 +05:30
parent 66b68a151c
commit 726cab9269
@@ -27,8 +27,7 @@ import {
useMemo,
useState,
} from 'react';
import { useLocation } from 'react-router-dom';
import usePrevious from 'react-use/esm/usePrevious';
import { useLocation, useSearchParams } from 'react-router-dom';
import { Direction } from '../EntityRelationsGraph';
export type CatalogGraphPageValue = {
@@ -70,6 +69,7 @@ export function useCatalogGraphPage({
};
}): CatalogGraphPageValue {
const location = useLocation();
const [_, setSearchParams] = useSearchParams();
const query = useMemo(
() =>
(qs.parse(location.search, { arrayLimit: 0, ignoreQueryPrefix: true }) ||
@@ -87,19 +87,53 @@ export function useCatalogGraphPage({
[location.search],
);
// Initial state
const [rootEntityNames, setRootEntityNames] = useState<CompoundEntityRef[]>(
const rootEntityNames = useMemo(
() =>
(Array.isArray(query.rootEntityRefs)
? query.rootEntityRefs
: initialState?.rootEntityRefs ?? []
).map(r => parseEntityRef(r)),
[initialState?.rootEntityRefs, query.rootEntityRefs],
);
const setRootEntityNames = useCallback(
(value: React.SetStateAction<CompoundEntityRef[]>) => {
const prev = Array.isArray(query.rootEntityRefs)
? query.rootEntityRefs
: [];
const hasChanged =
Array.isArray(value) &&
(value.length !== prev.length ||
value.some((r, i) => stringifyEntityRef(r) !== prev[i]));
if (!hasChanged) {
return;
}
setSearchParams(params => {
const rootEntityRefs = Array.isArray(value)
? value.map(r => stringifyEntityRef(r))
: [];
params.delete('rootEntityRefs[]');
rootEntityRefs.forEach(r => {
params.set('rootEntityRefs[]', r);
});
return params;
});
},
[query.rootEntityRefs, setSearchParams],
);
const [maxDepth, setMaxDepth] = useState<number>(() =>
typeof query.maxDepth === 'string'
? parseMaxDepth(query.maxDepth)
: initialState?.maxDepth ?? Number.POSITIVE_INFINITY,
);
const [selectedRelations, setSelectedRelations] = useState<
string[] | undefined
>(() =>
@@ -107,105 +141,52 @@ export function useCatalogGraphPage({
? query.selectedRelations
: initialState?.selectedRelations,
);
const [selectedKinds, setSelectedKinds] = useState<string[] | undefined>(() =>
(Array.isArray(query.selectedKinds)
? query.selectedKinds
: initialState?.selectedKinds
)?.map(k => k.toLocaleLowerCase('en-US')),
);
const [unidirectional, setUnidirectional] = useState<boolean>(() =>
typeof query.unidirectional === 'string'
? query.unidirectional === 'true'
: initialState?.unidirectional ?? true,
);
const [mergeRelations, setMergeRelations] = useState<boolean>(() =>
typeof query.mergeRelations === 'string'
? query.mergeRelations === 'true'
: initialState?.mergeRelations ?? true,
);
const [direction, setDirection] = useState<Direction>(() =>
typeof query.direction === 'string'
? query.direction
: initialState?.direction ?? Direction.LEFT_RIGHT,
);
const [curve, setCurve] = useState<'curveStepBefore' | 'curveMonotoneX'>(() =>
typeof query.curve === 'string'
? query.curve
: initialState?.curve ?? 'curveMonotoneX',
);
const [showFilters, setShowFilters] = useState<boolean>(() =>
typeof query.showFilters === 'string'
? query.showFilters === 'true'
: initialState?.showFilters ?? true,
);
const toggleShowFilters = useCallback(
() => setShowFilters(s => !s),
[setShowFilters],
);
// Update from query parameters
const prevQueryParams = usePrevious(location.search);
useEffect(() => {
// Only respond to changes to url query params
if (location.search === prevQueryParams) {
return;
}
if (Array.isArray(query.rootEntityRefs)) {
setRootEntityNames(query.rootEntityRefs.map(r => parseEntityRef(r)));
}
if (typeof query.maxDepth === 'string') {
setMaxDepth(parseMaxDepth(query.maxDepth));
}
if (Array.isArray(query.selectedKinds)) {
setSelectedKinds(query.selectedKinds);
}
if (Array.isArray(query.selectedRelations)) {
setSelectedRelations(query.selectedRelations);
}
if (typeof query.unidirectional === 'string') {
setUnidirectional(query.unidirectional === 'true');
}
if (typeof query.mergeRelations === 'string') {
setMergeRelations(query.mergeRelations === 'true');
}
if (typeof query.direction === 'string') {
setDirection(query.direction);
}
if (typeof query.showFilters === 'string') {
setShowFilters(query.showFilters === 'true');
}
}, [
prevQueryParams,
location.search,
query,
setRootEntityNames,
setMaxDepth,
setSelectedKinds,
setSelectedRelations,
setUnidirectional,
setMergeRelations,
setDirection,
setShowFilters,
]);
// Update query parameters
const previousRootEntityRefs = usePrevious(
rootEntityNames.map(e => stringifyEntityRef(e)),
);
useEffect(() => {
const rootEntityRefs = rootEntityNames.map(e => stringifyEntityRef(e));
const newParams = qs.stringify(
{
rootEntityRefs,
maxDepth: isFinite(maxDepth) ? maxDepth : '∞',
selectedKinds,
selectedRelations,
@@ -213,36 +194,33 @@ export function useCatalogGraphPage({
mergeRelations,
direction,
showFilters,
curve,
},
{ arrayFormat: 'brackets', addQueryPrefix: true },
);
const newUrl = `${window.location.pathname}${newParams}`;
// We directly manipulate window history here in order to not re-render
// infinitely (state => location => state => etc). The intention of this
// code is just to ensure the right query/filters are loaded when a user
// clicks the "back" button after clicking a result.
// Only push a new history entry if we switched to another entity, but not
// if we just changed a viewer setting.
if (
!previousRootEntityRefs ||
(rootEntityRefs.length === previousRootEntityRefs.length &&
rootEntityRefs.every((v, i) => v === previousRootEntityRefs[i]))
) {
window.history.replaceState(null, document.title, newUrl);
} else {
window.history.pushState(null, document.title, newUrl);
}
const searchParams = new URLSearchParams(newParams);
setSearchParams(
params => {
searchParams.forEach((value, key) => {
params.set(key, value);
});
return params;
},
{ replace: true },
);
}, [
rootEntityNames,
maxDepth,
curve,
selectedKinds,
selectedRelations,
unidirectional,
mergeRelations,
direction,
showFilters,
previousRootEntityRefs,
setSearchParams,
]);
return {