catalog-graph: fix navigation in catalog graph page
Signed-off-by: Mahendra Suthar <mahendra.suthar.1290@gmail.com>
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user