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

Some datasets can only be analyzed with layers from the same source #913

Merged
merged 8 commits into from
Apr 9, 2024
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
141 changes: 37 additions & 104 deletions app/scripts/components/common/browse-controls/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React from 'react';
import styled from 'styled-components';
import { Taxonomy } from 'veda';
import { Overline } from '@devseed-ui/typography';
Expand All @@ -14,7 +14,6 @@ import {
Actions,
FilterOption,
optionAll,
sortDirOptions,
useBrowserControls
} from './use-browse-controls';

Expand All @@ -34,15 +33,12 @@ const BrowseControlsWrapper = styled.div`
const SearchWrapper = styled.div`
display: flex;
gap: ${variableGlsp(0.5)};
width: 100%;
max-width: 70rem;
flex-wrap: no-wrap;
`;

const TaxonomyWrapper = styled.div`
const FilterOptionsWrapper = styled.div`
display: flex;
flex-flow: row wrap;
gap: ${variableGlsp(0.5)};

> * {
flex-shrink: 0;
}
Expand All @@ -58,15 +54,11 @@ const DropButton = styled(Button)`
flex-shrink: 0;
}
`;
const MainDropButton = styled(DropButton)`
width: 15rem;
max-width: 15rem;
`;

const ShowMorebutton = styled(Button)`
width: 10rem;
max-width: 10rem;
text-decoration: underline;
const MainDropButton = styled(DropButton)`
> * {
flex-shrink: 0;
}
`;

const ButtonPrefix = styled(Overline).attrs({ as: 'small' })`
Expand All @@ -76,28 +68,35 @@ const ButtonPrefix = styled(Overline).attrs({ as: 'small' })`

interface BrowseControlsProps extends ReturnType<typeof useBrowserControls> {
taxonomiesOptions: Taxonomy[];
sortOptions: FilterOption[];
showMoreButtonOpt?: boolean;
}

function BrowseControls(props: BrowseControlsProps) {
const {
taxonomiesOptions,
taxonomies,
sortOptions,
search,
showMoreButtonOpt,
sortField,
sortDir,
onAction,
...rest
} = props;

const [ showFilters, setShowFilters ] = useState(showMoreButtonOpt ? false : true);

const currentSortField = sortOptions.find((s) => s.id === sortField)!;

const { isLargeUp } = useMediaQuery();
const filterWrapConstant = 4;
const wrapTaxonomies = taxonomiesOptions.length > filterWrapConstant; // wrap list of taxonomies when more then 4 filter options

const createFilterList = (filterList: Taxonomy[]) => (
filterList.map(({ name, values }) => (
<DropdownOptions
key={name}
prefix={name}
items={[optionAll].concat(values)}
currentId={taxonomies?.[name] ?? 'all'}
onChange={(v) => {
onAction(Actions.TAXONOMY, { key: name, value: v });
}}
size={isLargeUp ? 'large' : 'medium'}
/>
))
);

return (
<BrowseControlsWrapper {...rest}>
Expand All @@ -109,83 +108,17 @@ function BrowseControls(props: BrowseControlsProps) {
value={search ?? ''}
onChange={(v) => onAction(Actions.SEARCH, v)}
/>
<DropdownScrollable
alignment='left'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
triggerElement={({ active, className, ...rest }) => (
<MainDropButton
variation='base-outline'
size={isLargeUp ? 'large' : 'medium'}
active={active}
{...rest}
>
<ButtonPrefix>Sort by</ButtonPrefix>
<span>{currentSortField.name}</span>{' '}
{active ? (
<CollecticonChevronUpSmall />
) : (
<CollecticonChevronDownSmall />
)}
</MainDropButton>
)}
>
<DropTitle>Options</DropTitle>
<DropMenu>
{/* { @NOTE: Display the sort option labels only when there is more than one otherwise it already defaults to the button title} */}
{sortOptions.length > 1 && sortOptions.map((t) => (
<li key={t.id}>
<DropMenuItemButton
active={t.id === sortField}
data-dropdown='click.close'
onClick={() => onAction(Actions.SORT_FIELD, t.id)}
>
{t.name}
</DropMenuItemButton>
</li>
))}
</DropMenu>
<DropMenu>
{sortDirOptions.map((t) => (
<li key={t.id}>
<DropMenuItemButton
active={t.id === sortDir}
data-dropdown='click.close'
onClick={() => onAction(Actions.SORT_DIR, t.id)}
>
{t.name}
</DropMenuItemButton>
</li>
))}
</DropMenu>
</DropdownScrollable>
{
showMoreButtonOpt && (
<ShowMorebutton
variation='base-text'
size={isLargeUp ? 'large' : 'medium'}
fitting='skinny'
onClick={() => {setShowFilters(value => !value);}}
>
{showFilters ? 'Hide filters' : 'Show filters'}
</ShowMorebutton>
)
}
<FilterOptionsWrapper>
{createFilterList(taxonomiesOptions.slice(0, filterWrapConstant))}
</FilterOptionsWrapper>
</SearchWrapper>
{showFilters &&
<TaxonomyWrapper>
{taxonomiesOptions.map(({ name, values }) => (
<DropdownOptions
key={name}
prefix={name}
items={[optionAll].concat(values)}
currentId={taxonomies?.[name] ?? 'all'}
onChange={(v) => {
onAction(Actions.TAXONOMY, { key: name, value: v });
}}
size={isLargeUp ? 'large' : 'medium'}
/>
))}
</TaxonomyWrapper>}
{
wrapTaxonomies && (
<FilterOptionsWrapper>
{createFilterList(taxonomiesOptions.slice(filterWrapConstant, taxonomiesOptions.length))}
</FilterOptionsWrapper>
)
}
</BrowseControlsWrapper>
);
}
Expand All @@ -206,13 +139,13 @@ function DropdownOptions(props: DropdownOptionsProps) {
const { size, items, currentId, onChange, prefix } = props;

const currentItem = items.find((d) => d.id === currentId);

return (
<DropdownScrollable
alignment='left'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
triggerElement={({ active, className, ...rest }) => (
<DropButton
<MainDropButton
variation='base-outline'
size={size}
active={active}
Expand All @@ -225,7 +158,7 @@ function DropdownOptions(props: DropdownOptionsProps) {
) : (
<CollecticonChevronDownSmall />
)}
</DropButton>
</MainDropButton>
)}
>
<DropTitle>Options</DropTitle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ export interface FilterOption {
name: string;
}

export interface TaxonomyFilterOption {
taxonomyType: string;
value: string;
exclusion?: string;
}

interface BrowseControlsHookParams {
sortOptions: FilterOption[];
}
Expand Down
1 change: 0 additions & 1 deletion app/scripts/components/data-catalog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,6 @@ function DataCatalog() {
<BrowseControls
{...controlVars}
taxonomiesOptions={datasetTaxonomies}
sortOptions={sortOptions}
/>
</BrowseFoldHeader>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { Link } from 'react-router-dom';
import styled, { css } from 'styled-components';
import { glsp, themeVal, media } from '@devseed-ui/theme-provider';
import {
Expand All @@ -20,7 +21,7 @@ import {
import TextHighlight from '$components/common/text-highlight';
import { CardSourcesList } from '$components/common/card-sources';
import { CollecticonDatasetLayers } from '$components/common/icons/dataset-layers';
import { getDatasetPath } from '$utils/routes';
import { DATASETS_PATH, getDatasetPath } from '$utils/routes';
import {
getTaxonomy,
TAXONOMY_SOURCE,
Expand Down Expand Up @@ -72,6 +73,11 @@ const DatasetIntro = styled.div`
padding: ${glsp(1)} 0;
`;

const EmptyInfoDiv = styled.div`
width: 70%;
text-align: center;
`;

export const ParentDatasetTitle = styled.h2<{size?: string}>`
color: ${themeVal('color.primary')};
text-align: left;
Expand All @@ -94,27 +100,40 @@ export const ParentDatasetTitle = styled.h2<{size?: string}>`
}
`;

const WarningPill = styled(Pill)`
margin-left: 8px;
`;

interface ModalContentComponentProps {
search: string;
selectedIds: string[];
displayDatasets: (DatasetData & {
displayDatasets?: (DatasetData & {
countSelectedLayers: number;
})[];
onCheck: (id: string) => void;
onCheck: (id: string, currentDataset?: DatasetData & {countSelectedLayers: number}) => void;
}

export default function ModalContentComponent(props:ModalContentComponentProps) {
const { search, selectedIds, displayDatasets, onCheck } = props;
const exclusiveSourceWarning = "Can only be analyzed with layers from the same source";

return(
<DatasetContainer>
{displayDatasets.length ? (
{displayDatasets?.length ? (
<div>
{displayDatasets.map(currentDataset => (
<SingleDataset key={currentDataset.id}>
<DatasetIntro>
<DatasetHeadline>
<ParentDatasetTitle>
<CollecticonDatasetLayers /> {currentDataset.name}
{
currentDataset.sourceExclusive && (
<WarningPill variation='warning'>
{exclusiveSourceWarning}
</WarningPill>
)
}
</ParentDatasetTitle>
{currentDataset.countSelectedLayers > 0 && <DatasetSelectedLayer><span>{currentDataset.countSelectedLayers} selected </span> </DatasetSelectedLayer>}
</DatasetHeadline>
Expand All @@ -136,7 +155,7 @@ export default function ModalContentComponent(props:ModalContentComponentProps)
layer={datasetLayer}
parent={currentDataset}
selected={selectedIds.includes(datasetLayer.id)}
onDatasetClick={() => onCheck(datasetLayer.id)}
onDatasetClick={() => onCheck(datasetLayer.id, currentDataset)}
/>
</li>
);
Expand All @@ -147,7 +166,10 @@ export default function ModalContentComponent(props:ModalContentComponentProps)
</div>
) : (
<EmptyHub>
There are no datasets to show with the selected filters.
<EmptyInfoDiv>
<p>There are no datasets to show with the selected filters.</p><br />
<p>This tool allows the exploration and analysis of time-series datasets in raster format. For a comprehensive list of available datasets, please visit the <Link to={DATASETS_PATH} target='_blank'>Data Catalog</Link>.</p>
</EmptyInfoDiv>
</EmptyHub>
)}
</DatasetContainer>
Expand Down Expand Up @@ -220,6 +242,7 @@ function DatasetLayerCard(props: DatasetLayerCardProps) {
const { parent, layer, onDatasetClick, selected, searchTerm } = props;

const topics = getTaxonomy(parent, TAXONOMY_TOPICS)?.values;
const sources = getTaxonomy(parent, TAXONOMY_SOURCE)?.values;
return (
<LayerCard
cardType='classic'
Expand All @@ -228,7 +251,7 @@ function DatasetLayerCard(props: DatasetLayerCardProps) {
<CardMeta>
<DatasetClassification dataset={parent} />
<CardSourcesList
sources={getTaxonomy(parent, TAXONOMY_SOURCE)?.values}
sources={sources}
/>
</CardMeta>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const LayerResult = styled.div`

export default function ModalFooterRender (props:ModalFooterComponentProps) {
const { selectedIds, close, onConfirm } = props;

return (
<>
<LayerResult aria-live='polite' className='selection-info'>
Expand Down
Loading
Loading