From 763309a53f58731a90e5bcd0343e92b64544fcfc Mon Sep 17 00:00:00 2001 From: Fran McDade Date: Wed, 4 Sep 2024 13:31:30 +1000 Subject: [PATCH 1/8] feat: add 'analysis' section (#18) --- .../AnalyzeGenome/analyzeGenome.styles.ts | 8 +++ .../AnalyzeGenome/analyzeGenome.tsx | 53 +++++++++++++++++++ .../AnalyzeGenome/common/constants.ts | 20 +++++++ .../app/components/Table/table.styles.ts | 40 ++++++++++++++ .../AnalyzeGenomeIcon/analyzeGenomeIcon.tsx | 21 ++++++++ .../ViewGenomeIcon/viewGenomeIcon.tsx | 23 ++++++++ data-catalog/app/components/index.ts | 1 + .../common/viewModelBuilders.ts | 16 ++++++ .../views/ExploreView/exploreView.styles.ts | 25 +++++++++ data-catalog/pages/[entityListType]/index.tsx | 4 +- data-catalog/routes/contants.ts | 3 ++ .../brc-analytics-catalog/category.ts | 2 + .../local/index/genomeEntityConfig.ts | 33 ++++++------ 13 files changed, 231 insertions(+), 18 deletions(-) create mode 100644 data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.styles.ts create mode 100644 data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx create mode 100644 data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/common/constants.ts create mode 100644 data-catalog/app/components/Table/table.styles.ts create mode 100644 data-catalog/app/components/common/CustomIcon/components/AnalyzeGenomeIcon/analyzeGenomeIcon.tsx create mode 100644 data-catalog/app/components/common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx create mode 100644 data-catalog/app/views/ExploreView/exploreView.styles.ts create mode 100644 data-catalog/routes/contants.ts diff --git a/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.styles.ts b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.styles.ts new file mode 100644 index 0000000..6df771f --- /dev/null +++ b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.styles.ts @@ -0,0 +1,8 @@ +import { ButtonGroup } from "@databiosphere/findable-ui/lib/components/common/ButtonGroup/buttonGroup"; +import styled from "@emotion/styled"; + +export const StyledButtonGroup = styled(ButtonGroup)` + .MuiButton-sizeSmall { + padding: 8px; + } +`; diff --git a/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx new file mode 100644 index 0000000..b57819d --- /dev/null +++ b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx @@ -0,0 +1,53 @@ +import { ANCHOR_TARGET } from "@databiosphere/findable-ui/lib/components/Links/common/entities"; +import { Button } from "@mui/material"; +import Router from "next/router"; +import { ROUTES } from "../../../../../../../routes/contants"; +import { BRCDataCatalogGenome } from "../../../../../../apis/catalog/brc-analytics-catalog/common/entities"; +import { AnalyzeGenomeIcon } from "../../../../../common/CustomIcon/components/AnalyzeGenomeIcon/analyzeGenomeIcon"; +import { ViewGenomeIcon } from "../../../../../common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon"; +import { StyledButtonGroup } from "./analyzeGenome.styles"; +import { + BUTTON_GROUP_PROPS, + BUTTON_PROPS, + ICON_PROPS, +} from "./common/constants"; + +export interface AnalyzeGenomeProps { + genome: BRCDataCatalogGenome; +} + +export const AnalyzeGenome = ({ genome }: AnalyzeGenomeProps): JSX.Element => { + const { genomeVersionAssemblyId, ucscBrowserUrl } = genome; + + const onAnalyze = (entityId: string): void => { + Router.push(`${ROUTES.GENOME}/${entityId}`); + }; + + const onView = (url: string | null): void => { + if (!url) return; + window.open(url, ANCHOR_TARGET.BLANK); + }; + + return ( + onAnalyze(genomeVersionAssemblyId)} + > + + , + , + ]} + /> + ); +}; diff --git a/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/common/constants.ts b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/common/constants.ts new file mode 100644 index 0000000..b8fa568 --- /dev/null +++ b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/common/constants.ts @@ -0,0 +1,20 @@ +import { CustomSVGIconProps } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/common/entities"; +import { + ButtonGroupProps as MButtonGroupProps, + ButtonProps, +} from "@mui/material"; + +export const BUTTON_PROPS: Partial = { + color: "secondary", + variant: "contained", +}; + +export const BUTTON_GROUP_PROPS: Partial = { + color: "secondary", + variant: "outlined", +}; + +export const ICON_PROPS: Partial = { + color: "inkLight", + fontSize: "small", +}; diff --git a/data-catalog/app/components/Table/table.styles.ts b/data-catalog/app/components/Table/table.styles.ts new file mode 100644 index 0000000..971764b --- /dev/null +++ b/data-catalog/app/components/Table/table.styles.ts @@ -0,0 +1,40 @@ +import { Table as DXTable } from "@databiosphere/findable-ui/lib/components/Detail/components/Table/table"; +import { mediaTabletUp } from "@databiosphere/findable-ui/lib/styles/common/mixins/breakpoints"; +import { smokeLightest } from "@databiosphere/findable-ui/lib/styles/common/mixins/colors"; +import { ThemeProps } from "@databiosphere/findable-ui/lib/theme/theme"; +import { css } from "@emotion/react"; +import styled from "@emotion/styled"; + +export const tableStyles = (props: ThemeProps) => css` + .MuiTable-root { + .MuiTableHead-root { + .MuiTableRow-root { + .MuiTableCell-root { + background-color: ${smokeLightest(props)}; + } + } + } + + ${mediaTabletUp(props)} { + .MuiTableHead-root, + .MuiTableBody-root { + .MuiTableRow-root { + .MuiTableCell-root { + min-height: 56px; + padding: 10px 16px; + + &.MuiTableCell-paddingCheckbox { + padding-right: 0; + } + } + } + } + } + } +`; + +export const Table = styled(DXTable)` + &.MuiTableContainer-root { + ${tableStyles} + } +` as typeof DXTable; diff --git a/data-catalog/app/components/common/CustomIcon/components/AnalyzeGenomeIcon/analyzeGenomeIcon.tsx b/data-catalog/app/components/common/CustomIcon/components/AnalyzeGenomeIcon/analyzeGenomeIcon.tsx new file mode 100644 index 0000000..e06b060 --- /dev/null +++ b/data-catalog/app/components/common/CustomIcon/components/AnalyzeGenomeIcon/analyzeGenomeIcon.tsx @@ -0,0 +1,21 @@ +import { CustomSVGIconProps } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/common/entities"; +import { SvgIcon } from "@mui/material"; + +/** + * Custom analyze genome icon. + */ + +export const AnalyzeGenomeIcon = ({ + fontSize = "xsmall", + viewBox = "0 0 18 18", + ...props /* Spread props to allow for Mui SvgIconProps specific prop overrides e.g. "htmlColor". */ +}: CustomSVGIconProps): JSX.Element => { + return ( + + + + ); +}; diff --git a/data-catalog/app/components/common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx b/data-catalog/app/components/common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx new file mode 100644 index 0000000..4281204 --- /dev/null +++ b/data-catalog/app/components/common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx @@ -0,0 +1,23 @@ +import { CustomSVGIconProps } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/common/entities"; +import { SvgIcon } from "@mui/material"; + +/** + * Custom view genome icon. + */ + +export const ViewGenomeIcon = ({ + fontSize = "xsmall", + viewBox = "0 0 18 18", + ...props /* Spread props to allow for Mui SvgIconProps specific prop overrides e.g. "htmlColor". */ +}: CustomSVGIconProps): JSX.Element => { + return ( + + + + ); +}; diff --git a/data-catalog/app/components/index.ts b/data-catalog/app/components/index.ts index 7bf33c0..e2a4a73 100644 --- a/data-catalog/app/components/index.ts +++ b/data-catalog/app/components/index.ts @@ -1,2 +1,3 @@ export { Link } from "@databiosphere/findable-ui/lib/components/Links/components/Link/link"; export { BasicCell } from "@databiosphere/findable-ui/lib/components/Table/components/TableCell/components/BasicCell/basicCell"; +export { AnalyzeGenome } from "./Table/components/TableCell/components/AnalyzeGenome/analyzeGenome"; diff --git a/data-catalog/app/viewModelBuilders/catalog/brc-analytics-catalog/common/viewModelBuilders.ts b/data-catalog/app/viewModelBuilders/catalog/brc-analytics-catalog/common/viewModelBuilders.ts index 730f465..e0bc015 100644 --- a/data-catalog/app/viewModelBuilders/catalog/brc-analytics-catalog/common/viewModelBuilders.ts +++ b/data-catalog/app/viewModelBuilders/catalog/brc-analytics-catalog/common/viewModelBuilders.ts @@ -1,6 +1,19 @@ import { BRCDataCatalogGenome } from "../../../../apis/catalog/brc-analytics-catalog/common/entities"; import * as C from "../../../../components/index"; +/** + * Build props for the genome analysis cell. + * @param genome - Genome entity. + * @returns Props to be used for the AnalyzeGenome component. + */ +export const buildAnalyzeGenome = ( + genome: BRCDataCatalogGenome +): React.ComponentProps => { + return { + genome, + }; +}; + /** * Build props for the chromosomes cell. * @param genome - Genome entity. @@ -80,6 +93,7 @@ export const buildSupercontigs = ( }; /** +<<<<<<< HEAD * Build props for the UCSC browser URL cell. * @param genome - Genome entity. * @returns Props to be used for the cell. @@ -94,6 +108,8 @@ export const buildUcscBrowserUrl = ( }; /** +======= +>>>>>>> 94283b9 (feat: add 'analysis' section (#18)) * Build props for the VEuPathDB project cell. * @param genome - Genome entity. * @returns Props to be used for the cell. diff --git a/data-catalog/app/views/ExploreView/exploreView.styles.ts b/data-catalog/app/views/ExploreView/exploreView.styles.ts new file mode 100644 index 0000000..9db5ae4 --- /dev/null +++ b/data-catalog/app/views/ExploreView/exploreView.styles.ts @@ -0,0 +1,25 @@ +import { mediaTabletDown } from "@databiosphere/findable-ui/lib/styles/common/mixins/breakpoints"; +import { ExploreView as DXExploreView } from "@databiosphere/findable-ui/lib/views/ExploreView/exploreView"; +import styled from "@emotion/styled"; +import { tableStyles } from "../../components/Table/table.styles"; + +export const StyledExploreView = styled(DXExploreView)` + & .MuiToolbar-root.MuiToolbar-table { + padding: 16px; + + .MuiButton-containedSecondary { + padding-bottom: 8px; + padding-top: 8px; + } + } + + & .MuiTableContainer-root { + ${tableStyles}; + } + + ${mediaTabletDown} { + .MuiPaper-table { + min-height: 64px; + } + } +`; diff --git a/data-catalog/pages/[entityListType]/index.tsx b/data-catalog/pages/[entityListType]/index.tsx index 2ba18e6..0f1ef9b 100644 --- a/data-catalog/pages/[entityListType]/index.tsx +++ b/data-catalog/pages/[entityListType]/index.tsx @@ -5,11 +5,11 @@ import { getEntityConfig } from "@databiosphere/findable-ui/lib/config/utils"; import { getEntityService } from "@databiosphere/findable-ui/lib/hooks/useEntityService"; import { EXPLORE_MODE } from "@databiosphere/findable-ui/lib/hooks/useExploreMode"; import { database } from "@databiosphere/findable-ui/lib/utils/database"; -import { ExploreView } from "@databiosphere/findable-ui/lib/views/ExploreView/exploreView"; import { config } from "app/config/config"; import fsp from "fs/promises"; import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next"; import { ParsedUrlQuery } from "querystring"; +import { StyledExploreView } from "../../app/views/ExploreView/exploreView.styles"; interface PageUrl extends ParsedUrlQuery { entityListType: string; @@ -61,7 +61,7 @@ const IndexPage = ({ ...props }: ListPageProps): JSX.Element => { if (!entityListType) return <>; - return ; + return ; }; /** diff --git a/data-catalog/routes/contants.ts b/data-catalog/routes/contants.ts new file mode 100644 index 0000000..6156061 --- /dev/null +++ b/data-catalog/routes/contants.ts @@ -0,0 +1,3 @@ +export const ROUTES = { + GENOME: "/genome", +}; diff --git a/data-catalog/site-config/brc-analytics-catalog/category.ts b/data-catalog/site-config/brc-analytics-catalog/category.ts index 4793942..3221b0b 100644 --- a/data-catalog/site-config/brc-analytics-catalog/category.ts +++ b/data-catalog/site-config/brc-analytics-catalog/category.ts @@ -1,4 +1,5 @@ export const BRC_DATA_CATALOG_CATEGORY_KEY = { + ANALYZE_GENOME: "analyzeGenome", CHROMOSOMES: "chromosomes", CONTIGS: "contigs", GENOME_VERSION_ASSEMBLY_ID: "genomeVersionAssemblyId", @@ -10,6 +11,7 @@ export const BRC_DATA_CATALOG_CATEGORY_KEY = { }; export const BRC_DATA_CATALOG_CATEGORY_LABEL = { + ANALYZE_GENOME: "Action", CHROMOSOMES: "Chromosomes", CONTIGS: "Contigs", GENOME_VERSION_ASSEMBLY_ID: "Genome Version/Assembly ID", diff --git a/data-catalog/site-config/brc-analytics-catalog/local/index/genomeEntityConfig.ts b/data-catalog/site-config/brc-analytics-catalog/local/index/genomeEntityConfig.ts index 092ec18..b5bcfea 100644 --- a/data-catalog/site-config/brc-analytics-catalog/local/index/genomeEntityConfig.ts +++ b/data-catalog/site-config/brc-analytics-catalog/local/index/genomeEntityConfig.ts @@ -55,6 +55,15 @@ export const genomeEntityConfig: EntityConfig = { label: "Genomes", list: { columns: [ + { + componentConfig: { + component: C.AnalyzeGenome, + viewBuilder: V.buildAnalyzeGenome, + } as ComponentConfig, + header: BRC_DATA_CATALOG_CATEGORY_LABEL.ANALYZE_GENOME, + id: BRC_DATA_CATALOG_CATEGORY_KEY.ANALYZE_GENOME, + width: "auto", + }, { componentConfig: { component: C.BasicCell, @@ -62,7 +71,7 @@ export const genomeEntityConfig: EntityConfig = { } as ComponentConfig, header: BRC_DATA_CATALOG_CATEGORY_LABEL.SPECIES, id: BRC_DATA_CATALOG_CATEGORY_KEY.SPECIES, - width: { max: "1.5fr", min: "212px" }, + width: { max: "1fr", min: "284px" }, }, { componentConfig: { @@ -71,16 +80,17 @@ export const genomeEntityConfig: EntityConfig = { } as ComponentConfig, header: BRC_DATA_CATALOG_CATEGORY_LABEL.STRAIN, id: BRC_DATA_CATALOG_CATEGORY_KEY.STRAIN, - width: { max: "1fr", min: "160px" }, + width: { max: "1fr", min: "124px" }, }, { + columnPinned: true, componentConfig: { component: C.BasicCell, viewBuilder: V.buildGenomeVersionAssemblyId, } as ComponentConfig, header: BRC_DATA_CATALOG_CATEGORY_LABEL.GENOME_VERSION_ASSEMBLY_ID, id: BRC_DATA_CATALOG_CATEGORY_KEY.GENOME_VERSION_ASSEMBLY_ID, - width: { max: "1fr", min: "160px" }, + width: { max: "1fr", min: "164px" }, }, { componentConfig: { @@ -89,7 +99,7 @@ export const genomeEntityConfig: EntityConfig = { } as ComponentConfig, header: BRC_DATA_CATALOG_CATEGORY_LABEL.VEUPATHDB_PROJECT, id: BRC_DATA_CATALOG_CATEGORY_KEY.VEUPATHDB_PROJECT, - width: { max: "1fr", min: "160px" }, + width: { max: "1fr", min: "140px" }, }, { componentConfig: { @@ -98,7 +108,7 @@ export const genomeEntityConfig: EntityConfig = { } as ComponentConfig, header: BRC_DATA_CATALOG_CATEGORY_LABEL.CONTIGS, id: BRC_DATA_CATALOG_CATEGORY_KEY.CONTIGS, - width: { max: "0.5fr", min: "112px" }, + width: { max: "0.5fr", min: "100px" }, }, { componentConfig: { @@ -107,7 +117,7 @@ export const genomeEntityConfig: EntityConfig = { } as ComponentConfig, header: BRC_DATA_CATALOG_CATEGORY_LABEL.SUPERCONTIGS, id: BRC_DATA_CATALOG_CATEGORY_KEY.SUPERCONTIGS, - width: { max: "0.5fr", min: "112px" }, + width: { max: "0.5fr", min: "140px" }, }, { componentConfig: { @@ -116,16 +126,7 @@ export const genomeEntityConfig: EntityConfig = { } as ComponentConfig, header: BRC_DATA_CATALOG_CATEGORY_LABEL.CHROMOSOMES, id: BRC_DATA_CATALOG_CATEGORY_KEY.CHROMOSOMES, - width: { max: "0.5fr", min: "112px" }, - }, - { - componentConfig: { - component: C.Link, - viewBuilder: V.buildUcscBrowserUrl, - } as ComponentConfig, - header: BRC_DATA_CATALOG_CATEGORY_LABEL.UCSC_BROWSER_URL, - id: BRC_DATA_CATALOG_CATEGORY_KEY.UCSC_BROWSER_URL, - width: { max: "1fr", min: "160px" }, + width: { max: "0.5fr", min: "142px" }, }, ], defaultSort: { From 7fafdb5ab88a4de0d482c521d505b9918bc6d522 Mon Sep 17 00:00:00 2001 From: Fran McDade Date: Wed, 4 Sep 2024 14:39:49 +1000 Subject: [PATCH 2/8] feat: linting (#18) --- .../TableCell/components/AnalyzeGenome/analyzeGenome.tsx | 2 +- .../CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx | 4 ++-- data-catalog/routes/contants.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx index b57819d..6b7670d 100644 --- a/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx +++ b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx @@ -20,7 +20,7 @@ export const AnalyzeGenome = ({ genome }: AnalyzeGenomeProps): JSX.Element => { const { genomeVersionAssemblyId, ucscBrowserUrl } = genome; const onAnalyze = (entityId: string): void => { - Router.push(`${ROUTES.GENOME}/${entityId}`); + Router.push(`${ROUTES.GENOMES}/${entityId}`); }; const onView = (url: string | null): void => { diff --git a/data-catalog/app/components/common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx b/data-catalog/app/components/common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx index 4281204..4e1d466 100644 --- a/data-catalog/app/components/common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx +++ b/data-catalog/app/components/common/CustomIcon/components/ViewGenomeIcon/viewGenomeIcon.tsx @@ -13,10 +13,10 @@ export const ViewGenomeIcon = ({ return ( ); diff --git a/data-catalog/routes/contants.ts b/data-catalog/routes/contants.ts index 6156061..62722ce 100644 --- a/data-catalog/routes/contants.ts +++ b/data-catalog/routes/contants.ts @@ -1,3 +1,3 @@ export const ROUTES = { - GENOME: "/genome", + GENOMES: "/genomes", }; From 8de2720cc3a5df7d206bf9d1d453f6054f93e452 Mon Sep 17 00:00:00 2001 From: Fran McDade Date: Wed, 4 Sep 2024 15:05:17 +1000 Subject: [PATCH 3/8] fix: remove reference to azul entities (#18) --- .../brc-analytics-catalog/common/entities.ts | 15 +++++++++++++ data-catalog/pages/[entityListType]/index.tsx | 22 +++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/data-catalog/app/apis/catalog/brc-analytics-catalog/common/entities.ts b/data-catalog/app/apis/catalog/brc-analytics-catalog/common/entities.ts index 33e58c7..78a67fb 100644 --- a/data-catalog/app/apis/catalog/brc-analytics-catalog/common/entities.ts +++ b/data-catalog/app/apis/catalog/brc-analytics-catalog/common/entities.ts @@ -1,3 +1,5 @@ +export type BRCCatalog = BRCDataCatalogGenome; + export interface BRCDataCatalogGenome { chromosomes: number; contigs: number; @@ -9,3 +11,16 @@ export interface BRCDataCatalogGenome { ucscBrowserUrl: string; vEuPathDbProject: string; } + +export interface EntitiesResponse { + hits: R[]; + pagination: EntitiesResponsePagination; + termFacets: Record; +} + +export interface EntitiesResponsePagination { + count: number; + pages: number; + size: number; + total: number; +} diff --git a/data-catalog/pages/[entityListType]/index.tsx b/data-catalog/pages/[entityListType]/index.tsx index 0f1ef9b..d5243f6 100644 --- a/data-catalog/pages/[entityListType]/index.tsx +++ b/data-catalog/pages/[entityListType]/index.tsx @@ -1,4 +1,3 @@ -import { AzulEntitiesStaticResponse } from "@databiosphere/findable-ui/lib/apis/azul/common/entities"; import { Main as DXMain } from "@databiosphere/findable-ui/lib/components/Layout/components/Main/main.styles"; import { EntityConfig } from "@databiosphere/findable-ui/lib/config/entities"; import { getEntityConfig } from "@databiosphere/findable-ui/lib/config/utils"; @@ -9,13 +8,18 @@ import { config } from "app/config/config"; import fsp from "fs/promises"; import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next"; import { ParsedUrlQuery } from "querystring"; +import { + BRCCatalog, + EntitiesResponse, +} from "../../app/apis/catalog/brc-analytics-catalog/common/entities"; import { StyledExploreView } from "../../app/views/ExploreView/exploreView.styles"; interface PageUrl extends ParsedUrlQuery { entityListType: string; } -interface ListPageProps extends AzulEntitiesStaticResponse { +interface ListPageProps { + data?: EntitiesResponse; entityListType: string; } @@ -25,7 +29,7 @@ interface ListPageProps extends AzulEntitiesStaticResponse { * @param entityConfig - Entity config. * @returns Promise. */ -const seedDatabase = async function seedDatabase( // TODO get rid of this duplicated code +const seedDatabase = async function seedDatabase( entityListType: string, entityConfig: EntityConfig ): Promise { @@ -56,10 +60,10 @@ const seedDatabase = async function seedDatabase( // TODO get rid of this duplic * @param props.entityListType - Entity list type. * @returns ExploreView component. */ -const IndexPage = ({ +const IndexPage = ({ entityListType, ...props -}: ListPageProps): JSX.Element => { +}: ListPageProps): JSX.Element => { if (!entityListType) return <>; return ; }; @@ -87,9 +91,9 @@ export const getStaticPaths: GetStaticPaths = async () => { * @param context - Object containing values related to the current context. * @returns static props. */ -export const getStaticProps: GetStaticProps< - AzulEntitiesStaticResponse -> = async (context: GetStaticPropsContext) => { +export const getStaticProps: GetStaticProps> = async ( + context: GetStaticPropsContext +) => { const appConfig = config(); const { entityListType } = context.params as PageUrl; const { entities } = appConfig; @@ -97,7 +101,7 @@ export const getStaticProps: GetStaticProps< const { exploreMode } = entityConfig; const { fetchAllEntities } = getEntityService(entityConfig, undefined); // Determine the type of fetch, either from an API endpoint or a TSV. - const props: AzulEntitiesStaticResponse = { entityListType }; + const props: ListPageProps = { entityListType }; // Seed database. if (exploreMode === EXPLORE_MODE.CS_FETCH_CS_FILTERING) { From eff9de782347da60e98680eb73a3f4444e387118 Mon Sep 17 00:00:00 2001 From: Fran McDade Date: Wed, 4 Sep 2024 16:10:23 +1000 Subject: [PATCH 4/8] feat: added genome entity page (#18) --- .../brc-analytics-catalog/common/utils.ts | 2 +- data-catalog/app/utils/seedDatabase.ts | 36 +++ .../pages/[entityListType]/[...params].tsx | 220 ++++++++++++++++++ data-catalog/pages/[entityListType]/index.tsx | 47 +--- .../entity/genome/analysisMethodMainColumn.ts | 1 + .../genome/analysisMethodsSideColumn.ts | 1 + .../local/index/genomeEntityConfig.ts | 11 +- 7 files changed, 275 insertions(+), 43 deletions(-) create mode 100644 data-catalog/app/utils/seedDatabase.ts create mode 100644 data-catalog/pages/[entityListType]/[...params].tsx create mode 100644 data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodMainColumn.ts create mode 100644 data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodsSideColumn.ts diff --git a/data-catalog/app/apis/catalog/brc-analytics-catalog/common/utils.ts b/data-catalog/app/apis/catalog/brc-analytics-catalog/common/utils.ts index 962db94..bcca8b8 100644 --- a/data-catalog/app/apis/catalog/brc-analytics-catalog/common/utils.ts +++ b/data-catalog/app/apis/catalog/brc-analytics-catalog/common/utils.ts @@ -1,5 +1,5 @@ import { BRCDataCatalogGenome } from "./entities"; export function getGenomeId(genome: BRCDataCatalogGenome): string { - return genome.organism; + return genome.genomeVersionAssemblyId; } diff --git a/data-catalog/app/utils/seedDatabase.ts b/data-catalog/app/utils/seedDatabase.ts new file mode 100644 index 0000000..29c739e --- /dev/null +++ b/data-catalog/app/utils/seedDatabase.ts @@ -0,0 +1,36 @@ +import { EntityConfig } from "@databiosphere/findable-ui/lib/config/entities"; +import { database } from "@databiosphere/findable-ui/lib/utils/database"; +import fsp from "fs/promises"; + +/** + * Seed database. + * @param entityListType - Entity list type. + * @param entityConfig - Entity config. + * @returns Promise. + */ +export const seedDatabase = async function seedDatabase( + entityListType: string, + entityConfig: EntityConfig +): Promise { + const { entityMapper, label, staticLoadFile } = entityConfig; + + if (!staticLoadFile) { + throw new Error(`staticLoadFile not found for entity ${label}`); + } + + // Build database from configured JSON, if any. + let jsonText; + try { + jsonText = await fsp.readFile(staticLoadFile, "utf8"); + } catch (e) { + throw new Error(`File ${staticLoadFile} not found for entity ${label}`); + } + + const object = JSON.parse(jsonText); + const entities = entityMapper + ? Object.values(object).map(entityMapper) + : Object.values(object); // Client-side fetched entities are mapped prior to dispatch to explore state. + + // Seed entities. + database.get().seed(entityListType, entities); +}; diff --git a/data-catalog/pages/[entityListType]/[...params].tsx b/data-catalog/pages/[entityListType]/[...params].tsx new file mode 100644 index 0000000..ebcad79 --- /dev/null +++ b/data-catalog/pages/[entityListType]/[...params].tsx @@ -0,0 +1,220 @@ +import { + PARAMS_INDEX_TAB, + PARAMS_INDEX_UUID, +} from "@databiosphere/findable-ui/lib/common/constants"; +import { + BackPageTabConfig, + EntityConfig, +} from "@databiosphere/findable-ui/lib/config/entities"; +import { getEntityConfig } from "@databiosphere/findable-ui/lib/config/utils"; +import { getEntityService } from "@databiosphere/findable-ui/lib/hooks/useEntityService"; +import { EXPLORE_MODE } from "@databiosphere/findable-ui/lib/hooks/useExploreMode"; +import { config } from "app/config/config"; +import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next"; +import { ParsedUrlQuery } from "querystring"; +import { + BRCCatalog, + EntitiesResponse, +} from "../../app/apis/catalog/brc-analytics-catalog/common/entities"; +import { seedDatabase } from "../../app/utils/seedDatabase"; + +const setOfProcessedIds = new Set(); + +interface StaticPath { + params: PageUrl; +} + +interface PageUrl extends ParsedUrlQuery { + entityListType: string; + params: string[]; +} + +export interface EntityPageProps { + data?: R; + entityListType: string; +} + +/** + * Entity detail view page. + * @param props - Entity detail view page props. + * @returns Entity detail view component. + */ +const EntityDetailPage = (props: EntityPageProps): JSX.Element => { + if (!props.entityListType) return <>; + return
{props.entityListType}
; +}; + +/** + * getStaticPaths - return the list of paths to prerender for each entity type and its tabs. + * @returns Promise>. + */ +export const getStaticPaths: GetStaticPaths = async () => { + const appConfig = config(); + const { entities } = appConfig; + + const paths: StaticPath[] = []; + + for (const entityConfig of entities) { + const { exploreMode, route: entityListType } = entityConfig; + // Process static paths. + // Client-side fetch, client-side filtering. + if (exploreMode === EXPLORE_MODE.CS_FETCH_CS_FILTERING) { + await seedDatabase(entityListType, entityConfig); + const entitiesResponse: EntitiesResponse = await getEntities( + entityConfig + ); + processEntityPaths(entityConfig, entitiesResponse, paths); + } + } + + return { + fallback: false, + paths, + }; +}; + +export const getStaticProps: GetStaticProps< + EntityPageProps +> = async ({ params }: GetStaticPropsContext) => { + const appConfig = config(); + const { entities } = appConfig; + const { entityListType, params: slug } = params || {}; + + if (typeof entityListType !== "string") return { notFound: true }; + if (!Array.isArray(slug)) return { notFound: true }; + + const entityConfig = getEntityConfig(entities, entityListType); + const entityTab = getSlugPath(slug, PARAMS_INDEX_TAB); + const entityId = getSlugPath(slug, PARAMS_INDEX_UUID); + + if (!entityConfig || !entityId) return { notFound: true }; + + const props: EntityPageProps = { entityListType }; + + // Process entity props. + await processEntityProps(entityConfig, entityTab, entityId, props); + + return { + props, + }; +}; + +export default EntityDetailPage; + +/** + * Fetches entities response for the given entity config. + * @param entityConfig - Entity config. + * @returns entities response. + */ +async function getEntities( + entityConfig: EntityConfig +): Promise> { + const { fetchAllEntities, path } = getEntityService(entityConfig, undefined); + return await fetchAllEntities(path, undefined, undefined, undefined); +} + +/** + * Fetches the entity for the given entity ID. + * @param entityConfig - Entity config. + * @param entityId - Entity ID. + * @returns entity response. + */ +async function getEntity( + entityConfig: EntityConfig, + entityId: string +): Promise { + const { fetchEntityDetail, path } = getEntityService(entityConfig, undefined); + return await fetchEntityDetail( + entityId, + path, + undefined, + undefined, + undefined, + true + ); +} + +/** + * Returns the slug path for the given slug and slug index. + * @param slug - Slug. + * @param slugIndex - Slug index. + * @returns path. + */ +function getSlugPath(slug: string[], slugIndex: number): string | undefined { + return slug[slugIndex]; +} + +/** + * Returns the list of tab routes for the given tab config. + * @param tabs - Tab config. + * @returns tab routes. + */ +function getTabRoutes(tabs: BackPageTabConfig[]): string[] { + return tabs.map(({ route }) => route) ?? []; +} + +/** + * Processes the static paths for the given entity response. + * @param entityConfig - Entity config. + * @param entitiesResponse - Entities response. + * @param paths - Static paths. + */ +function processEntityPaths( + entityConfig: EntityConfig, + entitiesResponse: EntitiesResponse, + paths: StaticPath[] +): void { + const { detail, route: entityListType } = entityConfig; + const { tabs } = detail; + const { hits: entities } = entitiesResponse; + const tabRoutes = getTabRoutes(tabs); + for (const entity of entities) { + const entityId = entityConfig.getId?.(entity); + if (!entityId) continue; + // Skip the entity if it has already been processed. + if (setOfProcessedIds.has(entityId)) continue; + setOfProcessedIds.add(entityId); + // Generate a path for each entity and each tab. + for (const tabRoute of tabRoutes) { + const params = [entityId, tabRoute]; + paths.push({ + params: { + entityListType, + params, + }, + }); + } + } +} + +/** + * Processes the entity props for the given entity page. + * @param entityConfig - Entity config. + * @param entityTab - Entity tab. + * @param entityId - Entity ID. + * @param props - Entity detail page props. + */ +async function processEntityProps( + entityConfig: EntityConfig, + entityTab = "", + entityId: string, + props: EntityPageProps +): Promise { + const { + detail: { staticLoad }, + exploreMode, + } = entityConfig; + // Early exit; return if the entity is not to be statically loaded. + if (!staticLoad) return; + // When the entity detail is to be fetched from API, we only do so for the first tab. + if (exploreMode === EXPLORE_MODE.SS_FETCH_SS_FILTERING && entityTab) return; + if (exploreMode === EXPLORE_MODE.CS_FETCH_CS_FILTERING) { + // Seed database. + await seedDatabase(entityConfig.route, entityConfig); + } + // Fetch entity detail, either from database or API. + const entityResponse = (await getEntity(entityConfig, entityId)) as R; + if (entityResponse) { + props.data = entityResponse; + } +} diff --git a/data-catalog/pages/[entityListType]/index.tsx b/data-catalog/pages/[entityListType]/index.tsx index d5243f6..5ddac9c 100644 --- a/data-catalog/pages/[entityListType]/index.tsx +++ b/data-catalog/pages/[entityListType]/index.tsx @@ -1,59 +1,26 @@ import { Main as DXMain } from "@databiosphere/findable-ui/lib/components/Layout/components/Main/main.styles"; -import { EntityConfig } from "@databiosphere/findable-ui/lib/config/entities"; import { getEntityConfig } from "@databiosphere/findable-ui/lib/config/utils"; import { getEntityService } from "@databiosphere/findable-ui/lib/hooks/useEntityService"; import { EXPLORE_MODE } from "@databiosphere/findable-ui/lib/hooks/useExploreMode"; -import { database } from "@databiosphere/findable-ui/lib/utils/database"; import { config } from "app/config/config"; -import fsp from "fs/promises"; import { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next"; import { ParsedUrlQuery } from "querystring"; import { BRCCatalog, EntitiesResponse, } from "../../app/apis/catalog/brc-analytics-catalog/common/entities"; +import { seedDatabase } from "../../app/utils/seedDatabase"; import { StyledExploreView } from "../../app/views/ExploreView/exploreView.styles"; interface PageUrl extends ParsedUrlQuery { entityListType: string; } -interface ListPageProps { +interface EntitiesPageProps { data?: EntitiesResponse; entityListType: string; } -/** - * Seed database. - * @param entityListType - Entity list type. - * @param entityConfig - Entity config. - * @returns Promise. - */ -const seedDatabase = async function seedDatabase( - entityListType: string, - entityConfig: EntityConfig -): Promise { - const { label, staticLoadFile } = entityConfig; - - if (!staticLoadFile) { - throw new Error(`staticLoadFile not found for entity entity ${label}`); - } - - // Build database from configured JSON, if any. - let jsonText; - try { - jsonText = await fsp.readFile(staticLoadFile, "utf8"); - } catch (e) { - throw new Error(`File ${staticLoadFile} not found for entity ${label}`); - } - - const object = JSON.parse(jsonText); - const entities = Object.values(object); // Client-side fetched entities are mapped prior to dispatch to explore state. - - // Seed entities. - database.get().seed(entityListType, entities); -}; - /** * Explore view page. * @param props - Explore view page props. @@ -63,7 +30,7 @@ const seedDatabase = async function seedDatabase( const IndexPage = ({ entityListType, ...props -}: ListPageProps): JSX.Element => { +}: EntitiesPageProps): JSX.Element => { if (!entityListType) return <>; return ; }; @@ -91,9 +58,9 @@ export const getStaticPaths: GetStaticPaths = async () => { * @param context - Object containing values related to the current context. * @returns static props. */ -export const getStaticProps: GetStaticProps> = async ( - context: GetStaticPropsContext -) => { +export const getStaticProps: GetStaticProps< + EntitiesPageProps +> = async (context: GetStaticPropsContext) => { const appConfig = config(); const { entityListType } = context.params as PageUrl; const { entities } = appConfig; @@ -101,7 +68,7 @@ export const getStaticProps: GetStaticProps> = async ( const { exploreMode } = entityConfig; const { fetchAllEntities } = getEntityService(entityConfig, undefined); // Determine the type of fetch, either from an API endpoint or a TSV. - const props: ListPageProps = { entityListType }; + const props: EntitiesPageProps = { entityListType }; // Seed database. if (exploreMode === EXPLORE_MODE.CS_FETCH_CS_FILTERING) { diff --git a/data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodMainColumn.ts b/data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodMainColumn.ts new file mode 100644 index 0000000..33115f7 --- /dev/null +++ b/data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodMainColumn.ts @@ -0,0 +1 @@ +export const mainColumn = []; diff --git a/data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodsSideColumn.ts b/data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodsSideColumn.ts new file mode 100644 index 0000000..860ab0e --- /dev/null +++ b/data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodsSideColumn.ts @@ -0,0 +1 @@ +export const sideColumn = []; diff --git a/data-catalog/site-config/brc-analytics-catalog/local/index/genomeEntityConfig.ts b/data-catalog/site-config/brc-analytics-catalog/local/index/genomeEntityConfig.ts index b5bcfea..c744e42 100644 --- a/data-catalog/site-config/brc-analytics-catalog/local/index/genomeEntityConfig.ts +++ b/data-catalog/site-config/brc-analytics-catalog/local/index/genomeEntityConfig.ts @@ -13,6 +13,7 @@ import { BRC_DATA_CATALOG_CATEGORY_KEY, BRC_DATA_CATALOG_CATEGORY_LABEL, } from "../../category"; +import { mainColumn as analysisMethodsMainColumn } from "../entity/genome/analysisMethodMainColumn"; /** * Entity config object responsible to config anything related to the /genomes route. @@ -45,8 +46,14 @@ export const genomeEntityConfig: EntityConfig = { }, detail: { detailOverviews: [], - staticLoad: false, - tabs: [], + staticLoad: true, + tabs: [ + { + label: "Analysis Methods", + mainColumn: analysisMethodsMainColumn, + route: "", + }, + ], top: [], }, exploreMode: EXPLORE_MODE.CS_FETCH_CS_FILTERING, From 5547d54bfc468a1e6c51006ffc02995141dbd9e5 Mon Sep 17 00:00:00 2001 From: Fran McDade Date: Wed, 4 Sep 2024 18:22:38 +1000 Subject: [PATCH 5/8] feat: added title and breadcrumbs to genome entity page (#18) --- .../brc-analytics-catalog/common/utils.ts | 5 ++ .../BackButton/backButton.styles.ts | 10 +++ .../components/BackButton/backButton.tsx | 32 ++++++++++ .../DetailViewHero/detailViewHero.styles.ts | 59 +++++++++++++++++ .../DetailViewHero/detailViewHero.tsx | 51 +++++++++++++++ .../AnalyzeGenome/analyzeGenome.tsx | 1 + data-catalog/app/components/index.ts | 2 + data-catalog/app/config/config.ts | 1 + .../common/viewModelBuilders.ts | 63 ++++++++++++------- .../app/views/EntityView/entityView.tsx | 54 ++++++++++++++++ .../pages/[entityListType]/[...params].tsx | 3 +- .../brc-analytics-catalog/local/config.ts | 20 +++++- .../entity/genome/analysisMethodMainColumn.ts | 4 +- .../genome/analysisMethodsSideColumn.ts | 4 +- .../local/entity/genome/analysisMethodsTop.ts | 13 ++++ .../local/index/genomeEntityConfig.ts | 18 ++++-- data-catalog/site-config/common/entities.ts | 20 ++++++ 17 files changed, 327 insertions(+), 33 deletions(-) create mode 100644 data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/components/BackButton/backButton.styles.ts create mode 100644 data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/components/BackButton/backButton.tsx create mode 100644 data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/detailViewHero.styles.ts create mode 100644 data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/detailViewHero.tsx create mode 100644 data-catalog/app/views/EntityView/entityView.tsx create mode 100644 data-catalog/site-config/brc-analytics-catalog/local/entity/genome/analysisMethodsTop.ts create mode 100644 data-catalog/site-config/common/entities.ts diff --git a/data-catalog/app/apis/catalog/brc-analytics-catalog/common/utils.ts b/data-catalog/app/apis/catalog/brc-analytics-catalog/common/utils.ts index bcca8b8..73363b8 100644 --- a/data-catalog/app/apis/catalog/brc-analytics-catalog/common/utils.ts +++ b/data-catalog/app/apis/catalog/brc-analytics-catalog/common/utils.ts @@ -3,3 +3,8 @@ import { BRCDataCatalogGenome } from "./entities"; export function getGenomeId(genome: BRCDataCatalogGenome): string { return genome.genomeVersionAssemblyId; } + +export function getGenomeTitle(genome?: BRCDataCatalogGenome): string { + if (!genome) return ""; + return `${genome.species} - ${genome.strain}`; +} diff --git a/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/components/BackButton/backButton.styles.ts b/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/components/BackButton/backButton.styles.ts new file mode 100644 index 0000000..8d60439 --- /dev/null +++ b/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/components/BackButton/backButton.styles.ts @@ -0,0 +1,10 @@ +import { mediaDesktopSmallUp } from "@databiosphere/findable-ui/lib/styles/common/mixins/breakpoints"; +import styled from "@emotion/styled"; +import { HeroActions as DetailViewActions } from "../../detailViewHero.styles"; + +export const HeroActions = styled(DetailViewActions)` + ${mediaDesktopSmallUp} { + align-self: flex-start; + margin: 8px 0; + } +`; diff --git a/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/components/BackButton/backButton.tsx b/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/components/BackButton/backButton.tsx new file mode 100644 index 0000000..4adab81 --- /dev/null +++ b/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/components/BackButton/backButton.tsx @@ -0,0 +1,32 @@ +import { SouthIcon } from "@databiosphere/findable-ui/lib/components/common/CustomIcon/components/SouthIcon/southIcon"; +import { IconButton } from "@mui/material"; +import { useRouter } from "next/router"; +import { useCallback } from "react"; +import { HeroActions } from "./backButton.styles"; + +export const BackButton = (): JSX.Element => { + const { asPath, push } = useRouter(); + const onNavigate = useCallback( + () => push(getNextPath(asPath)), + [asPath, push] + ); + return ( + + + + + + ); +}; + +/** + * Returns the next path to navigate to when the back button is clicked. + * The back button will navigate to the parent path of the current path. + * @param asPath - Current path. + * @returns next path. + */ +function getNextPath(asPath: string): string { + const path = asPath.split("/"); + path.pop(); + return path.join("/"); +} diff --git a/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/detailViewHero.styles.ts b/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/detailViewHero.styles.ts new file mode 100644 index 0000000..9f853e0 --- /dev/null +++ b/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/detailViewHero.styles.ts @@ -0,0 +1,59 @@ +import { + mediaDesktopSmallUp, + mediaTabletUp, +} from "@databiosphere/findable-ui/lib/styles/common/mixins/breakpoints"; +import styled from "@emotion/styled"; + +export const DetailViewHero = styled.div` + display: grid; + gap: 16px; + grid-column: 1 / -1; +`; + +export const DetailViewHeroHeadline = styled.div` + display: flex; + flex-direction: column; + gap: 16px; + + ${mediaDesktopSmallUp} { + flex-direction: row; + } +`; + +export const HeroHeader = styled.div` + display: flex; + flex: 1; + flex-direction: column; + gap: 4px; +`; + +export const HeroTitle = styled.div` + display: flex; + flex-direction: column; + gap: 8px; + + ${mediaTabletUp} { + align-items: center; + flex-direction: row; + } + + .MuiTypography-text-heading { + max-width: 726px; + } +`; + +export const Titles = styled.div` + display: grid; + gap: 4px; +`; + +export const HeroActions = styled.div` + align-items: center; + align-self: flex-start; + display: flex; + gap: 8px; + + ${mediaDesktopSmallUp} { + align-self: center; + } +`; diff --git a/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/detailViewHero.tsx b/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/detailViewHero.tsx new file mode 100644 index 0000000..db1fe88 --- /dev/null +++ b/data-catalog/app/components/Layout/components/Detail/components/DetailViewHero/detailViewHero.tsx @@ -0,0 +1,51 @@ +import { BackPageTabs } from "@databiosphere/findable-ui/lib/components/Layout/components/BackPage/backPageView.styles"; +import { SubTitle } from "@databiosphere/findable-ui/lib/components/Layout/components/BackPage/components/BackPageHero/components/SubTitle/subTitle"; +import { TEXT_HEADING } from "@databiosphere/findable-ui/lib/theme/common/typography"; +import { HeroTitle as Typography } from "@databiosphere/findable-ui/src/components/common/Title/title.styles"; +import { ReactNode } from "react"; +import { BackButton } from "./components/BackButton/backButton"; +import { + DetailViewHero as DetailViewHeroLayout, + DetailViewHeroHeadline, + HeroHeader, + HeroTitle, + Titles, +} from "./detailViewHero.styles"; + +export interface DetailViewHeroProps { + breadcrumbs?: ReactNode; + subTitle?: ReactNode; + tabs?: ReactNode; + title?: ReactNode; +} + +export const DetailViewHero = ({ + breadcrumbs, + subTitle, + tabs, + title, +}: DetailViewHeroProps): JSX.Element => { + return ( + + {(breadcrumbs || title) && ( + + + + {breadcrumbs} + + + {title && ( + + {title} + + )} + {subTitle && } + + + + + )} + {tabs && {tabs}} + + ); +}; diff --git a/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx index 6b7670d..7da7935 100644 --- a/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx +++ b/data-catalog/app/components/Table/components/TableCell/components/AnalyzeGenome/analyzeGenome.tsx @@ -34,6 +34,7 @@ export const AnalyzeGenome = ({ genome }: AnalyzeGenomeProps): JSX.Element => { Buttons={[