Skip to content

Commit

Permalink
feat: support unifying export views #4102 (#312)
Browse files Browse the repository at this point in the history
  • Loading branch information
MillenniumFalconMechanic authored Jan 30, 2025
1 parent 0375d48 commit cbeb6e5
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 5 deletions.
6 changes: 4 additions & 2 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export const COLLATOR_CASE_INSENSITIVE = new Intl.Collator("en", {
* Values to determine the index for each param.
* https://host/explore/[slug]/[param-uuid]/[param-tab]
* - ExploreView 0 returns the current UUID
* - ExploreView 1 returns the current tab
* - ExploreView 1 returns the current tab (or choose export)
* - ExportView 2 returns the export method
*/
export const PARAMS_INDEX_UUID = 0;
export const PARAMS_INDEX_TAB = 1;
export const PARAMS_INDEX_TAB = 1; // Note "export" (i.e. not a tab) can possibly be at this index too
export const PARAMS_INDEX_EXPORT_METHOD = 2;
2 changes: 2 additions & 0 deletions src/config/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,10 @@ export interface EntityConfig<T = any, I = any> extends TabConfig {
entityMapper?: EntityMapper<T, I>;
exploreMode: ExploreMode;
explorerTitle?: SiteConfig["explorerTitle"];
export?: ExportConfig;
getId?: GetIdFunction<T>;
getTitle?: GetTitleFunction<T>;
hideTabs?: boolean;
list: ListConfig<T>;
listView?: ListViewConfig;
options?: Options;
Expand Down
16 changes: 16 additions & 0 deletions src/hooks/useEntityExportConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ExportConfig } from "../config/entities";
import { useConfig } from "./useConfig";

/**
* Returns the export configuration for the given entity.
* @returns export configuration.
*/
export const useEntityExportConfig = (): ExportConfig => {
const { entityConfig } = useConfig();

if (!entityConfig.export) {
throw new Error("This entity config does not have an export field set");
}

return entityConfig.export;
};
12 changes: 9 additions & 3 deletions src/views/EntityDetailView/entityDetailView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ export const EntityDetailView = (props: EntityDetailViewProps): JSX.Element => {
const { push, query } = useRouter();
const { entityConfig } = useConfig();
const { mainColumn, sideColumn } = currentTab;
const { detail, route: entityRoute } = entityConfig;
const { detail, hideTabs, route: entityRoute } = entityConfig;
const { detailOverviews, top } = detail;
const uuid = query.params?.[PARAMS_INDEX_UUID];
const isDetailOverview = detailOverviews?.includes(currentTab.label);
const tabs = getTabs(entityConfig);
const tabs = hideTabs ? [] : getTabs(entityConfig);
const title = useEntityHeadTitle(response);

if (!response) {
Expand Down Expand Up @@ -78,7 +78,13 @@ export const EntityDetailView = (props: EntityDetailViewProps): JSX.Element => {
<ComponentCreator components={sideColumn} response={response} />
) : undefined
}
Tabs={<Tabs onTabChange={onTabChange} tabs={tabs} value={tabRoute} />}
Tabs={
hideTabs ? (
<></>
) : (
<Tabs onTabChange={onTabChange} tabs={tabs} value={tabRoute} />
)
}
top={<ComponentCreator components={top} response={response} />}
/>
</Fragment>
Expand Down
67 changes: 67 additions & 0 deletions src/views/EntityExportMethodView/entityExportMethodView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useRouter } from "next/router";
import type { ParsedUrlQuery } from "querystring";
import React from "react";
import { EntityDetailViewProps } from "views/EntityDetailView/entityDetailView";
import { PARAMS_INDEX_EXPORT_METHOD } from "../../common/constants";
import { ComponentCreator } from "../../components/ComponentCreator/ComponentCreator";
import { BackPageView } from "../../components/Layout/components/BackPage/backPageView";
import { ExportMethodConfig } from "../../config/entities";
import { useEntityExportConfig } from "../../hooks/useEntityExportConfig";
import { useFetchEntity } from "../../hooks/useFetchEntity";
import { useUpdateURLCatalogParams } from "../../hooks/useUpdateURLCatalogParam";

export const EntityExportMethodView = (
props: EntityDetailViewProps
): JSX.Element => {
// Update the catalog param if necessary.
useUpdateURLCatalogParams();

// Grab the entity to be exported.
const { response } = useFetchEntity(props);

// Get the column definitions for the entity export.
const { query } = useRouter();
const { exportMethods, tabs } = useEntityExportConfig();
const { sideColumn } = tabs[0];
const { mainColumn, top } = getExportMethodConfig(exportMethods, query) || {};

// Wait for the entity to be fetched.
if (!response) {
return <span></span>;
}

return (
<BackPageView
mainColumn={
<ComponentCreator components={mainColumn || []} response={response} />
}
sideColumn={
sideColumn ? (
<ComponentCreator components={sideColumn} response={response} />
) : undefined
}
top={<ComponentCreator components={top || []} response={response} />}
/>
);
};

/**
* Returns the export method configuration for the given pathname.
* @param exportMethods - Export methods config.
* @param query - Router query object.
* @returns export method configuration.
*/
function getExportMethodConfig(
exportMethods: ExportMethodConfig[],
query: ParsedUrlQuery
): ExportMethodConfig | undefined {
// Determine the selected export method from the URL.
const exportMethodRoute = query.params?.[PARAMS_INDEX_EXPORT_METHOD];
if (!exportMethodRoute) {
return;
}
// Find the config for the selected export method.
return exportMethods.find(({ route }) => {
return route.includes(exportMethodRoute);
});
}
39 changes: 39 additions & 0 deletions src/views/EntityExportView/entityExportView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from "react";
import { EntityDetailViewProps } from "views/EntityDetailView/entityDetailView";
import { ComponentCreator } from "../../components/ComponentCreator/ComponentCreator";
import { BackPageView } from "../../components/Layout/components/BackPage/backPageView";
import { useEntityExportConfig } from "../../hooks/useEntityExportConfig";
import { useFetchEntity } from "../../hooks/useFetchEntity";
import { useUpdateURLCatalogParams } from "../../hooks/useUpdateURLCatalogParam";

export const EntityExportView = (props: EntityDetailViewProps): JSX.Element => {
// Update the catalog param if necessary.
useUpdateURLCatalogParams();

// Grab the entity to be exported.
const { response } = useFetchEntity(props);

// Get the column definitions for the entity export.
const { tabs, top } = useEntityExportConfig();
const currentTab = tabs[0];
const { mainColumn, sideColumn } = currentTab;

// Wait for the entity to be fetched.
if (!response) {
return <span></span>;
}

return (
<BackPageView
mainColumn={
<ComponentCreator components={mainColumn} response={response} />
}
sideColumn={
sideColumn ? (
<ComponentCreator components={sideColumn} response={response} />
) : undefined
}
top={<ComponentCreator components={top} response={response} />}
/>
);
};

0 comments on commit cbeb6e5

Please sign in to comment.