@databiosphere/findable-ui 1.0.1 → 2.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.
- package/lib/components/Loading/loading.d.ts +2 -1
- package/lib/components/Loading/loading.js +4 -4
- package/lib/components/TableCreator/tableCreator.js +3 -2
- package/lib/components/TableCreator/tableCreator.styles.d.ts +5 -0
- package/lib/components/TableCreator/tableCreator.styles.js +10 -0
- package/lib/config/entities.d.ts +1 -0
- package/lib/providers/exploreState/utils.js +23 -5
- package/lib/providers/exploreState.d.ts +7 -2
- package/lib/providers/exploreState.js +12 -9
- package/lib/views/ExploreView/exploreView.js +3 -3
- package/package.json +1 -1
- package/src/components/Loading/loading.tsx +5 -2
- package/src/components/TableCreator/tableCreator.styles.ts +5 -0
- package/src/components/TableCreator/tableCreator.tsx +4 -2
- package/src/config/entities.ts +1 -0
- package/src/providers/exploreState/utils.ts +29 -1
- package/src/providers/exploreState.tsx +44 -14
- package/src/views/ExploreView/exploreView.tsx +9 -9
- package/src/hooks/useCategoryConfigs.ts +0 -17
|
@@ -13,9 +13,10 @@ export declare enum LOADING_PANEL_STYLE {
|
|
|
13
13
|
INHERIT = "INHERIT"
|
|
14
14
|
}
|
|
15
15
|
export interface LoadingProps {
|
|
16
|
+
appear?: boolean;
|
|
16
17
|
iconSize?: SvgIconProps["fontSize"];
|
|
17
18
|
loading: boolean;
|
|
18
19
|
panelStyle?: LoadingPanelStyle;
|
|
19
20
|
text?: string;
|
|
20
21
|
}
|
|
21
|
-
export declare const Loading: ({ iconSize, loading, panelStyle, text, }: LoadingProps) => JSX.Element | null;
|
|
22
|
+
export declare const Loading: ({ appear, iconSize, loading, panelStyle, text, }: LoadingProps) => JSX.Element | null;
|
|
@@ -16,8 +16,8 @@ var LOADING_PANEL_STYLE;
|
|
|
16
16
|
(function (LOADING_PANEL_STYLE) {
|
|
17
17
|
LOADING_PANEL_STYLE["INHERIT"] = "INHERIT";
|
|
18
18
|
})(LOADING_PANEL_STYLE = exports.LOADING_PANEL_STYLE || (exports.LOADING_PANEL_STYLE = {}));
|
|
19
|
-
const Loading = ({ iconSize = "large", loading, panelStyle = paper_1.PAPER_PANEL_STYLE.ROUNDED, text, }) => {
|
|
20
|
-
return (react_1.default.createElement(material_1.Fade, { in: loading, mountOnEnter: true, onEnter: (node) => onFadeEnter(node), onExited: (node) => onFadeExited(node), timeout: 300, unmountOnExit: true },
|
|
19
|
+
const Loading = ({ appear = true, iconSize = "large", loading, panelStyle = paper_1.PAPER_PANEL_STYLE.ROUNDED, text, }) => {
|
|
20
|
+
return (react_1.default.createElement(material_1.Fade, { appear: appear, in: loading, mountOnEnter: true, onEnter: (node) => onFadeEnter(node), onExited: (node) => onFadeExited(node), timeout: 300, unmountOnExit: true },
|
|
21
21
|
react_1.default.createElement(loading_styles_1.LoadingPositioner, { panelStyle: panelStyle },
|
|
22
22
|
react_1.default.createElement(loading_styles_1.LoadingPaper, { panelStyle: panelStyle },
|
|
23
23
|
react_1.default.createElement(loadingIcon_1.LoadingIcon, { color: "primary", fontSize: iconSize }),
|
|
@@ -32,7 +32,7 @@ exports.Loading = Loading;
|
|
|
32
32
|
function onFadeEnter(node) {
|
|
33
33
|
const parentEl = node.parentElement;
|
|
34
34
|
if (parentEl)
|
|
35
|
-
parentEl.style.position
|
|
35
|
+
parentEl.style.setProperty("position", "relative");
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
38
|
* Callback fired after the "exited" status is applied.
|
|
@@ -42,5 +42,5 @@ function onFadeEnter(node) {
|
|
|
42
42
|
function onFadeExited(node) {
|
|
43
43
|
const parentEl = node.parentElement;
|
|
44
44
|
if (parentEl)
|
|
45
|
-
parentEl.style.position
|
|
45
|
+
parentEl.style.removeProperty("position");
|
|
46
46
|
}
|
|
@@ -41,6 +41,7 @@ const ComponentCreator_1 = require("../ComponentCreator/ComponentCreator");
|
|
|
41
41
|
const loading_1 = require("../Loading/loading");
|
|
42
42
|
const utils_1 = require("../Table/common/utils");
|
|
43
43
|
const table_1 = require("../Table/table");
|
|
44
|
+
const tableCreator_styles_1 = require("./tableCreator.styles");
|
|
44
45
|
const createCell = (config) =>
|
|
45
46
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- We can't determine the cell type
|
|
46
47
|
function CellCreator({ row }) {
|
|
@@ -66,8 +67,8 @@ const TableCreator = ({ columns, defaultSort, items, listView, loading, pageCoun
|
|
|
66
67
|
});
|
|
67
68
|
}), [columns]);
|
|
68
69
|
const initialState = (0, utils_1.getInitialState)(columns, defaultSort);
|
|
69
|
-
return (react_1.default.createElement(
|
|
70
|
-
react_1.default.createElement(loading_1.Loading, { loading: loading || false, panelStyle: paper_1.PAPER_PANEL_STYLE.FLUID }),
|
|
70
|
+
return (react_1.default.createElement(tableCreator_styles_1.TableCreator, null,
|
|
71
|
+
react_1.default.createElement(loading_1.Loading, { appear: false, loading: loading || false, panelStyle: paper_1.PAPER_PANEL_STYLE.FLUID }),
|
|
71
72
|
react_1.default.createElement(table_1.Table, { columns: columnDefs, count: pageCount, initialState: initialState, items: items, listView: listView, loading: loading, pages: pages, pageSize: pageSize, pagination: pagination, total: total })));
|
|
72
73
|
};
|
|
73
74
|
exports.TableCreator = TableCreator;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const TableCreator: import("@emotion/styled").StyledComponent<{
|
|
3
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
4
|
+
as?: import("react").ElementType<any> | undefined;
|
|
5
|
+
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TableCreator = void 0;
|
|
7
|
+
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
8
|
+
exports.TableCreator = styled_1.default.div `
|
|
9
|
+
position: relative; // Required; when the table mounts, the loading element should not transition in and therefore to position the loading element correctly, the parent container must be styled with position relative.
|
|
10
|
+
`;
|
package/lib/config/entities.d.ts
CHANGED
|
@@ -115,6 +115,7 @@ export declare type EntityPath = string;
|
|
|
115
115
|
*/
|
|
116
116
|
export interface EntityConfig<T = any, I = any> extends TabConfig {
|
|
117
117
|
apiPath?: EntityPath;
|
|
118
|
+
categoryGroupConfigs?: CategoryGroupConfig[];
|
|
118
119
|
detail: BackPageConfig;
|
|
119
120
|
entityMapper?: EntityMapper<T, I>;
|
|
120
121
|
exploreMode: ExploreMode;
|
|
@@ -24,12 +24,21 @@ exports.getFilterCount = getFilterCount;
|
|
|
24
24
|
* @returns explore state.
|
|
25
25
|
*/
|
|
26
26
|
function initExploreState(config, entityListType, decodedFilterParam, decodedCatalogParam, decodedFeatureFlagParam) {
|
|
27
|
+
const entityPageState = initEntityPageState(config);
|
|
27
28
|
const filterState = initFilterState(decodedFilterParam);
|
|
28
29
|
const filterCount = getFilterCount(filterState);
|
|
29
|
-
return Object.assign(Object.assign({}, constants_1.INITIAL_STATE), { catalogState: decodedCatalogParam, entityPageState: initEntityPageState(config), featureFlagState: decodedFeatureFlagParam, filterCount,
|
|
30
|
+
return Object.assign(Object.assign({}, constants_1.INITIAL_STATE), { catalogState: decodedCatalogParam, categoryGroupConfigs: entityPageState[entityListType].categoryGroupConfigs, entityPageState: initEntityPageState(config), featureFlagState: decodedFeatureFlagParam, filterCount,
|
|
30
31
|
filterState, listView: exploreState_1.ENTITY_VIEW.EXACT, tabValue: entityListType });
|
|
31
32
|
}
|
|
32
33
|
exports.initExploreState = initExploreState;
|
|
34
|
+
/**
|
|
35
|
+
* Returns configured grouped configured categories as a list of configured categories.
|
|
36
|
+
* @param categoryGroupConfigs - Configured category groups.
|
|
37
|
+
* @returns a list of configured categories.
|
|
38
|
+
*/
|
|
39
|
+
function flattenCategoryGroupConfigs(categoryGroupConfigs) {
|
|
40
|
+
return categoryGroupConfigs === null || categoryGroupConfigs === void 0 ? void 0 : categoryGroupConfigs.flatMap(({ categoryConfigs }) => categoryConfigs);
|
|
41
|
+
}
|
|
33
42
|
/**
|
|
34
43
|
* Initializes filter state from URL "filter" parameter.
|
|
35
44
|
* @param decodedFilterParam - Decoded filter parameter.
|
|
@@ -53,10 +62,19 @@ exports.initFilterState = initFilterState;
|
|
|
53
62
|
* @returns entity page state.
|
|
54
63
|
*/
|
|
55
64
|
function initEntityPageState(config) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
65
|
+
const { categoryGroupConfigs } = config;
|
|
66
|
+
return config.entities.reduce((acc, entity) => {
|
|
67
|
+
var _a, _b;
|
|
68
|
+
return (Object.assign(Object.assign({}, acc), { [entity.route]: {
|
|
69
|
+
categoryConfigs: flattenCategoryGroupConfigs((_a = entity.categoryGroupConfigs) !== null && _a !== void 0 ? _a : categoryGroupConfigs),
|
|
70
|
+
categoryGroupConfigs: (_b = entity.categoryGroupConfigs) !== null && _b !== void 0 ? _b : categoryGroupConfigs,
|
|
71
|
+
categoryViews: [],
|
|
72
|
+
columnsVisibility: (0, utils_1.getInitialTableColumnVisibility)(entity.list.columns),
|
|
73
|
+
filterCount: 0,
|
|
74
|
+
filterState: [],
|
|
75
|
+
sorting: (0, utils_2.getDefaultSorting)(entity),
|
|
76
|
+
} }));
|
|
77
|
+
}, {});
|
|
60
78
|
}
|
|
61
79
|
exports.initEntityPageState = initEntityPageState;
|
|
62
80
|
/**
|
|
@@ -2,7 +2,7 @@ import { ColumnSort } from "@tanstack/react-table";
|
|
|
2
2
|
import React, { Dispatch, ReactNode } from "react";
|
|
3
3
|
import { AzulSearchIndex } from "../apis/azul/common/entities";
|
|
4
4
|
import { SelectCategory, SelectedFilter } from "../common/entities";
|
|
5
|
-
import { CategoryConfig, EntityPath, SiteConfig } from "../config/entities";
|
|
5
|
+
import { CategoryConfig, CategoryGroupConfig, EntityPath, SiteConfig } from "../config/entities";
|
|
6
6
|
import { PaginateTablePayload, ProcessExploreResponsePayload, ProcessRelatedResponsePayload, ResetExploreResponsePayload, ToggleEntityViewPayload, UpdateColumnVisibilityPayload, UpdateFilterPayload, UpdateSortingPayload } from "./exploreState/payloads/entities";
|
|
7
7
|
export declare type CatalogState = string | undefined;
|
|
8
8
|
/**
|
|
@@ -16,7 +16,6 @@ export declare enum ENTITY_VIEW {
|
|
|
16
16
|
* Explore context.
|
|
17
17
|
*/
|
|
18
18
|
export interface ExploreContext {
|
|
19
|
-
categoryConfigs?: CategoryConfig[];
|
|
20
19
|
config: SiteConfig;
|
|
21
20
|
entityList: string;
|
|
22
21
|
}
|
|
@@ -24,7 +23,12 @@ export interface ExploreContext {
|
|
|
24
23
|
* State for each entity.
|
|
25
24
|
*/
|
|
26
25
|
export interface EntityPageState {
|
|
26
|
+
categoryConfigs?: CategoryConfig[];
|
|
27
|
+
categoryGroupConfigs?: CategoryGroupConfig[];
|
|
28
|
+
categoryViews: SelectCategory[];
|
|
27
29
|
columnsVisibility: Record<string, boolean>;
|
|
30
|
+
filterCount: number;
|
|
31
|
+
filterState: SelectedFilter[];
|
|
28
32
|
sorting: ColumnSort[];
|
|
29
33
|
}
|
|
30
34
|
/**
|
|
@@ -38,6 +42,7 @@ export interface EntityPageStateMapper {
|
|
|
38
42
|
*/
|
|
39
43
|
export declare type ExploreState = {
|
|
40
44
|
catalogState: CatalogState;
|
|
45
|
+
categoryGroupConfigs?: CategoryGroupConfig[];
|
|
41
46
|
categoryViews: SelectCategory[];
|
|
42
47
|
entityPageState: EntityPageStateMapper;
|
|
43
48
|
featureFlagState: FeatureFlagState;
|
|
@@ -26,7 +26,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.ExploreActionKind = exports.ExploreStateProvider = exports.ExploreStateContext = exports.ENTITY_VIEW = void 0;
|
|
27
27
|
const react_1 = __importStar(require("react"));
|
|
28
28
|
const useAuthentication_1 = require("../hooks/useAuthentication/useAuthentication");
|
|
29
|
-
const useCategoryConfigs_1 = require("../hooks/useCategoryConfigs");
|
|
30
29
|
const useCategoryFilter_1 = require("../hooks/useCategoryFilter");
|
|
31
30
|
const useConfig_1 = require("../hooks/useConfig");
|
|
32
31
|
const useURLFilterParams_1 = require("../hooks/useURLFilterParams");
|
|
@@ -64,13 +63,11 @@ exports.ExploreStateContext = (0, react_1.createContext)({
|
|
|
64
63
|
*/
|
|
65
64
|
function ExploreStateProvider({ children, entityListType, }) {
|
|
66
65
|
const { config, defaultEntityListType } = (0, useConfig_1.useConfig)();
|
|
67
|
-
const categoryConfigs = (0, useCategoryConfigs_1.useCategoryConfigs)();
|
|
68
66
|
const { decodedCatalogParam, decodedFeatureFlagParam, decodedFilterParam } = (0, useURLFilterParams_1.useURLFilterParams)();
|
|
69
67
|
const { isEnabled: isAuthEnabled, token } = (0, useAuthentication_1.useAuthentication)();
|
|
70
68
|
const entityList = entityListType || defaultEntityListType;
|
|
71
69
|
const [initReducerState] = (0, react_1.useState)(() => (0, utils_1.initExploreState)(config, entityList, decodedFilterParam, decodedCatalogParam, decodedFeatureFlagParam));
|
|
72
70
|
const [exploreState, exploreDispatch] = (0, react_1.useReducer)((s, a) => exploreReducer(s, a, {
|
|
73
|
-
categoryConfigs,
|
|
74
71
|
config,
|
|
75
72
|
entityList,
|
|
76
73
|
}), initReducerState);
|
|
@@ -116,7 +113,7 @@ var ExploreActionKind;
|
|
|
116
113
|
*/
|
|
117
114
|
function exploreReducer(state, action, exploreContext) {
|
|
118
115
|
const { payload, type } = action;
|
|
119
|
-
const {
|
|
116
|
+
const { config, entityList } = exploreContext;
|
|
120
117
|
switch (type) {
|
|
121
118
|
/**
|
|
122
119
|
* Clear all filters
|
|
@@ -143,9 +140,12 @@ function exploreReducer(state, action, exploreContext) {
|
|
|
143
140
|
* Process explore response
|
|
144
141
|
**/
|
|
145
142
|
case ExploreActionKind.ProcessExploreResponse: {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
const { entityPageState, tabValue } = state;
|
|
144
|
+
const { categoryConfigs, categoryViews, filterState } = entityPageState[tabValue];
|
|
145
|
+
const nextCategoryViews = payload.selectCategories
|
|
146
|
+
? (0, useCategoryFilter_1.buildCategoryViews)(payload.selectCategories, categoryConfigs, filterState)
|
|
147
|
+
: undefined;
|
|
148
|
+
return Object.assign(Object.assign({}, state), { categoryGroupConfigs: entityPageState[tabValue].categoryGroupConfigs, categoryViews: nextCategoryViews !== null && nextCategoryViews !== void 0 ? nextCategoryViews : categoryViews, entityPageState: Object.assign(Object.assign({}, entityPageState), { [tabValue]: Object.assign(Object.assign({}, entityPageState[tabValue]), { categoryViews: nextCategoryViews !== null && nextCategoryViews !== void 0 ? nextCategoryViews : categoryViews }) }), listItems: payload.loading ? [] : payload.listItems, loading: payload.loading, paginationState: Object.assign(Object.assign({}, state.paginationState), payload.paginationResponse) });
|
|
149
149
|
}
|
|
150
150
|
/**
|
|
151
151
|
* Process related response
|
|
@@ -172,7 +172,7 @@ function exploreReducer(state, action, exploreContext) {
|
|
|
172
172
|
if (payload === state.tabValue) {
|
|
173
173
|
return state;
|
|
174
174
|
}
|
|
175
|
-
return Object.assign(Object.assign({}, state), { listItems: [], loading: true, paginationState: (0, utils_1.resetPage)(state.paginationState), tabValue: payload });
|
|
175
|
+
return Object.assign(Object.assign({}, state), { filterCount: state.entityPageState[payload].filterCount, filterState: state.entityPageState[payload].filterState, listItems: [], loading: true, paginationState: (0, utils_1.resetPage)(state.paginationState), tabValue: payload });
|
|
176
176
|
}
|
|
177
177
|
/**
|
|
178
178
|
* Toggle entity view
|
|
@@ -185,7 +185,10 @@ function exploreReducer(state, action, exploreContext) {
|
|
|
185
185
|
**/
|
|
186
186
|
case ExploreActionKind.UpdateFilter: {
|
|
187
187
|
const filterState = (0, useCategoryFilter_1.buildNextFilterState)(state.filterState, payload.categoryKey, payload.selectedValue, payload.selected);
|
|
188
|
-
|
|
188
|
+
const filterCount = (0, utils_1.getFilterCount)(filterState);
|
|
189
|
+
return Object.assign(Object.assign({}, state), { entityPageState: Object.assign(Object.assign({}, state.entityPageState), { [state.tabValue]: Object.assign(Object.assign({}, state.entityPageState[state.tabValue]), { filterCount,
|
|
190
|
+
filterState }) }), filterCount,
|
|
191
|
+
filterState, paginationState: (0, utils_1.resetPage)(state.paginationState) });
|
|
189
192
|
}
|
|
190
193
|
/**
|
|
191
194
|
* Update sorting
|
|
@@ -65,10 +65,10 @@ const ExploreView = (props) => {
|
|
|
65
65
|
const tabletDown = (0, useBreakpointHelper_1.useBreakpointHelper)(useBreakpointHelper_1.BREAKPOINT_FN_NAME.DOWN, breakpoints_1.DESKTOP_SM);
|
|
66
66
|
const { config, entityConfig } = (0, useConfig_1.useConfig)(); // Get app level config.
|
|
67
67
|
const { exploreDispatch, exploreState } = (0, useExploreState_1.useExploreState)(); // Get the useReducer state and dispatch for "Explore".
|
|
68
|
-
const {
|
|
68
|
+
const { entities, explorerTitle, summaryConfig, trackingConfig } = config;
|
|
69
69
|
const { listView } = entityConfig;
|
|
70
70
|
const { listHero, subTitleHero } = listView || {};
|
|
71
|
-
const { categoryViews, filterCount, isRelatedView, tabValue } = exploreState;
|
|
71
|
+
const { categoryGroupConfigs, categoryViews, filterCount, isRelatedView, tabValue, } = exploreState;
|
|
72
72
|
const { push } = (0, router_1.useRouter)();
|
|
73
73
|
const tabs = getTabs(entities);
|
|
74
74
|
const { response: summaryResponse } = (0, useSummary_1.useSummary)(); // Fetch summary.
|
|
@@ -208,7 +208,7 @@ function renderList(exploreState, entityConfig, entityListType) {
|
|
|
208
208
|
if (entityListType !== tabValue) {
|
|
209
209
|
// required currently for client-side fetching as the pre-rendered page
|
|
210
210
|
// loads with the previous tabs data on the first render after switching tabs. (or similar)
|
|
211
|
-
return react_1.default.createElement(react_1.default.Fragment, null);
|
|
211
|
+
return react_1.default.createElement(react_1.default.Fragment, null);
|
|
212
212
|
}
|
|
213
213
|
return (react_1.default.createElement(tableCreator_1.TableCreator, { columns: columnsConfig, defaultSort: defaultSort, items: isRelatedView && relatedListItems ? relatedListItems : listItems !== null && listItems !== void 0 ? listItems : [], listView: listView, loading: loading, pages: paginationState.pages, pageSize: paginationState.pageSize, pagination: undefined, total: paginationState.rows }));
|
|
214
214
|
}
|
package/package.json
CHANGED
|
@@ -21,6 +21,7 @@ export enum LOADING_PANEL_STYLE {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface LoadingProps {
|
|
24
|
+
appear?: boolean; // Note, if false, the component will not transition on the initial render and onEnter callbacks will not be called. In this instance, ensure the parent container is styled correctly with position relative.
|
|
24
25
|
iconSize?: SvgIconProps["fontSize"];
|
|
25
26
|
loading: boolean;
|
|
26
27
|
panelStyle?: LoadingPanelStyle; // Enables loading to mirror parent container styles.
|
|
@@ -28,6 +29,7 @@ export interface LoadingProps {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export const Loading = ({
|
|
32
|
+
appear = true,
|
|
31
33
|
iconSize = "large",
|
|
32
34
|
loading,
|
|
33
35
|
panelStyle = PAPER_PANEL_STYLE.ROUNDED,
|
|
@@ -35,6 +37,7 @@ export const Loading = ({
|
|
|
35
37
|
}: LoadingProps): JSX.Element | null => {
|
|
36
38
|
return (
|
|
37
39
|
<Fade
|
|
40
|
+
appear={appear}
|
|
38
41
|
in={loading}
|
|
39
42
|
mountOnEnter
|
|
40
43
|
onEnter={(node: HTMLElement): void => onFadeEnter(node)}
|
|
@@ -59,7 +62,7 @@ export const Loading = ({
|
|
|
59
62
|
*/
|
|
60
63
|
function onFadeEnter(node: HTMLElement): void {
|
|
61
64
|
const parentEl = node.parentElement;
|
|
62
|
-
if (parentEl) parentEl.style.position
|
|
65
|
+
if (parentEl) parentEl.style.setProperty("position", "relative");
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
/**
|
|
@@ -69,5 +72,5 @@ function onFadeEnter(node: HTMLElement): void {
|
|
|
69
72
|
*/
|
|
70
73
|
function onFadeExited(node: HTMLElement): void {
|
|
71
74
|
const parentEl = node.parentElement;
|
|
72
|
-
if (parentEl) parentEl.style.position
|
|
75
|
+
if (parentEl) parentEl.style.removeProperty("position");
|
|
73
76
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import styled from "@emotion/styled";
|
|
2
|
+
|
|
3
|
+
export const TableCreator = styled.div`
|
|
4
|
+
position: relative; // Required; when the table mounts, the loading element should not transition in and therefore to position the loading element correctly, the parent container must be styled with position relative.
|
|
5
|
+
`;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
sortingFn,
|
|
12
12
|
} from "../Table/common/utils";
|
|
13
13
|
import { Table } from "../Table/table";
|
|
14
|
+
import { TableCreator as TableCreatorContainer } from "./tableCreator.styles";
|
|
14
15
|
|
|
15
16
|
export interface TableCreatorProps<T> {
|
|
16
17
|
columns: ColumnConfig<T>[];
|
|
@@ -69,8 +70,9 @@ export const TableCreator = <T extends object>({
|
|
|
69
70
|
);
|
|
70
71
|
const initialState = getInitialState(columns, defaultSort);
|
|
71
72
|
return (
|
|
72
|
-
<
|
|
73
|
+
<TableCreatorContainer>
|
|
73
74
|
<Loading
|
|
75
|
+
appear={false}
|
|
74
76
|
loading={loading || false}
|
|
75
77
|
panelStyle={PAPER_PANEL_STYLE.FLUID}
|
|
76
78
|
/>
|
|
@@ -86,6 +88,6 @@ export const TableCreator = <T extends object>({
|
|
|
86
88
|
pagination={pagination}
|
|
87
89
|
total={total}
|
|
88
90
|
/>
|
|
89
|
-
</
|
|
91
|
+
</TableCreatorContainer>
|
|
90
92
|
);
|
|
91
93
|
};
|
package/src/config/entities.ts
CHANGED
|
@@ -143,6 +143,7 @@ export type EntityPath = string;
|
|
|
143
143
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This config model is part of a generic array
|
|
144
144
|
export interface EntityConfig<T = any, I = any> extends TabConfig {
|
|
145
145
|
apiPath?: EntityPath;
|
|
146
|
+
categoryGroupConfigs?: CategoryGroupConfig[];
|
|
146
147
|
detail: BackPageConfig;
|
|
147
148
|
entityMapper?: EntityMapper<T, I>;
|
|
148
149
|
exploreMode: ExploreMode;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { SelectedFilter } from "../../common/entities";
|
|
2
2
|
import { getInitialTableColumnVisibility } from "../../components/Table/common/utils";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
CategoryConfig,
|
|
5
|
+
CategoryGroupConfig,
|
|
6
|
+
SiteConfig,
|
|
7
|
+
} from "../../config/entities";
|
|
4
8
|
import { getDefaultSorting } from "../../config/utils";
|
|
5
9
|
import {
|
|
6
10
|
EntityPageStateMapper,
|
|
@@ -35,11 +39,13 @@ export function initExploreState(
|
|
|
35
39
|
decodedCatalogParam?: string,
|
|
36
40
|
decodedFeatureFlagParam?: string
|
|
37
41
|
): ExploreState {
|
|
42
|
+
const entityPageState = initEntityPageState(config);
|
|
38
43
|
const filterState = initFilterState(decodedFilterParam);
|
|
39
44
|
const filterCount = getFilterCount(filterState);
|
|
40
45
|
return {
|
|
41
46
|
...INITIAL_STATE,
|
|
42
47
|
catalogState: decodedCatalogParam,
|
|
48
|
+
categoryGroupConfigs: entityPageState[entityListType].categoryGroupConfigs,
|
|
43
49
|
entityPageState: initEntityPageState(config),
|
|
44
50
|
featureFlagState: decodedFeatureFlagParam,
|
|
45
51
|
filterCount,
|
|
@@ -49,6 +55,19 @@ export function initExploreState(
|
|
|
49
55
|
};
|
|
50
56
|
}
|
|
51
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[]
|
|
65
|
+
): CategoryConfig[] | undefined {
|
|
66
|
+
return categoryGroupConfigs?.flatMap(
|
|
67
|
+
({ categoryConfigs }) => categoryConfigs
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
52
71
|
/**
|
|
53
72
|
* Initializes filter state from URL "filter" parameter.
|
|
54
73
|
* @param decodedFilterParam - Decoded filter parameter.
|
|
@@ -71,11 +90,20 @@ export function initFilterState(decodedFilterParam: string): SelectedFilter[] {
|
|
|
71
90
|
* @returns entity page state.
|
|
72
91
|
*/
|
|
73
92
|
export function initEntityPageState(config: SiteConfig): EntityPageStateMapper {
|
|
93
|
+
const { categoryGroupConfigs } = config;
|
|
74
94
|
return config.entities.reduce(
|
|
75
95
|
(acc, entity) => ({
|
|
76
96
|
...acc,
|
|
77
97
|
[entity.route]: {
|
|
98
|
+
categoryConfigs: flattenCategoryGroupConfigs(
|
|
99
|
+
entity.categoryGroupConfigs ?? categoryGroupConfigs
|
|
100
|
+
),
|
|
101
|
+
categoryGroupConfigs:
|
|
102
|
+
entity.categoryGroupConfigs ?? categoryGroupConfigs,
|
|
103
|
+
categoryViews: [],
|
|
78
104
|
columnsVisibility: getInitialTableColumnVisibility(entity.list.columns),
|
|
105
|
+
filterCount: 0,
|
|
106
|
+
filterState: [],
|
|
79
107
|
sorting: getDefaultSorting(entity),
|
|
80
108
|
},
|
|
81
109
|
}),
|
|
@@ -10,9 +10,13 @@ import React, {
|
|
|
10
10
|
} from "react";
|
|
11
11
|
import { AzulSearchIndex } from "../apis/azul/common/entities";
|
|
12
12
|
import { SelectCategory, SelectedFilter } from "../common/entities";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
CategoryConfig,
|
|
15
|
+
CategoryGroupConfig,
|
|
16
|
+
EntityPath,
|
|
17
|
+
SiteConfig,
|
|
18
|
+
} from "../config/entities";
|
|
14
19
|
import { useAuthentication } from "../hooks/useAuthentication/useAuthentication";
|
|
15
|
-
import { useCategoryConfigs } from "../hooks/useCategoryConfigs";
|
|
16
20
|
import {
|
|
17
21
|
buildCategoryViews,
|
|
18
22
|
buildNextFilterState,
|
|
@@ -53,7 +57,6 @@ export enum ENTITY_VIEW {
|
|
|
53
57
|
* Explore context.
|
|
54
58
|
*/
|
|
55
59
|
export interface ExploreContext {
|
|
56
|
-
categoryConfigs?: CategoryConfig[];
|
|
57
60
|
config: SiteConfig;
|
|
58
61
|
entityList: string;
|
|
59
62
|
}
|
|
@@ -62,7 +65,12 @@ export interface ExploreContext {
|
|
|
62
65
|
* State for each entity.
|
|
63
66
|
*/
|
|
64
67
|
export interface EntityPageState {
|
|
68
|
+
categoryConfigs?: CategoryConfig[];
|
|
69
|
+
categoryGroupConfigs?: CategoryGroupConfig[];
|
|
70
|
+
categoryViews: SelectCategory[];
|
|
65
71
|
columnsVisibility: Record<string, boolean>;
|
|
72
|
+
filterCount: number;
|
|
73
|
+
filterState: SelectedFilter[];
|
|
66
74
|
sorting: ColumnSort[];
|
|
67
75
|
}
|
|
68
76
|
|
|
@@ -78,6 +86,7 @@ export interface EntityPageStateMapper {
|
|
|
78
86
|
*/
|
|
79
87
|
export type ExploreState = {
|
|
80
88
|
catalogState: CatalogState;
|
|
89
|
+
categoryGroupConfigs?: CategoryGroupConfig[];
|
|
81
90
|
categoryViews: SelectCategory[];
|
|
82
91
|
entityPageState: EntityPageStateMapper;
|
|
83
92
|
featureFlagState: FeatureFlagState;
|
|
@@ -177,7 +186,6 @@ export function ExploreStateProvider({
|
|
|
177
186
|
entityListType: string;
|
|
178
187
|
}): JSX.Element {
|
|
179
188
|
const { config, defaultEntityListType } = useConfig();
|
|
180
|
-
const categoryConfigs = useCategoryConfigs();
|
|
181
189
|
const { decodedCatalogParam, decodedFeatureFlagParam, decodedFilterParam } =
|
|
182
190
|
useURLFilterParams();
|
|
183
191
|
const { isEnabled: isAuthEnabled, token } = useAuthentication();
|
|
@@ -195,7 +203,6 @@ export function ExploreStateProvider({
|
|
|
195
203
|
const [exploreState, exploreDispatch] = useReducer(
|
|
196
204
|
(s: ExploreState, a: ExploreAction) =>
|
|
197
205
|
exploreReducer(s, a, {
|
|
198
|
-
categoryConfigs,
|
|
199
206
|
config,
|
|
200
207
|
entityList,
|
|
201
208
|
}),
|
|
@@ -357,7 +364,7 @@ function exploreReducer(
|
|
|
357
364
|
exploreContext: ExploreContext
|
|
358
365
|
): ExploreState {
|
|
359
366
|
const { payload, type } = action;
|
|
360
|
-
const {
|
|
367
|
+
const { config, entityList } = exploreContext;
|
|
361
368
|
|
|
362
369
|
switch (type) {
|
|
363
370
|
/**
|
|
@@ -392,15 +399,27 @@ function exploreReducer(
|
|
|
392
399
|
* Process explore response
|
|
393
400
|
**/
|
|
394
401
|
case ExploreActionKind.ProcessExploreResponse: {
|
|
402
|
+
const { entityPageState, tabValue } = state;
|
|
403
|
+
const { categoryConfigs, categoryViews, filterState } =
|
|
404
|
+
entityPageState[tabValue];
|
|
405
|
+
const nextCategoryViews = payload.selectCategories
|
|
406
|
+
? buildCategoryViews(
|
|
407
|
+
payload.selectCategories,
|
|
408
|
+
categoryConfigs,
|
|
409
|
+
filterState
|
|
410
|
+
)
|
|
411
|
+
: undefined;
|
|
395
412
|
return {
|
|
396
413
|
...state,
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
414
|
+
categoryGroupConfigs: entityPageState[tabValue].categoryGroupConfigs,
|
|
415
|
+
categoryViews: nextCategoryViews ?? categoryViews,
|
|
416
|
+
entityPageState: {
|
|
417
|
+
...entityPageState,
|
|
418
|
+
[tabValue]: {
|
|
419
|
+
...entityPageState[tabValue],
|
|
420
|
+
categoryViews: nextCategoryViews ?? categoryViews,
|
|
421
|
+
},
|
|
422
|
+
},
|
|
404
423
|
listItems: payload.loading ? [] : payload.listItems,
|
|
405
424
|
loading: payload.loading,
|
|
406
425
|
paginationState: {
|
|
@@ -444,6 +463,8 @@ function exploreReducer(
|
|
|
444
463
|
}
|
|
445
464
|
return {
|
|
446
465
|
...state,
|
|
466
|
+
filterCount: state.entityPageState[payload].filterCount,
|
|
467
|
+
filterState: state.entityPageState[payload].filterState,
|
|
447
468
|
listItems: [],
|
|
448
469
|
loading: true,
|
|
449
470
|
paginationState: resetPage(state.paginationState),
|
|
@@ -470,9 +491,18 @@ function exploreReducer(
|
|
|
470
491
|
payload.selectedValue,
|
|
471
492
|
payload.selected
|
|
472
493
|
);
|
|
494
|
+
const filterCount = getFilterCount(filterState);
|
|
473
495
|
return {
|
|
474
496
|
...state,
|
|
475
|
-
|
|
497
|
+
entityPageState: {
|
|
498
|
+
...state.entityPageState,
|
|
499
|
+
[state.tabValue]: {
|
|
500
|
+
...state.entityPageState[state.tabValue],
|
|
501
|
+
filterCount,
|
|
502
|
+
filterState,
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
filterCount,
|
|
476
506
|
filterState,
|
|
477
507
|
paginationState: resetPage(state.paginationState),
|
|
478
508
|
};
|
|
@@ -66,16 +66,16 @@ export const ExploreView = (props: ExploreViewProps): JSX.Element => {
|
|
|
66
66
|
const tabletDown = useBreakpointHelper(BREAKPOINT_FN_NAME.DOWN, DESKTOP_SM);
|
|
67
67
|
const { config, entityConfig } = useConfig(); // Get app level config.
|
|
68
68
|
const { exploreDispatch, exploreState } = useExploreState(); // Get the useReducer state and dispatch for "Explore".
|
|
69
|
-
const {
|
|
70
|
-
categoryGroupConfigs,
|
|
71
|
-
entities,
|
|
72
|
-
explorerTitle,
|
|
73
|
-
summaryConfig,
|
|
74
|
-
trackingConfig,
|
|
75
|
-
} = config;
|
|
69
|
+
const { entities, explorerTitle, summaryConfig, trackingConfig } = config;
|
|
76
70
|
const { listView } = entityConfig;
|
|
77
71
|
const { listHero, subTitleHero } = listView || {};
|
|
78
|
-
const {
|
|
72
|
+
const {
|
|
73
|
+
categoryGroupConfigs,
|
|
74
|
+
categoryViews,
|
|
75
|
+
filterCount,
|
|
76
|
+
isRelatedView,
|
|
77
|
+
tabValue,
|
|
78
|
+
} = exploreState;
|
|
79
79
|
const { push } = useRouter();
|
|
80
80
|
const tabs = getTabs(entities);
|
|
81
81
|
const { response: summaryResponse } = useSummary(); // Fetch summary.
|
|
@@ -291,7 +291,7 @@ function renderList(
|
|
|
291
291
|
if (entityListType !== tabValue) {
|
|
292
292
|
// required currently for client-side fetching as the pre-rendered page
|
|
293
293
|
// loads with the previous tabs data on the first render after switching tabs. (or similar)
|
|
294
|
-
return <></>;
|
|
294
|
+
return <></>;
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
return (
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
2
|
-
import { CategoryConfig } from "../config/entities";
|
|
3
|
-
import { useConfig } from "./useConfig";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Returns configured grouped configured categories as a list of configured categories.
|
|
7
|
-
* @returns a list of configured categories.
|
|
8
|
-
*/
|
|
9
|
-
export const useCategoryConfigs = (): CategoryConfig[] | undefined => {
|
|
10
|
-
const { config } = useConfig();
|
|
11
|
-
const { categoryGroupConfigs } = config;
|
|
12
|
-
return useMemo(() => {
|
|
13
|
-
return categoryGroupConfigs?.flatMap(
|
|
14
|
-
({ categoryConfigs }) => categoryConfigs
|
|
15
|
-
);
|
|
16
|
-
}, [categoryGroupConfigs]);
|
|
17
|
-
};
|