Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create explorer mode to handle server-side fetches with client-side filtering (#495) #496

Merged
merged 2 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/data-explorer-ui/src/components/Table/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
GridTrackMinMax,
GridTrackSize,
} from "../../../config/entities";
import { ExploreMode, EXPLORE_MODE } from "../../../hooks/useExploreMode";
import { CheckboxMenuListItem } from "../components/CheckboxMenu/checkboxMenu";

/**
Expand Down Expand Up @@ -333,6 +334,18 @@ function getVisibleRowsTableData<T>(rows: Row<T>[]): TableData[][] {
);
}

/**
* Returns true if client-side filtering is enabled.
* @param exploreMode - Explore mode.
* @returns true if client-side filtering is enabled.
*/
export function isClientFilteringEnabled(exploreMode: ExploreMode): boolean {
return (
exploreMode === EXPLORE_MODE.CS_FETCH_CS_FILTERING ||
exploreMode === EXPLORE_MODE.SS_FETCH_CS_FILTERING
);
}

/**
* Returns true if column has a sort direction.
* @param sortDirection - Column sort direction.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { useExploreState } from "../../../../hooks/useExploreState";
import {
EntityView,
ENTITY_VIEW,
ExploreActionKind,
} from "../../../../providers/exploreState";
import { ToggleButtonGroup } from "../../../common/ToggleButtonGroup/toggleButtonGroup";
Expand All @@ -11,21 +11,21 @@ export const EntityViewToggle = (): JSX.Element => {
const toggleButtons = [
{
label: "Exact Match",
onToggle: () => onChange(EntityView.EXACT),
value: EntityView.EXACT,
onToggle: () => onChange(ENTITY_VIEW.EXACT),
value: ENTITY_VIEW.EXACT,
},
{
label: "Related Match",
onToggle: () => onChange(EntityView.RELATED),
value: EntityView.RELATED,
onToggle: () => onChange(ENTITY_VIEW.RELATED),
value: ENTITY_VIEW.RELATED,
},
];

/**
* Callback fired when toggle button value changes.
* @param entityView - Entity list view.
*/
const onChange = (entityView: EntityView): void => {
const onChange = (entityView: ENTITY_VIEW): void => {
exploreDispatch({
payload: entityView,
type: ExploreActionKind.ToggleEntityView,
Expand Down
56 changes: 28 additions & 28 deletions packages/data-explorer-ui/src/components/Table/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ import {
BREAKPOINT_FN_NAME,
useBreakpointHelper,
} from "../../hooks/useBreakpointHelper";
import { useExploreMode } from "../../hooks/useExploreMode";
import { useExploreState } from "../../hooks/useExploreState";
import { useScroll } from "../../hooks/useScroll";
import { EntityView, ExploreActionKind } from "../../providers/exploreState";
import { ENTITY_VIEW, ExploreActionKind } from "../../providers/exploreState";
import { DEFAULT_PAGINATION_STATE } from "../../providers/exploreState/constants";
import { TABLET } from "../../theme/common/breakpoints";
import { FluidPaper, GridPaper } from "../common/Paper/paper.styles";
import { NoResults } from "../NoResults/noResults";
Expand All @@ -38,6 +40,7 @@ import {
buildCategoryViews,
getFacetedUniqueValuesWithArrayValues,
getGridTemplateColumns,
isClientFilteringEnabled,
} from "./common/utils";
import { Pagination as DXPagination } from "./components/Pagination/pagination";
import { TableBody } from "./components/TableBody/tableBody";
Expand All @@ -55,7 +58,6 @@ export interface TableProps<T extends object> {
pages?: number;
pageSize: number;
pagination?: Pagination;
staticallyLoaded?: boolean;
total?: number;
}

Expand All @@ -80,20 +82,21 @@ export const TableComponent = <T extends object>({
}: // eslint-disable-next-line sonarjs/cognitive-complexity -- TODO fix component length / complexity
TableProps<T>): JSX.Element => {
const tabletDown = useBreakpointHelper(BREAKPOINT_FN_NAME.DOWN, TABLET);
const exploreMode = useExploreMode();
const { exploreDispatch, exploreState } = useExploreState();
const {
entityPageState,
filterState,
isRelatedView,
listItems,
listStaticLoad,
loading,
paginationState,
tabValue,
} = exploreState;
const { columnsVisibility, sorting } = entityPageState[tabValue];
const { currentPage, pages, pageSize } = paginationState;
const { disablePagination = false } = listView || {};
const clientFiltering = isClientFilteringEnabled(exploreMode);
const rowDirection = tabletDown
? ROW_DIRECTION.VERTICAL
: ROW_DIRECTION.DEFAULT;
Expand Down Expand Up @@ -134,22 +137,22 @@ TableProps<T>): JSX.Element => {
const tableInstance = useReactTable({
columns,
data: items,
enableColumnFilters: true, // listStaticLoad,
enableFilters: true, // listStaticLoad,
enableColumnFilters: true, // client-side filtering.
enableFilters: true, // client-side filtering.
enableMultiSort: false,
enableSorting: true, // listStaticLoad
enableSortingRemoval: false, // listStaticLoad
enableSorting: true, // client-side filtering.
enableSortingRemoval: false, // client-side filtering.
getCoreRowModel: getCoreRowModel(),
getFacetedRowModel: listStaticLoad ? getFacetedRowModel() : undefined,
getFacetedUniqueValues: listStaticLoad
getFacetedRowModel: clientFiltering ? getFacetedRowModel() : undefined,
getFacetedUniqueValues: clientFiltering
? getFacetedUniqueValuesWithArrayValues()
: undefined,
getFilteredRowModel: listStaticLoad ? getFilteredRowModel() : undefined,
getFilteredRowModel: clientFiltering ? getFilteredRowModel() : undefined,
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: listStaticLoad ? getSortedRowModel() : undefined,
getSortedRowModel: clientFiltering ? getSortedRowModel() : undefined,
initialState,
manualPagination: listStaticLoad,
manualSorting: !listStaticLoad,
manualPagination: clientFiltering,
manualSorting: !clientFiltering,
onColumnVisibilityChange,
onSortingChange,
pageCount: total,
Expand All @@ -173,7 +176,7 @@ TableProps<T>): JSX.Element => {

const handleTableNextPage = (): void => {
let nextPage = tableNextPage;
if (!listStaticLoad) {
if (!clientFiltering) {
nextPage = (): void => {
exploreDispatch({
payload: "next",
Expand All @@ -192,9 +195,8 @@ TableProps<T>): JSX.Element => {
};

const handleTablePreviousPage = (): void => {
//const previousPage = pagination?.previousPage ?? tablePreviousPage;
let previousPage = tablePreviousPage;
if (!listStaticLoad) {
if (!clientFiltering) {
previousPage = (): void => {
exploreDispatch({
payload: "prev",
Expand All @@ -210,11 +212,11 @@ TableProps<T>): JSX.Element => {
scrollTop();
};

// Sets or resets react table column filters `columnFilters` state, for statically loaded api only, with update of filterState.
// Sets or resets react table column filters `columnFilters` state - for client-side filtering only - with update of filterState.
// - `columnFilters` state is "cleared" for related view, and
// - `columnFilters` state is "set" for all other views.
useEffect(() => {
if (listStaticLoad) {
if (clientFiltering) {
if (isRelatedView) {
tableInstance.resetColumnFilters();
} else {
Expand All @@ -226,22 +228,20 @@ TableProps<T>): JSX.Element => {
);
}
}
}, [filterState, isRelatedView, listStaticLoad, tableInstance]);
}, [clientFiltering, filterState, isRelatedView, tableInstance]);

/**
* Static List Mode - Process Explore Response
*/
// Process explore response - client-side filtering only.
useEffect(() => {
if (!isRelatedView && listStaticLoad) {
if (isRelatedView) return;
if (!listItems || listItems.length === 0) return;
if (clientFiltering) {
exploreDispatch({
payload: {
listItems,
loading: false,
paginationResponse: {
nextIndex: null,
...DEFAULT_PAGINATION_STATE,
pageSize: results.length,
pages: 1,
previousIndex: null,
rows: results.length,
},
selectCategories: buildCategoryViews(allColumns, columnFilters),
Expand All @@ -251,19 +251,19 @@ TableProps<T>): JSX.Element => {
}
}, [
allColumns,
clientFiltering,
columnFilters,
exploreDispatch,
isRelatedView,
listItems,
listStaticLoad,
results,
]);

// Unmount - reset entity view to "exact".
useEffect(() => {
return () => {
exploreDispatch({
payload: EntityView.EXACT,
payload: ENTITY_VIEW.EXACT,
type: ExploreActionKind.ToggleEntityView,
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export interface TableCreatorProps<T> {
pages: number;
pageSize: number;
pagination?: Pagination;
staticallyLoaded?: boolean;
total?: number;
}

Expand All @@ -47,7 +46,6 @@ export const TableCreator = <T extends object>({
pages,
pageSize,
pagination,
staticallyLoaded,
total,
}: TableCreatorProps<T>): JSX.Element => {
const columnDefs: ColumnDef<T>[] = useMemo(
Expand Down Expand Up @@ -86,7 +84,6 @@ export const TableCreator = <T extends object>({
pages={pages}
pageSize={pageSize}
pagination={pagination}
staticallyLoaded={staticallyLoaded}
total={total}
/>
</div>
Expand Down
15 changes: 8 additions & 7 deletions packages/data-explorer-ui/src/config/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { CategoryKey, SelectedFilterValue } from "../common/entities";
import { HeroTitle } from "../components/common/Title/title";
import { FooterProps } from "../components/Layout/components/Footer/footer";
import { HeaderProps } from "../components/Layout/components/Header/header";
import { ExploreMode } from "../hooks/useExploreMode";
import { AuthContextProps } from "../providers/authentication";
import { ExploreState } from "../providers/exploreState";
import { FileManifestState } from "../providers/fileManifestState";
Expand Down Expand Up @@ -138,23 +139,23 @@ export type EntityPath = string;
* the detail and the list page configuration.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- This config model is part of a generic array
export interface EntityConfig<D = any, I = any> extends TabConfig {
export interface EntityConfig<T = any, I = any> extends TabConfig {
apiPath?: EntityPath;
detail: BackPageConfig;
getId?: GetIdFunction<D>;
entityMapper?: EntityMapper<T, I>;
exploreMode: ExploreMode;
getId?: GetIdFunction<T>;
list: ListConfig;
listView?: ListViewConfig;
options?: Options;
overrides?: Override[];
staticEntityImportMapper?: EntityImportMapper<I, D>;
staticLoad: boolean;
staticLoadFile?: string;
}

/**
* Entity import mapper function.
* Entity mapper function.
*/
type EntityImportMapper<I, D> = (input: I) => D;
export type EntityMapper<T, I> = (input: I) => T;

/**
* Interface to define the export configuration for a given site.
Expand All @@ -175,7 +176,7 @@ export interface ExportMethodConfig {
/**
* Get identifier function.
*/
type GetIdFunction<T> = (detail: T) => string;
export type GetIdFunction<T> = (detail: T) => string;

/**
* Google GIS authentication configuration.
Expand Down
3 changes: 2 additions & 1 deletion packages/data-explorer-ui/src/config/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ColumnSort } from "@tanstack/react-table";
import { EXPLORE_MODE } from "../hooks/useExploreMode";
import { getConfig } from "./config";
import { EntityConfig, SiteConfig } from "./entities";

Expand Down Expand Up @@ -42,12 +43,12 @@ export function getDefaultEntityConfig(): EntityConfig {
tabs: [],
top: [],
},
exploreMode: EXPLORE_MODE.CS_FETCH_CS_FILTERING,
label: "",
list: {
columns: [],
},
route: "",
staticLoad: false,
};
}

Expand Down
9 changes: 6 additions & 3 deletions packages/data-explorer-ui/src/entity/api/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,24 @@ export const fetchAllEntities = async (
* @param apiPath - API endpoint URL.
* @param catalog - Catalog.
* @param accessToken - Access token.
* @param param - Catalog's version, if none passed it will default to the current one.
* @param defaultParams - Default parameters.
* @returns @see ProjectResponse
*/
export const fetchEntityDetail = async (
id: string,
apiPath: string,
catalog: string | undefined,
accessToken: string | undefined,
param = getDefaultDetailParams()
defaultParams = getDefaultDetailParams()
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- this response type can't be determined beforehand
): Promise<any> => {
const catalogParam = catalog ? { [AZUL_PARAM.CATALOG]: catalog } : undefined;
const options = createFetchOptions(accessToken);
const res = await api().get(
`${apiPath}/${id}?${convertUrlParams({ ...param, ...catalogParam })}`,
`${apiPath}/${id}?${convertUrlParams({
...defaultParams,
...catalogParam,
})}`,
options
);
return res.data;
Expand Down
18 changes: 18 additions & 0 deletions packages/data-explorer-ui/src/entity/apicf/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import axios, { AxiosInstance } from "axios";
import { getURL } from "../../shared/utils";

let axiosInstance: AxiosInstance | null = null;

/**
* Returns an AxiosInstance to be used to make API calls with a timeout of 10 seconds
* @returns {AxiosInstance} with the current configs URL as baseURL
*/
export const api = (): AxiosInstance => {
if (!axiosInstance) {
axiosInstance = axios.create({
baseURL: getURL(),
timeout: 20 * 1000,
});
}
return axiosInstance;
};
Loading
Loading