Skip to content

Commit 330b028

Browse files
authored
Limit facet options and render them nicely (#243)
1 parent 2b27ad5 commit 330b028

File tree

4 files changed

+40
-6
lines changed

4 files changed

+40
-6
lines changed

src/components/browse/dataset/datasetHeader.tsx

+10-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { SearchResponseModel } from "../../../models/dataset";
55
import { useNavigate } from "react-router-dom";
66
import { querySearchService } from "../../../api/browse";
77
import { handleFilterAndSearch } from "../shared";
8+
import { renderFacetOption } from "../sidebar/filter";
89

910
interface DatasetHeaderProps {
1011
dsCount: number;
@@ -23,6 +24,12 @@ interface DatasetHeaderProps {
2324
setPage: Dispatch<SetStateAction<number>>;
2425
}
2526

27+
function renderItem(item: string): string {
28+
let facetAndValue = item.split("|", 2)[1];
29+
let [facet, value] = facetAndValue.split(": ", 2);
30+
return facet + ": " + renderFacetOption(value, facet);
31+
}
32+
2633
/** Section at the top of Browse page. It contains search keywords, applied filters and datasets count found. */
2734
const DatasetHeader = (props: DatasetHeaderProps) => {
2835
const navigate = useNavigate();
@@ -147,13 +154,13 @@ const DatasetHeader = (props: DatasetHeaderProps) => {
147154
)}
148155
{getFilterParamsList().map((item, idx) => (
149156
<Badge
150-
key={item.split("|")[1]}
157+
key={item.split("|", 2)[1]}
151158
className="py-1 m-0 me-2 text-black fs-7 border text-capitalize bg-white border-secondary fw-normal"
152159
style={{
153160
whiteSpace: "nowrap",
154161
textOverflow: "ellipsis",
155162
}}
156-
title={item.split("|")[1]}
163+
title={renderItem(item)}
157164
>
158165
<div className="lh-1">
159166
<Row className="flex-nowrap">
@@ -164,7 +171,7 @@ const DatasetHeader = (props: DatasetHeaderProps) => {
164171
/>
165172
</Col>
166173
<Col className="ps-0 align-items-center d-flex">
167-
<span className="px-1 mb-0">{item.split("|")[1]}</span>
174+
<span className="px-1 mb-0">{renderItem(item)}</span>
168175
</Col>
169176
</Row>
170177
</div>

src/components/browse/sidebar/filter.tsx

+26-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,31 @@ import React, { Dispatch, SetStateAction } from "react";
22
import { Form, Col, Container, Row, Badge } from "react-bootstrap";
33
import { FacetModel, FacetFilterModel } from "../../../models/facets";
44

5+
const ALWAYS_TITLE_CASE_OPTIONS = /Experiment|Study Type/i;
6+
7+
const SOMETIMES_TITLE_CASE_OPTIONS = /Platform|Analysis Level/i;
8+
9+
const TITLE_CASE_WORDS = /Illumina|Total/gi;
10+
11+
const UPPER_CASE_REPLACE = ["HiSeq"];
12+
13+
export function renderFacetOption(value: string, facet: string): string {
14+
if (!value) return "unspecified";
15+
value = value.replace(/_/g, " ");
16+
if (facet && ALWAYS_TITLE_CASE_OPTIONS.test(facet)) {
17+
value = value.toLowerCase().replace(/\b\w/g, (char) => char.toUpperCase());
18+
} else if (facet && SOMETIMES_TITLE_CASE_OPTIONS.test(facet)) {
19+
value = value.replace(
20+
TITLE_CASE_WORDS,
21+
(word) => word.slice(0, 1).toUpperCase() + word.slice(1).toLowerCase()
22+
);
23+
for (let word of UPPER_CASE_REPLACE) {
24+
value = value.replace(word.toUpperCase(), word);
25+
}
26+
}
27+
return value;
28+
}
29+
530
interface FilterProps {
631
facet: FacetModel;
732
check: Map<string, boolean>;
@@ -63,7 +88,7 @@ const Filter = (props: FilterProps) => {
6388
<Row>
6489
<Col lg={10} md={10} sm={10} xl={10} xs={10} xxl={10}>
6590
<p className="ps-2 my-0 text-capitalize text-break">
66-
{option.value}
91+
{renderFacetOption(option.value, props.facet.name)}
6792
</p>
6893
</Col>
6994
<Col

src/components/browse/sidebar/sidebar.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
1111
import { faBars } from "@fortawesome/free-solid-svg-icons";
1212
import { handleFilterAndSearch } from "../shared";
1313

14+
const MAX_FACET_OPTIONS = 5;
15+
1416
interface SidebarProps {
1517
facetList: FacetModel[] | null;
1618
setSearchResults: Dispatch<SetStateAction<SearchResponseModel | null>>;
@@ -86,6 +88,7 @@ const Sidebar = (props: SidebarProps) => {
8688
{props.facetList === null || props.facetList.length === 0 ? null : (
8789
<Row className="position-relative w-100 px-1 mx-0">
8890
{props.facetList
91+
.filter((facet) => facet.options.length <= MAX_FACET_OPTIONS)
8992
.sort((a, b) => (b.key < a.key ? 1 : -1))
9093
.map((facet, index) => (
9194
<Filter

src/mocks/handlers.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ export const handlers = [
6363
}),
6464
// intercept user creation request
6565
http.post(USERS_URL.href, () => {
66-
console.log("registered called")
6766
session.id = user.id;
6867
session.state = "Registered";
6968
return HttpResponse.json(undefined, { status: 201 });
@@ -105,7 +104,7 @@ async function getMatchingParamString(request, responseMap) {
105104
Object.entries(bodyParams).forEach(([key, value]) => {
106105
requestParams.set(key, value);
107106
});
108-
} catch { }
107+
} catch {}
109108
}
110109
// find the response with the most matching parameters
111110
let bestParamString = null;

0 commit comments

Comments
 (0)