@databiosphere/findable-ui 0.0.0 → 1.0.0

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 (27) hide show
  1. package/README.md +11 -11
  2. package/lib/apis/azul/common/entities.d.ts +2 -1
  3. package/lib/apis/azul/common/entities.js +1 -0
  4. package/lib/components/Export/components/ExportToTerra/exportToTerra.d.ts +1 -1
  5. package/lib/components/Layout/components/ContentLayout/common/constants.d.ts +1 -0
  6. package/lib/components/Layout/components/ContentLayout/common/constants.js +6 -1
  7. package/lib/components/Layout/components/ContentLayout/contentLayout.styles.js +1 -0
  8. package/lib/hooks/useEntityList.js +3 -3
  9. package/lib/hooks/useURLFilterParams.d.ts +3 -2
  10. package/lib/hooks/useURLFilterParams.js +10 -6
  11. package/lib/hooks/useUpdateURLSearchParams.js +3 -3
  12. package/lib/providers/exploreState/constants.js +1 -0
  13. package/lib/providers/exploreState/utils.d.ts +2 -1
  14. package/lib/providers/exploreState/utils.js +3 -2
  15. package/lib/providers/exploreState.d.ts +2 -0
  16. package/lib/providers/exploreState.js +2 -2
  17. package/package.json +1 -1
  18. package/src/apis/azul/common/entities.ts +1 -0
  19. package/src/components/Export/components/ExportToTerra/exportToTerra.tsx +1 -1
  20. package/src/components/Layout/components/ContentLayout/common/constants.ts +6 -0
  21. package/src/components/Layout/components/ContentLayout/contentLayout.styles.ts +1 -0
  22. package/src/hooks/useEntityList.ts +9 -3
  23. package/src/hooks/useURLFilterParams.ts +14 -4
  24. package/src/hooks/useUpdateURLSearchParams.ts +3 -3
  25. package/src/providers/exploreState/constants.ts +1 -0
  26. package/src/providers/exploreState/utils.ts +4 -1
  27. package/src/providers/exploreState.tsx +7 -2
package/README.md CHANGED
@@ -1,19 +1,19 @@
1
- # data-explorer-ui
1
+ # findable-ui
2
2
 
3
3
  ## General info
4
4
 
5
5
  - `src` contains TypeScript source files; `lib` will contain compiled JavaScript, which is what should be imported by
6
6
  the external application.
7
7
  - Import paths used by the external application need to specify the full path starting from the package name,
8
- in the form `@clevercanary/data-explorer-ui/lib/<path>`, where `<path>` is the path of the file within the `lib`
8
+ in the form `@databiosphere/findable-ui/lib/<path>`, where `<path>` is the path of the file within the `lib`
9
9
  folder.
10
10
 
11
- ## Developing the Clever Canary Data Explorer alongside Clever Canary Data Browser
11
+ ## Developing Findable UI alongside Data Biosphere Data Browser
12
12
 
13
13
  1. Clone this repository into the same parent folder as
14
- the [Clever Canary Data Browser](https://github.com/clevercanary/data-browser).
15
- 2. Set `node` version to `16.15.0` (this is also the version used by the Data Browser).
16
- 3. In the Data Explorer `packages/data-explorer-ui` directory (e.g. `data-explorer/packages/data-explorer-ui`):
14
+ the [Data Biosphere Data Browser](https://github.com/DataBiosphere/data-browser).
15
+ 2. Set `node` version to `20.10.0` (this is also the version used by the Data Browser).
16
+ 3. In the `findable-ui` repository directory:
17
17
  - Run `npm ci`.
18
18
  - [Bump the version number](https://docs.npmjs.com/cli/v6/commands/npm-version) in `package.json`
19
19
  e.g. `npm version <update_type>`.
@@ -23,9 +23,9 @@
23
23
  in VS Code so that it can be done with a keyboard shortcut).
24
24
  4. In the Data Browser `explorer` directory (e.g. `data-browser/explorer`):
25
25
  - Run `npm ci`.
26
- - Update the `@clevercanary/data-explorer-ui` dependency in the `package.json` file to use the new version
27
- of `data-explorer-ui`.
28
- - Run `npm link ../../data-explorer/packages/data-explorer-ui`, which will create a symlink in node_modules pointing
29
- to data-explorer-ui.
26
+ - Update the `@databiosphere/findable-ui` dependency in the `package.json` file to use the new version
27
+ of Findable UI.
28
+ - Run `npm link ../../findable-ui`, which will create a symlink in node_modules pointing
29
+ to findable-ui.
30
30
  - If any packages are later installed or uninstalled, the symlink will need to be created again, which can be done
31
- with the same command or by running `npm link @clevercanary/data-explorer-ui`.
31
+ with the same command or by running `npm link @databiosphere/findable-ui`.
@@ -156,6 +156,7 @@ export declare enum MANIFEST_DOWNLOAD_FORMAT {
156
156
  "CURL" = "curl",
157
157
  "FULL" = "full",
158
158
  "TERRA_BDBAG" = "terra.bdbag",
159
- "TERRA_PFB" = "terra.pfb"
159
+ "TERRA_PFB" = "terra.pfb",
160
+ "VERBATIM_PFB" = "verbatim.pfb"
160
161
  }
161
162
  export {};
@@ -54,4 +54,5 @@ var MANIFEST_DOWNLOAD_FORMAT;
54
54
  MANIFEST_DOWNLOAD_FORMAT["FULL"] = "full";
55
55
  MANIFEST_DOWNLOAD_FORMAT["TERRA_BDBAG"] = "terra.bdbag";
56
56
  MANIFEST_DOWNLOAD_FORMAT["TERRA_PFB"] = "terra.pfb";
57
+ MANIFEST_DOWNLOAD_FORMAT["VERBATIM_PFB"] = "verbatim.pfb";
57
58
  })(MANIFEST_DOWNLOAD_FORMAT = exports.MANIFEST_DOWNLOAD_FORMAT || (exports.MANIFEST_DOWNLOAD_FORMAT = {}));
@@ -12,7 +12,7 @@ export interface ExportToTerraProps {
12
12
  fileSummaryFacetName: string;
13
13
  filters: Filters;
14
14
  formFacet: FormFacet;
15
- manifestDownloadFormat: ManifestDownloadFormat;
15
+ manifestDownloadFormat?: ManifestDownloadFormat;
16
16
  manifestDownloadFormats: ManifestDownloadFormat[];
17
17
  }
18
18
  export declare const ExportToTerra: ({ ExportForm, ExportToTerraStart, ExportToTerraSuccess, fileManifestState, fileSummaryFacetName, filters, formFacet, manifestDownloadFormat, manifestDownloadFormats, }: ExportToTerraProps) => JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { LayoutStyle } from "./entities";
2
2
  export declare const LAYOUT_STYLE_CONTRAST_LIGHT: LayoutStyle;
3
3
  export declare const LAYOUT_STYLE_CONTRAST_LIGHTEST: LayoutStyle;
4
+ export declare const LAYOUT_STYLE_NO_CONTRAST_DEFAULT: LayoutStyle;
4
5
  export declare const LAYOUT_STYLE_NO_CONTRAST_LIGHT: LayoutStyle;
5
6
  export declare const LAYOUT_STYLE_NO_CONTRAST_LIGHTEST: LayoutStyle;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.LAYOUT_STYLE_NO_CONTRAST_LIGHTEST = exports.LAYOUT_STYLE_NO_CONTRAST_LIGHT = exports.LAYOUT_STYLE_CONTRAST_LIGHTEST = exports.LAYOUT_STYLE_CONTRAST_LIGHT = void 0;
3
+ exports.LAYOUT_STYLE_NO_CONTRAST_LIGHTEST = exports.LAYOUT_STYLE_NO_CONTRAST_LIGHT = exports.LAYOUT_STYLE_NO_CONTRAST_DEFAULT = exports.LAYOUT_STYLE_CONTRAST_LIGHTEST = exports.LAYOUT_STYLE_CONTRAST_LIGHT = void 0;
4
4
  const entities_1 = require("./entities");
5
5
  exports.LAYOUT_STYLE_CONTRAST_LIGHT = {
6
6
  content: entities_1.PANEL_BACKGROUND_COLOR.DEFAULT,
@@ -12,6 +12,11 @@ exports.LAYOUT_STYLE_CONTRAST_LIGHTEST = {
12
12
  navigation: entities_1.PANEL_BACKGROUND_COLOR.SMOKE_LIGHTEST,
13
13
  outline: entities_1.PANEL_BACKGROUND_COLOR.DEFAULT,
14
14
  };
15
+ exports.LAYOUT_STYLE_NO_CONTRAST_DEFAULT = {
16
+ content: entities_1.PANEL_BACKGROUND_COLOR.DEFAULT,
17
+ navigation: entities_1.PANEL_BACKGROUND_COLOR.DEFAULT,
18
+ outline: entities_1.PANEL_BACKGROUND_COLOR.DEFAULT,
19
+ };
15
20
  exports.LAYOUT_STYLE_NO_CONTRAST_LIGHT = {
16
21
  content: entities_1.PANEL_BACKGROUND_COLOR.SMOKE_LIGHT,
17
22
  navigation: entities_1.PANEL_BACKGROUND_COLOR.SMOKE_LIGHT,
@@ -67,6 +67,7 @@ exports.NavigationGrid = styled_1.default.div `
67
67
  exports.ContentGrid = styled_1.default.div `
68
68
  ${content};
69
69
  grid-area: content;
70
+ min-width: 0;
70
71
  `;
71
72
  exports.OutlineGrid = (0, styled_1.default)("div") `
72
73
  ${navigation};
@@ -28,7 +28,7 @@ const useEntityList = (staticResponse) => {
28
28
  const { catalog, entityMapper, fetchAllEntities, fetchEntitiesFromQuery, path, } = (0, useEntityService_1.useEntityService)();
29
29
  const { exploreDispatch, exploreState } = (0, useExploreState_1.useExploreState)();
30
30
  const { data, isIdle, isLoading, run } = (0, useAsync_1.useAsync)();
31
- const { catalogState, entityPageState, filterState, tabValue } = exploreState;
31
+ const { catalogState, entityPageState, featureFlagState, filterState, tabValue, } = exploreState;
32
32
  const { pagination, termFacets } = data || {};
33
33
  const { updateFilterQueryString } = (0, useURLFilterParams_1.useURLFilterParams)();
34
34
  const { sorting } = entityPageState[tabValue];
@@ -37,8 +37,8 @@ const useEntityList = (staticResponse) => {
37
37
  const isFetching = isIdle || isLoading;
38
38
  // Update the filter query string when the filter state changes.
39
39
  (0, react_1.useEffect)(() => {
40
- updateFilterQueryString(catalogState, filterState);
41
- }, [catalogState, filterState, updateFilterQueryString]);
40
+ updateFilterQueryString(catalogState, featureFlagState, filterState);
41
+ }, [catalogState, featureFlagState, filterState, updateFilterQueryString]);
42
42
  // Fetch entities - on change of filter state - server-side fetching and server-side filtering.
43
43
  (0, react_1.useEffect)(() => {
44
44
  var _a, _b;
@@ -1,9 +1,10 @@
1
1
  import { SelectedFilter } from "../common/entities";
2
- import { CatalogState } from "../providers/exploreState";
2
+ import { CatalogState, FeatureFlagState } from "../providers/exploreState";
3
3
  interface UseURLFilterParamsResult {
4
4
  decodedCatalogParam: string | undefined;
5
+ decodedFeatureFlagParam: string | undefined;
5
6
  decodedFilterParam: string;
6
- updateFilterQueryString: (catalogState: CatalogState, filterState: SelectedFilter[]) => void;
7
+ updateFilterQueryString: (catalogState: CatalogState, featureFlagState: FeatureFlagState, filterState: SelectedFilter[]) => void;
7
8
  }
8
9
  /**
9
10
  * useURLFilterParams hook is used to keep track of the url search params, and update them,
@@ -10,28 +10,32 @@ const useLocation_1 = require("./useLocation");
10
10
  * @returns an object containing a update function and the current filter
11
11
  */
12
12
  const useURLFilterParams = () => {
13
- var _a, _b;
13
+ var _a, _b, _c;
14
14
  const { basePath, push } = (0, router_1.useRouter)();
15
15
  const { href, pathname, search } = (0, useLocation_1.useLocation)() || {};
16
- const filterParam = (_a = search === null || search === void 0 ? void 0 : search.get("filter")) !== null && _a !== void 0 ? _a : "[]";
17
- const catalogParam = (_b = search === null || search === void 0 ? void 0 : search.get("catalog")) !== null && _b !== void 0 ? _b : undefined;
18
- const updateFilterQueryString = (0, react_1.useCallback)((catalogState, filterState) => {
16
+ const featureFlagParam = (_a = search === null || search === void 0 ? void 0 : search.get("ff")) !== null && _a !== void 0 ? _a : undefined;
17
+ const filterParam = (_b = search === null || search === void 0 ? void 0 : search.get("filter")) !== null && _b !== void 0 ? _b : "[]";
18
+ const catalogParam = (_c = search === null || search === void 0 ? void 0 : search.get("catalog")) !== null && _c !== void 0 ? _c : undefined;
19
+ const updateFilterQueryString = (0, react_1.useCallback)((catalogState, featureFlagState, filterState) => {
19
20
  if (catalogParam !== catalogState ||
21
+ featureFlagParam !== featureFlagState ||
20
22
  filterParam !== JSON.stringify(filterState)) {
23
+ const featureFlag = featureFlagState ? { ff: featureFlagState } : {};
21
24
  const filter = filterState.length > 0 ? { filter: JSON.stringify(filterState) } : {};
22
25
  const catalog = catalogState ? { catalog: catalogState } : {};
23
26
  push({
24
27
  pathname: pathname === null || pathname === void 0 ? void 0 : pathname.replace(basePath, ""),
25
- query: Object.assign(Object.assign({}, catalog), filter),
28
+ query: Object.assign(Object.assign(Object.assign({}, catalog), featureFlag), filter),
26
29
  }, undefined, {
27
30
  shallow: true,
28
31
  });
29
32
  }
30
33
  },
31
34
  // eslint-disable-next-line react-hooks/exhaustive-deps -- push method isn't memoized and shouldn't be added as deps https://github.com/vercel/next.js/issues/18127
32
- [catalogParam, filterParam, href]);
35
+ [catalogParam, featureFlagParam, filterParam, href]);
33
36
  return {
34
37
  decodedCatalogParam: catalogParam,
38
+ decodedFeatureFlagParam: featureFlagParam,
35
39
  decodedFilterParam: filterParam,
36
40
  updateFilterQueryString,
37
41
  };
@@ -10,12 +10,12 @@ const useURLFilterParams_1 = require("./useURLFilterParams");
10
10
  const useUpdateURLSearchParams = () => {
11
11
  const { exploreState } = (0, useExploreState_1.useExploreState)();
12
12
  const { updateFilterQueryString } = (0, useURLFilterParams_1.useURLFilterParams)();
13
- const { catalogState, filterState } = exploreState;
13
+ const { catalogState, featureFlagState, filterState } = exploreState;
14
14
  /**
15
15
  * Update the URL search params when the filter state changes.
16
16
  */
17
17
  (0, react_1.useEffect)(() => {
18
- updateFilterQueryString(catalogState, filterState);
19
- }, [catalogState, filterState, updateFilterQueryString]);
18
+ updateFilterQueryString(catalogState, featureFlagState, filterState);
19
+ }, [catalogState, featureFlagState, filterState, updateFilterQueryString]);
20
20
  };
21
21
  exports.useUpdateURLSearchParams = useUpdateURLSearchParams;
@@ -16,6 +16,7 @@ exports.INITIAL_STATE = {
16
16
  catalogState: undefined,
17
17
  categoryViews: [],
18
18
  entityPageState: {},
19
+ featureFlagState: undefined,
19
20
  filterCount: 0,
20
21
  filterState: [],
21
22
  isRelatedView: false,
@@ -13,9 +13,10 @@ export declare function getFilterCount(filterState: SelectedFilter[]): number;
13
13
  * @param entityListType - Entity list type.
14
14
  * @param decodedFilterParam - Decoded filter parameter.
15
15
  * @param decodedCatalogParam - Decoded catalog parameter.
16
+ * @param decodedFeatureFlagParam - Decoded feature flag parameter.
16
17
  * @returns explore state.
17
18
  */
18
- export declare function initExploreState(config: SiteConfig, entityListType: string, decodedFilterParam: string, decodedCatalogParam?: string): ExploreState;
19
+ export declare function initExploreState(config: SiteConfig, entityListType: string, decodedFilterParam: string, decodedCatalogParam?: string, decodedFeatureFlagParam?: string): ExploreState;
19
20
  /**
20
21
  * Initializes filter state from URL "filter" parameter.
21
22
  * @param decodedFilterParam - Decoded filter parameter.
@@ -20,12 +20,13 @@ exports.getFilterCount = getFilterCount;
20
20
  * @param entityListType - Entity list type.
21
21
  * @param decodedFilterParam - Decoded filter parameter.
22
22
  * @param decodedCatalogParam - Decoded catalog parameter.
23
+ * @param decodedFeatureFlagParam - Decoded feature flag parameter.
23
24
  * @returns explore state.
24
25
  */
25
- function initExploreState(config, entityListType, decodedFilterParam, decodedCatalogParam) {
26
+ function initExploreState(config, entityListType, decodedFilterParam, decodedCatalogParam, decodedFeatureFlagParam) {
26
27
  const filterState = initFilterState(decodedFilterParam);
27
28
  const filterCount = getFilterCount(filterState);
28
- return Object.assign(Object.assign({}, constants_1.INITIAL_STATE), { catalogState: decodedCatalogParam, entityPageState: initEntityPageState(config), filterCount,
29
+ return Object.assign(Object.assign({}, constants_1.INITIAL_STATE), { catalogState: decodedCatalogParam, entityPageState: initEntityPageState(config), featureFlagState: decodedFeatureFlagParam, filterCount,
29
30
  filterState, listView: exploreState_1.ENTITY_VIEW.EXACT, tabValue: entityListType });
30
31
  }
31
32
  exports.initExploreState = initExploreState;
@@ -40,6 +40,7 @@ export declare type ExploreState = {
40
40
  catalogState: CatalogState;
41
41
  categoryViews: SelectCategory[];
42
42
  entityPageState: EntityPageStateMapper;
43
+ featureFlagState: FeatureFlagState;
43
44
  filterCount: number;
44
45
  filterState: SelectedFilter[];
45
46
  isRelatedView: boolean;
@@ -57,6 +58,7 @@ export interface ExploreStateContextProps {
57
58
  exploreDispatch: Dispatch<ExploreAction>;
58
59
  exploreState: ExploreState;
59
60
  }
61
+ export declare type FeatureFlagState = string | undefined;
60
62
  /**
61
63
  * List items.
62
64
  */
@@ -65,10 +65,10 @@ exports.ExploreStateContext = (0, react_1.createContext)({
65
65
  function ExploreStateProvider({ children, entityListType, }) {
66
66
  const { config, defaultEntityListType } = (0, useConfig_1.useConfig)();
67
67
  const categoryConfigs = (0, useCategoryConfigs_1.useCategoryConfigs)();
68
- const { decodedCatalogParam, decodedFilterParam } = (0, useURLFilterParams_1.useURLFilterParams)();
68
+ const { decodedCatalogParam, decodedFeatureFlagParam, decodedFilterParam } = (0, useURLFilterParams_1.useURLFilterParams)();
69
69
  const { isEnabled: isAuthEnabled, token } = (0, useAuthentication_1.useAuthentication)();
70
70
  const entityList = entityListType || defaultEntityListType;
71
- const [initReducerState] = (0, react_1.useState)(() => (0, utils_1.initExploreState)(config, entityList, decodedFilterParam, decodedCatalogParam));
71
+ const [initReducerState] = (0, react_1.useState)(() => (0, utils_1.initExploreState)(config, entityList, decodedFilterParam, decodedCatalogParam, decodedFeatureFlagParam));
72
72
  const [exploreState, exploreDispatch] = (0, react_1.useReducer)((s, a) => exploreReducer(s, a, {
73
73
  categoryConfigs,
74
74
  config,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@databiosphere/findable-ui",
3
- "version": "0.0.0",
3
+ "version": "1.0.0",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "jest",
@@ -181,4 +181,5 @@ export enum MANIFEST_DOWNLOAD_FORMAT {
181
181
  "FULL" = "full",
182
182
  "TERRA_BDBAG" = "terra.bdbag",
183
183
  "TERRA_PFB" = "terra.pfb",
184
+ "VERBATIM_PFB" = "verbatim.pfb",
184
185
  }
@@ -18,7 +18,7 @@ export interface ExportToTerraProps {
18
18
  fileSummaryFacetName: string;
19
19
  filters: Filters; // Initializes export to terra filters.
20
20
  formFacet: FormFacet;
21
- manifestDownloadFormat: ManifestDownloadFormat;
21
+ manifestDownloadFormat?: ManifestDownloadFormat;
22
22
  manifestDownloadFormats: ManifestDownloadFormat[];
23
23
  }
24
24
 
@@ -12,6 +12,12 @@ export const LAYOUT_STYLE_CONTRAST_LIGHTEST: LayoutStyle = {
12
12
  outline: PANEL_BACKGROUND_COLOR.DEFAULT,
13
13
  };
14
14
 
15
+ export const LAYOUT_STYLE_NO_CONTRAST_DEFAULT: LayoutStyle = {
16
+ content: PANEL_BACKGROUND_COLOR.DEFAULT,
17
+ navigation: PANEL_BACKGROUND_COLOR.DEFAULT,
18
+ outline: PANEL_BACKGROUND_COLOR.DEFAULT,
19
+ };
20
+
15
21
  export const LAYOUT_STYLE_NO_CONTRAST_LIGHT: LayoutStyle = {
16
22
  content: PANEL_BACKGROUND_COLOR.SMOKE_LIGHT,
17
23
  navigation: PANEL_BACKGROUND_COLOR.SMOKE_LIGHT,
@@ -100,6 +100,7 @@ export const NavigationGrid = styled.div<GridProps>`
100
100
  export const ContentGrid = styled.div<GridProps>`
101
101
  ${content};
102
102
  grid-area: content;
103
+ min-width: 0;
103
104
  `;
104
105
 
105
106
  export const OutlineGrid = styled("div")<GridProps>`
@@ -44,7 +44,13 @@ export const useEntityList = (
44
44
  } = useEntityService();
45
45
  const { exploreDispatch, exploreState } = useExploreState();
46
46
  const { data, isIdle, isLoading, run } = useAsync<AzulEntitiesResponse>();
47
- const { catalogState, entityPageState, filterState, tabValue } = exploreState;
47
+ const {
48
+ catalogState,
49
+ entityPageState,
50
+ featureFlagState,
51
+ filterState,
52
+ tabValue,
53
+ } = exploreState;
48
54
  const { pagination, termFacets } = data || {};
49
55
  const { updateFilterQueryString } = useURLFilterParams();
50
56
  const { sorting } = entityPageState[tabValue];
@@ -58,8 +64,8 @@ export const useEntityList = (
58
64
 
59
65
  // Update the filter query string when the filter state changes.
60
66
  useEffect(() => {
61
- updateFilterQueryString(catalogState, filterState);
62
- }, [catalogState, filterState, updateFilterQueryString]);
67
+ updateFilterQueryString(catalogState, featureFlagState, filterState);
68
+ }, [catalogState, featureFlagState, filterState, updateFilterQueryString]);
63
69
 
64
70
  // Fetch entities - on change of filter state - server-side fetching and server-side filtering.
65
71
  useEffect(() => {
@@ -1,14 +1,16 @@
1
1
  import { useRouter } from "next/router";
2
2
  import { useCallback } from "react";
3
3
  import { SelectedFilter } from "../common/entities";
4
- import { CatalogState } from "../providers/exploreState";
4
+ import { CatalogState, FeatureFlagState } from "../providers/exploreState";
5
5
  import { useLocation } from "./useLocation";
6
6
 
7
7
  interface UseURLFilterParamsResult {
8
8
  decodedCatalogParam: string | undefined;
9
+ decodedFeatureFlagParam: string | undefined;
9
10
  decodedFilterParam: string;
10
11
  updateFilterQueryString: (
11
12
  catalogState: CatalogState,
13
+ featureFlagState: FeatureFlagState,
12
14
  filterState: SelectedFilter[]
13
15
  ) => void;
14
16
  }
@@ -21,22 +23,29 @@ interface UseURLFilterParamsResult {
21
23
  export const useURLFilterParams = (): UseURLFilterParamsResult => {
22
24
  const { basePath, push } = useRouter();
23
25
  const { href, pathname, search } = useLocation() || {};
26
+ const featureFlagParam = search?.get("ff") ?? undefined;
24
27
  const filterParam = search?.get("filter") ?? "[]";
25
28
  const catalogParam = search?.get("catalog") ?? undefined;
26
29
 
27
30
  const updateFilterQueryString = useCallback(
28
- (catalogState: CatalogState, filterState: SelectedFilter[]) => {
31
+ (
32
+ catalogState: CatalogState,
33
+ featureFlagState: FeatureFlagState,
34
+ filterState: SelectedFilter[]
35
+ ) => {
29
36
  if (
30
37
  catalogParam !== catalogState ||
38
+ featureFlagParam !== featureFlagState ||
31
39
  filterParam !== JSON.stringify(filterState)
32
40
  ) {
41
+ const featureFlag = featureFlagState ? { ff: featureFlagState } : {};
33
42
  const filter =
34
43
  filterState.length > 0 ? { filter: JSON.stringify(filterState) } : {};
35
44
  const catalog = catalogState ? { catalog: catalogState } : {};
36
45
  push(
37
46
  {
38
47
  pathname: pathname?.replace(basePath, ""),
39
- query: { ...catalog, ...filter },
48
+ query: { ...catalog, ...featureFlag, ...filter },
40
49
  },
41
50
  undefined,
42
51
  {
@@ -46,11 +55,12 @@ export const useURLFilterParams = (): UseURLFilterParamsResult => {
46
55
  }
47
56
  },
48
57
  // eslint-disable-next-line react-hooks/exhaustive-deps -- push method isn't memoized and shouldn't be added as deps https://github.com/vercel/next.js/issues/18127
49
- [catalogParam, filterParam, href]
58
+ [catalogParam, featureFlagParam, filterParam, href]
50
59
  );
51
60
 
52
61
  return {
53
62
  decodedCatalogParam: catalogParam,
63
+ decodedFeatureFlagParam: featureFlagParam,
54
64
  decodedFilterParam: filterParam,
55
65
  updateFilterQueryString,
56
66
  };
@@ -8,12 +8,12 @@ import { useURLFilterParams } from "./useURLFilterParams";
8
8
  export const useUpdateURLSearchParams = (): void => {
9
9
  const { exploreState } = useExploreState();
10
10
  const { updateFilterQueryString } = useURLFilterParams();
11
- const { catalogState, filterState } = exploreState;
11
+ const { catalogState, featureFlagState, filterState } = exploreState;
12
12
 
13
13
  /**
14
14
  * Update the URL search params when the filter state changes.
15
15
  */
16
16
  useEffect(() => {
17
- updateFilterQueryString(catalogState, filterState);
18
- }, [catalogState, filterState, updateFilterQueryString]);
17
+ updateFilterQueryString(catalogState, featureFlagState, filterState);
18
+ }, [catalogState, featureFlagState, filterState, updateFilterQueryString]);
19
19
  };
@@ -16,6 +16,7 @@ export const INITIAL_STATE: ExploreState = {
16
16
  catalogState: undefined,
17
17
  categoryViews: [],
18
18
  entityPageState: {},
19
+ featureFlagState: undefined,
19
20
  filterCount: 0,
20
21
  filterState: [],
21
22
  isRelatedView: false,
@@ -25,13 +25,15 @@ export function getFilterCount(filterState: SelectedFilter[]): number {
25
25
  * @param entityListType - Entity list type.
26
26
  * @param decodedFilterParam - Decoded filter parameter.
27
27
  * @param decodedCatalogParam - Decoded catalog parameter.
28
+ * @param decodedFeatureFlagParam - Decoded feature flag parameter.
28
29
  * @returns explore state.
29
30
  */
30
31
  export function initExploreState(
31
32
  config: SiteConfig,
32
33
  entityListType: string,
33
34
  decodedFilterParam: string,
34
- decodedCatalogParam?: string
35
+ decodedCatalogParam?: string,
36
+ decodedFeatureFlagParam?: string
35
37
  ): ExploreState {
36
38
  const filterState = initFilterState(decodedFilterParam);
37
39
  const filterCount = getFilterCount(filterState);
@@ -39,6 +41,7 @@ export function initExploreState(
39
41
  ...INITIAL_STATE,
40
42
  catalogState: decodedCatalogParam,
41
43
  entityPageState: initEntityPageState(config),
44
+ featureFlagState: decodedFeatureFlagParam,
42
45
  filterCount,
43
46
  filterState,
44
47
  listView: ENTITY_VIEW.EXACT,
@@ -80,6 +80,7 @@ export type ExploreState = {
80
80
  catalogState: CatalogState;
81
81
  categoryViews: SelectCategory[];
82
82
  entityPageState: EntityPageStateMapper;
83
+ featureFlagState: FeatureFlagState;
83
84
  filterCount: number;
84
85
  filterState: SelectedFilter[];
85
86
  isRelatedView: boolean;
@@ -99,6 +100,8 @@ export interface ExploreStateContextProps {
99
100
  exploreState: ExploreState;
100
101
  }
101
102
 
103
+ export type FeatureFlagState = string | undefined;
104
+
102
105
  /**
103
106
  * List items.
104
107
  */
@@ -175,7 +178,8 @@ export function ExploreStateProvider({
175
178
  }): JSX.Element {
176
179
  const { config, defaultEntityListType } = useConfig();
177
180
  const categoryConfigs = useCategoryConfigs();
178
- const { decodedCatalogParam, decodedFilterParam } = useURLFilterParams();
181
+ const { decodedCatalogParam, decodedFeatureFlagParam, decodedFilterParam } =
182
+ useURLFilterParams();
179
183
  const { isEnabled: isAuthEnabled, token } = useAuthentication();
180
184
  const entityList = entityListType || defaultEntityListType;
181
185
  const [initReducerState] = useState(() =>
@@ -183,7 +187,8 @@ export function ExploreStateProvider({
183
187
  config,
184
188
  entityList,
185
189
  decodedFilterParam,
186
- decodedCatalogParam
190
+ decodedCatalogParam,
191
+ decodedFeatureFlagParam
187
192
  )
188
193
  );
189
194