@databiosphere/findable-ui 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/lib/components/Table/table.js +1 -1
  2. package/lib/components/common/AnchorLink/anchorLink.styles.js +1 -0
  3. package/lib/config/entities.d.ts +10 -3
  4. package/lib/hooks/useEntityList.js +1 -1
  5. package/lib/hooks/useSessionTimeout.js +9 -2
  6. package/lib/providers/exploreState/entities.d.ts +19 -0
  7. package/lib/providers/exploreState/entities.js +2 -0
  8. package/lib/providers/exploreState/initializer/constants.d.ts +5 -0
  9. package/lib/providers/exploreState/initializer/constants.js +32 -0
  10. package/lib/providers/exploreState/initializer/utils.d.ts +12 -0
  11. package/lib/providers/exploreState/initializer/utils.js +116 -0
  12. package/lib/providers/exploreState/utils.d.ts +37 -22
  13. package/lib/providers/exploreState/utils.js +64 -65
  14. package/lib/providers/exploreState.d.ts +4 -21
  15. package/lib/providers/exploreState.js +23 -22
  16. package/lib/views/ExploreView/exploreView.js +6 -6
  17. package/package.json +1 -1
  18. package/src/components/Table/table.tsx +1 -1
  19. package/src/components/common/AnchorLink/anchorLink.styles.ts +1 -0
  20. package/src/config/entities.ts +11 -3
  21. package/src/hooks/useEntityList.ts +1 -1
  22. package/src/hooks/useSessionTimeout.ts +9 -3
  23. package/src/providers/exploreState/entities.ts +32 -0
  24. package/src/providers/exploreState/{constants.ts → initializer/constants.ts} +8 -3
  25. package/src/providers/exploreState/initializer/utils.ts +183 -0
  26. package/src/providers/exploreState/utils.ts +103 -92
  27. package/src/providers/exploreState.tsx +50 -81
  28. package/src/views/ExploreView/exploreView.tsx +8 -8
@@ -1,114 +1,64 @@
1
1
  import { SelectedFilter } from "../../common/entities";
2
- import { getInitialTableColumnVisibility } from "../../components/Table/common/utils";
3
- import {
4
- CategoryConfig,
5
- CategoryGroupConfig,
6
- SiteConfig,
7
- } from "../../config/entities";
8
- import { getDefaultSorting } from "../../config/utils";
2
+ import { CategoryConfig } from "../../config/entities";
3
+ import { ExploreState, PaginationState } from "../exploreState";
9
4
  import {
5
+ CategoryGroupConfigKey,
6
+ EntityPageState,
10
7
  EntityPageStateMapper,
11
- ENTITY_VIEW,
12
- ExploreState,
13
- PaginationState,
14
- } from "../exploreState";
15
- import { INITIAL_STATE } from "./constants";
8
+ EntityState,
9
+ } from "./entities";
10
+ import { DEFAULT_ENTITY_STATE } from "./initializer/constants";
16
11
 
17
12
  /**
18
- * Returns the filter count.
19
- * @param filterState - Filter state.
20
- * @returns filter count.
13
+ * Returns the category group config key for the current entity.
14
+ * @param entityPath - Entity path.
15
+ * @param entityPageState - Entity page state mapper.
16
+ * @returns category group config key.
21
17
  */
22
- export function getFilterCount(filterState: SelectedFilter[]): number {
23
- return filterState.reduce((acc, filter) => acc + filter.value.length, 0);
18
+ export function getEntityCategoryGroupConfigKey(
19
+ entityPath: string,
20
+ entityPageState: EntityPageStateMapper
21
+ ): CategoryGroupConfigKey {
22
+ return entityPageState[entityPath].categoryGroupConfigKey;
24
23
  }
25
24
 
26
25
  /**
27
- * Returns the initial explore state.
28
- * @param config - Site config.
29
- * @param entityListType - Entity list type.
30
- * @param decodedFilterParam - Decoded filter parameter.
31
- * @param decodedCatalogParam - Decoded catalog parameter.
32
- * @param decodedFeatureFlagParam - Decoded feature flag parameter.
33
- * @returns explore state.
26
+ * Returns the category configs for the current entity.
27
+ * @param state - Explore state.
28
+ * @returns category configs.
34
29
  */
35
- export function initExploreState(
36
- config: SiteConfig,
37
- entityListType: string,
38
- decodedFilterParam: string,
39
- decodedCatalogParam?: string,
40
- decodedFeatureFlagParam?: string
41
- ): ExploreState {
42
- const entityPageState = initEntityPageState(config);
43
- const filterState = initFilterState(decodedFilterParam);
44
- const filterCount = getFilterCount(filterState);
45
- return {
46
- ...INITIAL_STATE,
47
- catalogState: decodedCatalogParam,
48
- categoryGroupConfigs: entityPageState[entityListType].categoryGroupConfigs,
49
- entityPageState: initEntityPageState(config),
50
- featureFlagState: decodedFeatureFlagParam,
51
- filterCount,
52
- filterState,
53
- listView: ENTITY_VIEW.EXACT,
54
- tabValue: entityListType,
55
- };
56
- }
57
-
58
- /**
59
- * Returns configured grouped configured categories as a list of configured categories.
60
- * @param categoryGroupConfigs - Configured category groups.
61
- * @returns a list of configured categories.
62
- */
63
- function flattenCategoryGroupConfigs(
64
- categoryGroupConfigs?: CategoryGroupConfig[]
30
+ export function getEntityCategoryConfigs(
31
+ state: ExploreState
65
32
  ): CategoryConfig[] | undefined {
66
- return categoryGroupConfigs?.flatMap(
67
- ({ categoryConfigs }) => categoryConfigs
68
- );
33
+ return getEntityState(
34
+ getEntityCategoryGroupConfigKey(state.tabValue, state.entityPageState),
35
+ state
36
+ ).categoryConfigs;
69
37
  }
70
38
 
71
39
  /**
72
- * Initializes filter state from URL "filter" parameter.
73
- * @param decodedFilterParam - Decoded filter parameter.
74
- * @returns filter state.
40
+ * Returns the entity state for the given category group config key.
41
+ * @param categoryGroupConfigKey - Category group config key.
42
+ * @param state - Explore state.
43
+ * @returns entity state.
75
44
  */
76
- export function initFilterState(decodedFilterParam: string): SelectedFilter[] {
77
- // Define filter state, from URL "filter" parameter, if present and valid.
78
- let filterState: SelectedFilter[] = [];
79
- try {
80
- filterState = JSON.parse(decodedFilterParam);
81
- } catch {
82
- // do nothing
83
- }
84
- return filterState;
45
+ export function getEntityState(
46
+ categoryGroupConfigKey: CategoryGroupConfigKey,
47
+ state: ExploreState
48
+ ): EntityState {
49
+ return (
50
+ state.entityStateByCategoryGroupConfigKey.get(categoryGroupConfigKey) ||
51
+ DEFAULT_ENTITY_STATE
52
+ );
85
53
  }
86
54
 
87
55
  /**
88
- * Initializes entity page state.
89
- * @param config - Site config.
90
- * @returns entity page state.
56
+ * Returns the filter count.
57
+ * @param filterState - Filter state.
58
+ * @returns filter count.
91
59
  */
92
- export function initEntityPageState(config: SiteConfig): EntityPageStateMapper {
93
- const { categoryGroupConfigs } = config;
94
- return config.entities.reduce(
95
- (acc, entity) => ({
96
- ...acc,
97
- [entity.route]: {
98
- categoryConfigs: flattenCategoryGroupConfigs(
99
- entity.categoryGroupConfigs ?? categoryGroupConfigs
100
- ),
101
- categoryGroupConfigs:
102
- entity.categoryGroupConfigs ?? categoryGroupConfigs,
103
- categoryViews: [],
104
- columnsVisibility: getInitialTableColumnVisibility(entity.list.columns),
105
- filterCount: 0,
106
- filterState: [],
107
- sorting: getDefaultSorting(entity),
108
- },
109
- }),
110
- {}
111
- );
60
+ export function getFilterCount(filterState: SelectedFilter[]): number {
61
+ return filterState.reduce((acc, filter) => acc + filter.value.length, 0);
112
62
  }
113
63
 
114
64
  /**
@@ -122,3 +72,64 @@ export function resetPage(paginationState: PaginationState): PaginationState {
122
72
  nextPaginationState.currentPage = 1;
123
73
  return nextPaginationState;
124
74
  }
75
+
76
+ /**
77
+ * Sets entity state for the given category group config key.
78
+ * @param categoryGroupConfigKey - Category group config key.
79
+ * @param state - Explore state.
80
+ * @param nextEntityState - Next entity state.
81
+ */
82
+ function setEntityStateByCategoryGroupConfigKey(
83
+ categoryGroupConfigKey: CategoryGroupConfigKey,
84
+ state: ExploreState,
85
+ nextEntityState: EntityState
86
+ ): void {
87
+ state.entityStateByCategoryGroupConfigKey.set(
88
+ categoryGroupConfigKey,
89
+ nextEntityState
90
+ );
91
+ }
92
+
93
+ /**
94
+ * Updates entity page state for the given entity path.
95
+ * @param entityPath - Entity path.
96
+ * @param entityPageState - Entity page state.
97
+ * @param nextEntityPageState - Partial next entity page state.
98
+ * @returns updated entity page state.
99
+ */
100
+ export function updateEntityPageState(
101
+ entityPath: string, // entityListType.
102
+ entityPageState: EntityPageStateMapper,
103
+ nextEntityPageState: Partial<EntityPageState>
104
+ ): EntityPageStateMapper {
105
+ return {
106
+ ...entityPageState,
107
+ [entityPath]: {
108
+ ...entityPageState[entityPath],
109
+ ...nextEntityPageState,
110
+ },
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Updates entity state by category group config key.
116
+ * @param state - Explore state.
117
+ * @param nextEntityState - Partial next entity state.
118
+ * @returns updated entity state by category group config key.
119
+ */
120
+ export function updateEntityStateByCategoryGroupConfigKey(
121
+ state: ExploreState,
122
+ nextEntityState: Partial<EntityState>
123
+ ): void {
124
+ const categoryGroupConfigKey = getEntityCategoryGroupConfigKey(
125
+ state.tabValue,
126
+ state.entityPageState
127
+ );
128
+ const entityState = getEntityState(categoryGroupConfigKey, state);
129
+ if (entityState) {
130
+ setEntityStateByCategoryGroupConfigKey(categoryGroupConfigKey, state, {
131
+ ...entityState,
132
+ ...nextEntityState,
133
+ });
134
+ }
135
+ }
@@ -1,4 +1,3 @@
1
- import { ColumnSort } from "@tanstack/react-table";
2
1
  import React, {
3
2
  createContext,
4
3
  Dispatch,
@@ -10,12 +9,7 @@ import React, {
10
9
  } from "react";
11
10
  import { AzulSearchIndex } from "../apis/azul/common/entities";
12
11
  import { SelectCategory, SelectedFilter } from "../common/entities";
13
- import {
14
- CategoryConfig,
15
- CategoryGroupConfig,
16
- EntityPath,
17
- SiteConfig,
18
- } from "../config/entities";
12
+ import { CategoryGroup, SiteConfig } from "../config/entities";
19
13
  import { useAuthentication } from "../hooks/useAuthentication/useAuthentication";
20
14
  import {
21
15
  buildCategoryViews,
@@ -23,10 +17,15 @@ import {
23
17
  } from "../hooks/useCategoryFilter";
24
18
  import { useConfig } from "../hooks/useConfig";
25
19
  import { useURLFilterParams } from "../hooks/useURLFilterParams";
20
+ import {
21
+ EntityPageStateMapper,
22
+ EntityStateByCategoryGroupConfigKey,
23
+ } from "./exploreState/entities";
26
24
  import {
27
25
  DEFAULT_PAGINATION_STATE,
28
26
  INITIAL_STATE,
29
- } from "./exploreState/constants";
27
+ } from "./exploreState/initializer/constants";
28
+ import { initReducerArguments } from "./exploreState/initializer/utils";
30
29
  import {
31
30
  PaginateTablePayload,
32
31
  ProcessExploreResponsePayload,
@@ -38,9 +37,13 @@ import {
38
37
  UpdateSortingPayload,
39
38
  } from "./exploreState/payloads/entities";
40
39
  import {
40
+ getEntityCategoryConfigs,
41
+ getEntityCategoryGroupConfigKey,
42
+ getEntityState,
41
43
  getFilterCount,
42
- initExploreState,
43
44
  resetPage,
45
+ updateEntityPageState,
46
+ updateEntityStateByCategoryGroupConfigKey,
44
47
  } from "./exploreState/utils";
45
48
 
46
49
  export type CatalogState = string | undefined;
@@ -61,34 +64,15 @@ export interface ExploreContext {
61
64
  entityList: string;
62
65
  }
63
66
 
64
- /**
65
- * State for each entity.
66
- */
67
- export interface EntityPageState {
68
- categoryConfigs?: CategoryConfig[];
69
- categoryGroupConfigs?: CategoryGroupConfig[];
70
- categoryViews: SelectCategory[];
71
- columnsVisibility: Record<string, boolean>;
72
- filterCount: number;
73
- filterState: SelectedFilter[];
74
- sorting: ColumnSort[];
75
- }
76
-
77
- /**
78
- * State for all entities.
79
- */
80
- export interface EntityPageStateMapper {
81
- [key: EntityPath]: EntityPageState;
82
- }
83
-
84
67
  /**
85
68
  * Explore state.
86
69
  */
87
70
  export type ExploreState = {
88
71
  catalogState: CatalogState;
89
- categoryGroupConfigs?: CategoryGroupConfig[];
72
+ categoryGroups?: CategoryGroup[];
90
73
  categoryViews: SelectCategory[];
91
74
  entityPageState: EntityPageStateMapper;
75
+ entityStateByCategoryGroupConfigKey: EntityStateByCategoryGroupConfigKey;
92
76
  featureFlagState: FeatureFlagState;
93
77
  filterCount: number;
94
78
  filterState: SelectedFilter[];
@@ -190,8 +174,8 @@ export function ExploreStateProvider({
190
174
  useURLFilterParams();
191
175
  const { isEnabled: isAuthEnabled, token } = useAuthentication();
192
176
  const entityList = entityListType || defaultEntityListType;
193
- const [initReducerState] = useState(() =>
194
- initExploreState(
177
+ const [initializerArg] = useState(() =>
178
+ initReducerArguments(
195
179
  config,
196
180
  entityList,
197
181
  decodedFilterParam,
@@ -206,7 +190,7 @@ export function ExploreStateProvider({
206
190
  config,
207
191
  entityList,
208
192
  }),
209
- initReducerState
193
+ initializerArg
210
194
  );
211
195
 
212
196
  // does this help? https://hswolff.com/blog/how-to-usecontext-with-usereducer/
@@ -371,10 +355,13 @@ function exploreReducer(
371
355
  * Clear all filters
372
356
  **/
373
357
  case ExploreActionKind.ClearFilters: {
358
+ const filterCount = 0;
359
+ const filterState: SelectedFilter[] = [];
360
+ updateEntityStateByCategoryGroupConfigKey(state, { filterState });
374
361
  return {
375
362
  ...state,
376
- filterCount: 0,
377
- filterState: [],
363
+ filterCount,
364
+ filterState,
378
365
  paginationState: resetPage(state.paginationState),
379
366
  };
380
367
  }
@@ -399,27 +386,19 @@ function exploreReducer(
399
386
  * Process explore response
400
387
  **/
401
388
  case ExploreActionKind.ProcessExploreResponse: {
402
- const { entityPageState, tabValue } = state;
403
- const { categoryConfigs, categoryViews, filterState } =
404
- entityPageState[tabValue];
405
389
  const nextCategoryViews = payload.selectCategories
406
390
  ? buildCategoryViews(
407
391
  payload.selectCategories,
408
- categoryConfigs,
409
- filterState
392
+ getEntityCategoryConfigs(state),
393
+ state.filterState
410
394
  )
411
- : undefined;
395
+ : state.categoryViews;
396
+ updateEntityStateByCategoryGroupConfigKey(state, {
397
+ categoryViews: nextCategoryViews,
398
+ });
412
399
  return {
413
400
  ...state,
414
- categoryGroupConfigs: entityPageState[tabValue].categoryGroupConfigs,
415
- categoryViews: nextCategoryViews ?? categoryViews,
416
- entityPageState: {
417
- ...entityPageState,
418
- [tabValue]: {
419
- ...entityPageState[tabValue],
420
- categoryViews: nextCategoryViews ?? categoryViews,
421
- },
422
- },
401
+ categoryViews: nextCategoryViews,
423
402
  listItems: payload.loading ? [] : payload.listItems,
424
403
  loading: payload.loading,
425
404
  paginationState: {
@@ -452,7 +431,7 @@ function exploreReducer(
452
431
  * Reset the current state to the initial
453
432
  */
454
433
  case ExploreActionKind.ResetState: {
455
- return initExploreState(config, entityList, "");
434
+ return initReducerArguments(config, entityList, "");
456
435
  }
457
436
  /**
458
437
  * Select entity type
@@ -461,10 +440,16 @@ function exploreReducer(
461
440
  if (payload === state.tabValue) {
462
441
  return state;
463
442
  }
443
+ const entityState = getEntityState(
444
+ getEntityCategoryGroupConfigKey(payload, state.entityPageState),
445
+ state
446
+ );
464
447
  return {
465
448
  ...state,
466
- filterCount: state.entityPageState[payload].filterCount,
467
- filterState: state.entityPageState[payload].filterState,
449
+ categoryGroups: entityState.categoryGroups,
450
+ categoryViews: entityState.categoryViews,
451
+ filterCount: getFilterCount(entityState.filterState),
452
+ filterState: entityState.filterState,
468
453
  listItems: [],
469
454
  loading: true,
470
455
  paginationState: resetPage(state.paginationState),
@@ -491,18 +476,10 @@ function exploreReducer(
491
476
  payload.selectedValue,
492
477
  payload.selected
493
478
  );
494
- const filterCount = getFilterCount(filterState);
479
+ updateEntityStateByCategoryGroupConfigKey(state, { filterState });
495
480
  return {
496
481
  ...state,
497
- entityPageState: {
498
- ...state.entityPageState,
499
- [state.tabValue]: {
500
- ...state.entityPageState[state.tabValue],
501
- filterCount,
502
- filterState,
503
- },
504
- },
505
- filterCount,
482
+ filterCount: getFilterCount(filterState),
506
483
  filterState,
507
484
  paginationState: resetPage(state.paginationState),
508
485
  };
@@ -511,17 +488,13 @@ function exploreReducer(
511
488
  * Update sorting
512
489
  **/
513
490
  case ExploreActionKind.UpdateSorting: {
514
- const currentEntity = state.tabValue;
515
- const currentPageState = state.entityPageState[currentEntity];
516
491
  return {
517
492
  ...state,
518
- entityPageState: {
519
- ...state.entityPageState,
520
- [currentEntity]: {
521
- ...currentPageState,
522
- sorting: payload,
523
- },
524
- },
493
+ entityPageState: updateEntityPageState(
494
+ state.tabValue,
495
+ state.entityPageState,
496
+ { sorting: payload }
497
+ ),
525
498
  paginationState: resetPage(state.paginationState),
526
499
  };
527
500
  }
@@ -529,17 +502,13 @@ function exploreReducer(
529
502
  * Update column visibility
530
503
  **/
531
504
  case ExploreActionKind.UpdateColumnVisibility: {
532
- const currentEntity = state.tabValue;
533
- const currentPageState = state.entityPageState[currentEntity];
534
505
  return {
535
506
  ...state,
536
- entityPageState: {
537
- ...state.entityPageState,
538
- [currentEntity]: {
539
- ...currentPageState,
540
- columnsVisibility: payload,
541
- },
542
- },
507
+ entityPageState: updateEntityPageState(
508
+ state.tabValue,
509
+ state.entityPageState,
510
+ { columnsVisibility: payload }
511
+ ),
543
512
  };
544
513
  }
545
514
 
@@ -26,7 +26,7 @@ import { SidebarTools } from "../../components/Layout/components/Sidebar/compone
26
26
  import { Sidebar } from "../../components/Layout/components/Sidebar/sidebar";
27
27
  import { TableCreator } from "../../components/TableCreator/tableCreator";
28
28
  import {
29
- CategoryGroupConfig,
29
+ CategoryGroup,
30
30
  ComponentsConfig,
31
31
  EntityConfig,
32
32
  SummaryConfig,
@@ -70,7 +70,7 @@ export const ExploreView = (props: ExploreViewProps): JSX.Element => {
70
70
  const { listView } = entityConfig;
71
71
  const { listHero, subTitleHero } = listView || {};
72
72
  const {
73
- categoryGroupConfigs,
73
+ categoryGroups,
74
74
  categoryViews,
75
75
  filterCount,
76
76
  isRelatedView,
@@ -83,8 +83,8 @@ export const ExploreView = (props: ExploreViewProps): JSX.Element => {
83
83
  useEntityListRelatedView(); // Fetch related entities.
84
84
  const { entityListType } = props;
85
85
  const categoryFilters = useMemo(
86
- () => buildCategoryFilters(categoryViews, categoryGroupConfigs),
87
- [categoryViews, categoryGroupConfigs]
86
+ () => buildCategoryFilters(categoryViews, categoryGroups),
87
+ [categoryGroups, categoryViews]
88
88
  );
89
89
 
90
90
  /**
@@ -216,17 +216,17 @@ export const ExploreView = (props: ExploreViewProps): JSX.Element => {
216
216
  /**
217
217
  * Builds the category views into category views grouped by the given category group configuration.
218
218
  * @param selectCategoryViews - View models of categories to display.
219
- * @param categoryGroupConfigs - Category group configuration.
219
+ * @param categoryGroups - Category groups.
220
220
  * @returns category filters.
221
221
  */
222
222
  function buildCategoryFilters(
223
223
  selectCategoryViews: SelectCategoryView[],
224
- categoryGroupConfigs?: CategoryGroupConfig[]
224
+ categoryGroups?: CategoryGroup[]
225
225
  ): CategoryFilter[] {
226
- if (!categoryGroupConfigs) {
226
+ if (!categoryGroups) {
227
227
  return [{ categoryViews: selectCategoryViews }];
228
228
  }
229
- return categoryGroupConfigs.map(({ categoryConfigs, label }) => {
229
+ return categoryGroups.map(({ categoryConfigs, label }) => {
230
230
  // Grab the category views for the configured grouped categories.
231
231
  const categoryViews = categoryConfigs.reduce(
232
232
  (acc, { key: categoryKey }) => {