Skip to content

Commit

Permalink
Merge pull request #184 from kbase/feature/context-tab-ui
Browse files Browse the repository at this point in the history
Switch context tabs and filters positions in layout hierarchy
  • Loading branch information
codytodonnell authored Mar 26, 2024
2 parents c719a16 + 96c094c commit 2a00149
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 91 deletions.
27 changes: 16 additions & 11 deletions src/common/components/Table.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,26 @@ $header-height: 2em;
}

.pagination {
align-items: stretch;
display: flex;
flex-flow: row nowrap;
gap: 0.333em;
justify-content: flex-start;
max-width: 20em;
display: block;
text-align: right;

* {
flex: 1 1 2.25em;
min-width: fit-content;
display: inline-block;
margin-left: 0.5rem;
}

*:first-child {
margin-left: 0;
}

[disabled] {
color: #000;
}

*:first-child,
*:last-child {
flex: 0 1 2.25em;
.selected {
background-color: use-color("mid-green-light");
color: #000;
opacity: 1;
}
}

Expand Down
14 changes: 8 additions & 6 deletions src/common/components/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,15 @@ export const Pagination = <Datum,>({
if (buttons[0] !== start) {
buttons[0] = start;
buttons[1] = (
<Button key="etc-start" color="base" disabled>
<Button key="etc-start" color="gray" disabled>
{'...'}
</Button>
);
}
buttons.unshift(
<Button
className={classNamePagination}
color="base"
color="gray"
disabled={!table.getCanPreviousPage()}
key="prev"
onClick={() => table.previousPage()}
Expand All @@ -189,7 +189,7 @@ export const Pagination = <Datum,>({
<Button
key="etc-end"
className={classNamePagination}
color="base"
color="gray"
disabled
>
{'...'}
Expand All @@ -199,7 +199,7 @@ export const Pagination = <Datum,>({
buttons.push(
<Button
className={classNamePagination}
color="base"
color="gray"
disabled={!table.getCanNextPage() || curr >= maxPage}
key="next"
onClick={() => table.nextPage()}
Expand All @@ -210,8 +210,10 @@ export const Pagination = <Datum,>({
const buttonList = buttons.map((button, ix) =>
typeof button === 'number' ? (
<Button
className={classNamePagination}
color="base"
className={`${classNamePagination} ${
button === curr ? classes.selected : ''
}`}
color="gray"
disabled={button === curr || button > maxPage}
hidden={button > maxPage} // Hides the max page when we can't display it
key={button}
Expand Down
126 changes: 65 additions & 61 deletions src/features/collections/CollectionDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Button, Input } from '../../common/components';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faArrowRightArrowLeft,
faFilter,
faSliders,
faAngleRight,
faX,
faCircleXmark,
Expand Down Expand Up @@ -130,6 +130,7 @@ export const CollectionDetail = () => {

const { filterPanelOpen } = useFilters(collection?.id);
const filterMenuRef = useRef<HTMLButtonElement>(null);
const { filterEntries } = useFilterEntries(collection?.id || '');

const handleToggleFilters = () => {
if (collection?.id) {
Expand Down Expand Up @@ -177,32 +178,26 @@ export const CollectionDetail = () => {
<>
<div className={styles['collection_toolbar']}>
<Stack direction="row" spacing={1}>
<Input
hidden={!showSearch}
className={styles['search-box']}
placeholder="Search genomes by classification"
/>
<Button
hidden={!showFilterButton}
ref={filterMenuRef}
icon={<FontAwesomeIcon icon={faFilter} />}
onClick={handleToggleFilters}
>
Filters
</Button>
<Button
hidden={!showMatchButton}
icon={<FontAwesomeIcon icon={faArrowRightArrowLeft} />}
variant="contained"
onClick={() => {
setModalView('match');
modal?.show();
}}
>
{match
? `Matching by ${MATCHER_LABELS.get(match.matcher_id)}`
: `Match my Data`}
</Button>
{showSearch && (
<Input
className={styles['search-box']}
placeholder="Search genomes by classification"
/>
)}
{showMatchButton && (
<Button
icon={<FontAwesomeIcon icon={faArrowRightArrowLeft} />}
color="accent-warm-light"
onClick={() => {
setModalView('match');
modal?.show();
}}
>
{match
? `Matching by ${MATCHER_LABELS.get(match.matcher_id)}`
: `Match My Data`}
</Button>
)}
</Stack>
<Button
icon={<FontAwesomeIcon icon={faFileExport} />}
Expand All @@ -218,8 +213,8 @@ export const CollectionDetail = () => {
})`}
</Button>
</div>
<div>
<FilterChips collectionId={collection.id} />
<div className={styles['context-tabs']}>
<FilterContextTabs collectionId={collection.id} />
</div>
</>
)}
Expand All @@ -231,23 +226,48 @@ export const CollectionDetail = () => {
open={filterPanelOpen ?? false}
onClose={() => {
if (collection?.id) {
dispatch(setFilterPanelOpen(filterPanelOpen));
dispatch(setFilterPanelOpen(false));
}
}}
/>
<div className={styles['data_product_detail']}>
<FilterContextTabs collectionId={collection.id} />
{showOverview ? (
<CollectionOverview
collection_id={collection.id}
setModalView={setModalView}
modal={modal}
/>
) : currDataProduct ? (
<DataProduct
dataProduct={currDataProduct}
collection_id={collection.id}
/>
<>
{showFilterButton && (
<Stack
className={styles['filter-controls']}
direction="row"
spacing={2}
alignItems="center"
>
<Button
ref={filterMenuRef}
icon={<FontAwesomeIcon icon={faSliders} />}
onClick={handleToggleFilters}
>
Filters
</Button>
<div className={styles['filter-chips-label']}>
{filterEntries ? filterEntries.length : '0'} active{' '}
{filterEntries && filterEntries.length !== 1
? 'filters'
: 'filter'}
{filterEntries && filterEntries.length > 0 ? ':' : ''}
</div>
<FilterChips collectionId={collection.id} />
</Stack>
)}
<DataProduct
dataProduct={currDataProduct}
collection_id={collection.id}
/>
</>
) : (
<></>
)}
Expand Down Expand Up @@ -303,9 +323,13 @@ const useFilterEntries = (collectionId: string) => {
);

// Use same filter order if ignoring categories for consistency
// Only include filters who have a non-undefined value
const filterEntries = categorizedFilters.reduce<[string, FilterState][]>(
(filterEntires, category) => {
filterEntires.push(...category.filters);
const activeFilters = category.filters.filter(
(f) => f[1].value !== undefined
);
filterEntires.push(...activeFilters);
return filterEntires;
},
[]
Expand Down Expand Up @@ -334,13 +358,7 @@ const FilterChips = ({ collectionId }: { collectionId: string }) => {
useFilterEntries(collectionId);
if (filterEntries.length === 0) return <></>;
return (
<Stack
direction={'row'}
gap={'4px'}
useFlexGap
flexWrap="wrap"
sx={{ paddingTop: '14px' }}
>
<Stack direction={'row'} gap={'4px'} useFlexGap flexWrap="wrap">
{filterEntries.map(([column, filter]) => {
return (
<FilterChip
Expand Down Expand Up @@ -375,29 +393,15 @@ const FilterMenu = ({
} = useFilterEntries(collectionId);

/**
* Store category expanded state in an object
* Store expanded category string, empty string for none expanded
*/
const [expandedByCategory, setExpandedByCategory] = useState(() => {
const expanded: { [key: string]: boolean } = {};
categorizedFilters.forEach((category) => {
expanded[category.category] = false;
});
return expanded;
});
const [expandedCategory, setExpandedCategory] = useState('');

/**
* Only allow one category to be expanded at a time.
*/
const handleExpand = (expanded: boolean, category: string) => {
const newValue = { ...expandedByCategory };
Object.keys(expandedByCategory).forEach((c) => {
if (expanded && c === category) {
newValue[c] = true;
} else {
newValue[c] = false;
}
});
setExpandedByCategory(newValue);
setExpandedCategory(expanded ? category : '');
};

if (open) {
Expand Down Expand Up @@ -430,7 +434,7 @@ const FilterMenu = ({
key={`${category.category}-${context}`}
className={styles['filter-category']}
elevation={0}
expanded={expandedByCategory[category.category]}
expanded={category.category === expandedCategory}
onChange={(e, expanded) =>
handleExpand(expanded, category.category)
}
Expand Down
9 changes: 9 additions & 0 deletions src/features/collections/CollectionOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ export const CollectionOverview: FC<{
sx={{ paddingBottom: 0 }}
/>
<CardContent>
<Typography
sx={{ fontSize: 12 }}
color="text.secondary"
gutterBottom
>
Collection Name
</Typography>
<div>{collection.name}</div>
<br></br>
<Typography
sx={{ fontSize: 12 }}
color="text.secondary"
Expand Down
17 changes: 16 additions & 1 deletion src/features/collections/Collections.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,18 @@ $border: 1px solid use-color("base-lighter");
background-color: use-color("white");
border-bottom: 1px solid use-color("silver");
min-width: 600px;
padding: 1rem;
padding: 1rem 1rem 0;
}

.detail_header h2 {
margin-bottom: 0.5rem;
margin-top: 0;
}

.context-tabs {
margin-top: 0.5rem;
}

.match-highlight {
background-color: use-color("warning-lightest");
}
Expand All @@ -107,6 +111,17 @@ $border: 1px solid use-color("base-lighter");
width: 400px;
}

.filter-controls {
background-color: use-color("white");
border-radius: 4px;
margin-bottom: 0.5rem;
padding: 0.5rem;
}

.filter-chips-label {
color: use-color("base-dark");
}

.detail_content {
background-color: use-color("base-lightest");
display: flex;
Expand Down
2 changes: 1 addition & 1 deletion src/features/collections/MatchModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ const CreateMatch = ({ collectionId }: { collectionId: string }) => {
)}
</Stack>
<Stack spacing={1}>
<label htmlFor={idNarrative}>Narrative Test</label>
<label htmlFor={idNarrative}>Narrative</label>
<Select
id={idNarrative}
disabled={!matcherSelected}
Expand Down
Loading

0 comments on commit 2a00149

Please sign in to comment.