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
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add updated styling
sandrahoang686 committed Apr 6, 2024
commit 4109fe253831a800c86c09e03750fc1c47b24a09
139 changes: 38 additions & 101 deletions app/scripts/components/common/browse-controls/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import React from 'react';
import styled from 'styled-components';
import { Taxonomy, TaxonomyItem } from 'veda';
import { Taxonomy } from 'veda';
import { Overline } from '@devseed-ui/typography';
import { Button, ButtonProps } from '@devseed-ui/button';
import {
@@ -15,7 +15,6 @@ import {
FilterOption,
TaxonomyFilterOption,
optionAll,
sortDirOptions,
useBrowserControls
} from './use-browse-controls';

@@ -35,19 +34,16 @@ 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;
}
`;
`

const DropButton = styled(Button)`
max-width: 12rem;
@@ -59,15 +55,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' })`
@@ -78,7 +70,6 @@ const ButtonPrefix = styled(Overline).attrs({ as: 'small' })`
interface BrowseControlsProps extends ReturnType<typeof useBrowserControls> {
taxonomiesOptions: Taxonomy[];
sortOptions: FilterOption[];
showMoreButtonOpt?: boolean;
defaultSelect?: TaxonomyFilterOption;
}

@@ -88,19 +79,31 @@ function BrowseControls(props: BrowseControlsProps) {
taxonomies,
sortOptions,
search,
showMoreButtonOpt,
sortField,
sortDir,
onAction,
defaultSelect,
...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={filterList?.[name] ?? 'all'}
onChange={(v) => {
onAction(Actions.TAXONOMY, { key: name, value: v });
}}
size={isLargeUp ? 'large' : 'medium'}
/>
))
);

return (
<BrowseControlsWrapper {...rest}>
@@ -112,83 +115,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(0, filterWrapConstant))}
</FilterOptionsWrapper>
)
}
</BrowseControlsWrapper>
);
}
@@ -215,7 +152,7 @@ function DropdownOptions(props: DropdownOptionsProps) {
alignment='left'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
triggerElement={({ active, className, ...rest }) => (
<DropButton
<MainDropButton
variation='base-outline'
size={size}
active={active}
@@ -228,7 +165,7 @@ function DropdownOptions(props: DropdownOptionsProps) {
) : (
<CollecticonChevronDownSmall />
)}
</DropButton>
</MainDropButton>
)}
>
<DropTitle>Options</DropTitle>
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ import {
CollecticonTickSmall,
iconDataURI
} from '@devseed-ui/collecticons';
import { DatasetData, DatasetLayer, TaxonomyItem } from 'veda';
import { DatasetData } from 'veda';
import { DatasetLayerCardProps } from './';

import { DatasetClassification } from '$components/common/dataset-classification';
@@ -20,13 +20,14 @@ 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,
TAXONOMY_TOPICS
} from '$utils/veda-data';
import { Pill } from '$styles/pill';
import { Link } from 'react-router-dom';

const DatasetContainer = styled.div`
height: auto;
@@ -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;
@@ -94,18 +100,23 @@ export const ParentDatasetTitle = styled.h2<{size?: string}>`
}
`;

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

interface ModalContentComponentProps {
search: string;
selectedIds: string[];
displayDatasets?: (DatasetData & {
countSelectedLayers: number;
})[];
// onCheck: (id: string, sources?: TaxonomyItem[], currentDataset?: any) => 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 ? (
@@ -116,6 +127,13 @@ export default function ModalContentComponent(props:ModalContentComponentProps)
<DatasetHeadline>
<ParentDatasetTitle>
<CollecticonDatasetLayers /> {currentDataset.name}
{
currentDataset.sourceExclusive && (
<WarningPill variation='warning'>
{exclusiveSourceWarning}
</WarningPill>
)
}
</ParentDatasetTitle>
{currentDataset.countSelectedLayers > 0 && <DatasetSelectedLayer><span>{currentDataset.countSelectedLayers} selected </span> </DatasetSelectedLayer>}
</DatasetHeadline>
@@ -137,7 +155,6 @@ export default function ModalContentComponent(props:ModalContentComponentProps)
layer={datasetLayer}
parent={currentDataset}
selected={selectedIds.includes(datasetLayer.id)}
// onDatasetClick={() => onCheck(datasetLayer.id, getTaxonomy(currentDataset, TAXONOMY_SOURCE)?.values, currentDataset)}
onDatasetClick={() => onCheck(datasetLayer.id, currentDataset)}
/>
</li>
@@ -149,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>
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { media } from '@devseed-ui/theme-provider';
import { Taxonomy, TaxonomyItem, datasetTaxonomies } from 'veda';
import { datasetTaxonomies } from 'veda';
import {
ModalHeadline
} from '@devseed-ui/modal';
@@ -15,13 +13,9 @@ import {
useBrowserControls
} from '$components/common/browse-controls/use-browse-controls';
import { sortOptions } from '$components/data-catalog';
import { DATASETS_PATH } from '$utils/routes';

const StyledModalHeadline = styled(ModalHeadline)``;
const ModalIntro = styled.div`
${media.largeUp`
width: 66%;
`}
const StyledModalHeadline = styled(ModalHeadline)`
width: 100%;
`;

export default function RenderModalHeader ({defaultSelect}: {defaultSelect?: TaxonomyFilterOption}) {
@@ -39,15 +33,10 @@ export default function RenderModalHeader ({defaultSelect}: {defaultSelect?: Tax
return(
<StyledModalHeadline>
<Heading size='small'>Data layers</Heading>
<ModalIntro>
<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>
</ModalIntro>
<BrowseControls
{...controlVars}
taxonomiesOptions={datasetTaxonomies}
sortOptions={sortOptions}
showMoreButtonOpt={true}
defaultSelect={defaultSelect}
/>
</StyledModalHeadline>
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import { useAtom } from 'jotai';

import { DatasetData, DatasetLayer, Taxonomy, TaxonomyItem } from 'veda';
import { DatasetData, DatasetLayer } from 'veda';
import {
Modal,
ModalBody,
@@ -106,34 +106,26 @@ export function DatasetSelectorModal(props: DatasetSelectorModalProps) {

const prevSelectedIds = usePreviousValue(selectedIds);

const [relevantIds, setReleventIds] = useState<string[] | undefined>();

const [exclusionSelected, setExclusionSelected] = useState<boolean>(false);

useEffect(() => {
setSelectedIds(timelineDatasets.map((dataset) => dataset.data.id));
}, [timelineDatasets]);

const onCheck = useCallback((id: string, currentDataset?: DatasetData & {countSelectedLayers: number}) => {
console.log(`checked_currentDataset: `, currentDataset)
if (currentDataset) {
// This layer is part of a dataset that is exclusive
const exclusiveSource = currentDataset.sourceExclusive;
const sources = getTaxonomy(currentDataset, TAXONOMY_SOURCE)?.values;
const sourceIds = sources?.map(source => source.id);
console.log(`sourceIds: `, sourceIds)

// if (sourceIds?.includes('epa')) {

if (exclusiveSource && sourceIds?.includes(exclusiveSource.toLowerCase())) {
console.log(`epa source chosen, remove all others, `, sources)
// setDefaultSelectFilter({taxonomyType: TAXONOMY_SOURCE, value: 'epa'});
setDefaultSelectFilter({taxonomyType: TAXONOMY_SOURCE, value: exclusiveSource.toLowerCase()});
setExclusionSelected(true);
// setSelectedIds([]);
}
// if (exclusiveSource && !sourceIds?.includes(exclusiveSource.toLowerCase())) {
if (!exclusiveSource) {
console.log(`non epa source chosen, remove epa choices`)
if (!exclusiveSource) {
setDefaultSelectFilter(undefined);
setExclusionSelected(false);
}
@@ -181,8 +173,6 @@ export function DatasetSelectorModal(props: DatasetSelectorModalProps) {
relevantIds = selectedIdsWithParentData.filter((x) => !x.values?.includes(x.sourceExclusive)).map((x) => x.id)
}

console.log(`relevantIds: `, relevantIds)

setSelectedIds((ids) =>
ids.filter((id) => relevantIds?.includes(id))
);
@@ -201,24 +191,6 @@ export function DatasetSelectorModal(props: DatasetSelectorModalProps) {
}
}, [revealed]);

// // Filtered datasets for modal display
// const displayDatasets = useMemo<(DatasetData & {countSelectedLayers: number})[]>(
// () =>
// // @TODO: Move function from data-catalog once that page is removed.
// prepareDatasets(allDatasets, {
// search,
// taxonomies,
// sortField,
// sortDir,
// filterLayers: true
// })
// .map(dataset => ({
// ...dataset,
// countSelectedLayers: countOverlap(dataset.layers.map(l => l.id), selectedIds)
// })),
// [search, taxonomies, sortField, sortDir, selectedIds]
// );

useEffect(() => {
const datasets = prepareDatasets(allDatasets, {
search,
@@ -249,7 +221,6 @@ export function DatasetSelectorModal(props: DatasetSelectorModalProps) {
<ModalContentRender
search={search}
selectedIds={selectedIds}
// displayDatasets={displayDatasets}
displayDatasets={datasetsToDisplay}
onCheck={onCheck}
/>
9 changes: 7 additions & 2 deletions app/scripts/styles/pill.tsx
Original file line number Diff line number Diff line change
@@ -2,13 +2,18 @@ import styled, { css } from 'styled-components';
import { glsp, themeVal } from '@devseed-ui/theme-provider';

const renderPillVariation = ({ variation }: PillProps) => {
console.log(`variation: `, variation)
switch (variation) {
case 'achromic':
return css`
color: ${themeVal('color.surface')};
background: ${themeVal('color.surface-100a')};
`;

case 'warning':
return css`
color: ${themeVal('color.danger-500')};
background: ${themeVal('color.danger-200a')};
`;
case 'primary':
default:
return css`
@@ -19,7 +24,7 @@ const renderPillVariation = ({ variation }: PillProps) => {
};

interface PillProps {
variation?: 'primary' | 'achromic';
variation?: 'primary' | 'achromic' | 'warning';
}
export const Pill = styled.span<PillProps>`
display: inline-flex;