From dd696296255d8e232054b65054c90a9e6c538bfa Mon Sep 17 00:00:00 2001 From: Tim Hansen Date: Mon, 21 Jun 2021 11:28:09 -0600 Subject: [PATCH] Use query params with useEntityListProvider Signed-off-by: Tim Hansen --- .../EntityKindPicker/EntityKindPicker.tsx | 7 +++++-- plugins/catalog-react/src/filters.ts | 4 ++++ .../src/hooks/useEntityListProvider.tsx | 21 +++++++++++++++++++ plugins/catalog-react/src/types.ts | 7 +++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx index 92831ea252..5b3f95b7ba 100644 --- a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx +++ b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx @@ -28,8 +28,11 @@ export const EntityKindPicker = ({ initialFilter, hidden, }: EntityKindFilterProps) => { - const [selectedKind] = useState(initialFilter); - const { updateFilters } = useEntityListProvider(); + const { updateFilters, queryParameters } = useEntityListProvider(); + const [selectedKind] = useState( + // TODO Cast here is not great 🤔 + (queryParameters.kind as string) ?? initialFilter, + ); useEffect(() => { updateFilters({ diff --git a/plugins/catalog-react/src/filters.ts b/plugins/catalog-react/src/filters.ts index 9b57e0f560..2b23031cc9 100644 --- a/plugins/catalog-react/src/filters.ts +++ b/plugins/catalog-react/src/filters.ts @@ -29,6 +29,10 @@ export class EntityKindFilter implements EntityFilter { getCatalogFilters(): Record { return { kind: this.value }; } + + toQueryValue(): string { + return this.value; + } } export class EntityTypeFilter implements EntityFilter { diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index 33c951acce..253184a851 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -77,6 +77,11 @@ export type EntityListContextProps< | ((prevFilters: EntityFilters) => Partial), ) => void; + /** + * Filter values from query parameters. + */ + queryParameters: Record; + loading: boolean; error?: Error; }; @@ -89,6 +94,7 @@ type OutputState = { appliedFilters: EntityFilters; entities: Entity[]; backendEntities: Entity[]; + queryParameters: Record; }; export const EntityListProvider = ({ @@ -102,6 +108,7 @@ export const EntityListProvider = ({ appliedFilters: {} as EntityFilters, entities: [], backendEntities: [], + queryParameters: {}, // TODO: Load (once!!) from query parameters }); // The main async filter worker. Note that while it has a lot of dependencies @@ -116,6 +123,15 @@ export const EntityListProvider = ({ compact(Object.values(outputState.appliedFilters)), ); + const queryParams = Object.keys(requestedFilters).reduce((params, key) => { + const filter: EntityFilter | undefined = + requestedFilters[key as keyof EntityFilters]; + if (filter?.toQueryValue) { + params[key] = filter.toQueryValue(); + } + return params; + }, {} as Record); + // TODO(mtlewis): currently entities will never be requested unless // there's at least one filter, we should allow an initial request // to happen with no filters. @@ -129,14 +145,18 @@ export const EntityListProvider = ({ appliedFilters: requestedFilters, backendEntities: response.items, entities: response.items.filter(entityFilter), + queryParameters: queryParams, }); } else { setOutputState({ appliedFilters: requestedFilters, backendEntities: outputState.backendEntities, entities: outputState.backendEntities.filter(entityFilter), + queryParameters: queryParams, }); } + + // TODO: write queryParams to query string }, [catalogApi, requestedFilters, outputState], { loading: true }, @@ -168,6 +188,7 @@ export const EntityListProvider = ({ entities: outputState.entities, backendEntities: outputState.backendEntities, updateFilters, + queryParameters: outputState.queryParameters, loading, error, }} diff --git a/plugins/catalog-react/src/types.ts b/plugins/catalog-react/src/types.ts index 68c11d7f38..4ac7644ee1 100644 --- a/plugins/catalog-react/src/types.ts +++ b/plugins/catalog-react/src/types.ts @@ -34,6 +34,13 @@ export type EntityFilter = { * @param env */ filterEntity?: (entity: Entity) => boolean; + + /** + * Serialize the filter value to a string for query params. The UI component responsible for + * handling this filter should retrieve this from useEntityListProvider.queryParameters. The + * value restored should be in the precedence: queryParameters > initialValue prop > default. + */ + toQueryValue?: () => string | string[]; }; export type UserListFilterKind = 'owned' | 'starred' | 'all';