Skip to content

Commit

Permalink
Various fixes for E&A (#1229)
Browse files Browse the repository at this point in the history
**Related Ticket:** #1220

### Description of Changes
This PR is WIP, opening in case it helps anybody. (That says, please
don't spend time reviewing the changes in this PR yet, but it will be
really helpful if you can validate that this branch can run with Next
instance with stability.)

### Notes & Questions About Changes
I've noticed E&A still doesn't run with stability in Next instance. I
traced down all the possible errors that I can spot. That includes
#### Fixed in this PR
- export useAtom hook for timelinedataset (to remove the possibility of
more than one jotai instances)
- LinkProperties problem 
- MapboxDraw not added to the map yet when its method is called
- Date value that gets fed to atom is not valid - this was because our
polyfill for Array.last was not getting exported

#### Not fixed in this PR yet

- TimelineDatasetAtom still depends on veda faux module datasets 

I put temporary work-arounds for unsolved problems to validate that
those are the errors that can interrupt Next instance.

### Validate & Test
Please test this branch with `test-branch` Next branch :
https://github.com/developmentseed/next-veda-ui/tree/test-branch - It
will still lack of some functionalities, but hopefully the e&a page
doesn't return abrupt errors anymore.
  • Loading branch information
sandrahoang686 authored Nov 6, 2024
2 parents ef4a30c + f5bb96c commit 7771378
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 71 deletions.
16 changes: 8 additions & 8 deletions app/scripts/components/common/card-sources.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
import { listReset } from '@devseed-ui/theme-provider';
import { TaxonomyItem } from '$types/veda';
import { LinkProperties, TaxonomyItem } from '$types/veda';
import { FilterActions } from '$components/common//catalog/utils';

const SourcesUl = styled.ul`
Expand All @@ -23,11 +22,12 @@ interface SourcesListProps {
sources?: TaxonomyItem[];
onSourceClick?: (v: string) => void;
rootPath?: string;
linkProperties: LinkProperties;
}

export function CardSourcesList(props: SourcesListProps) {
const { sources, onSourceClick, rootPath } = props;

const { sources, onSourceClick, linkProperties, rootPath } = props;
const { LinkElement, pathAttributeKeyName } = linkProperties as { LinkElement: React.ElementType, pathAttributeKeyName: string };
if (!sources?.length) return null;

// No link rendering
Expand All @@ -50,19 +50,19 @@ export function CardSourcesList(props: SourcesListProps) {
<SourcesUl>
{sources.map((source) => (
<li key={source.id}>
<Link
to={`${rootPath}?${FilterActions.TAXONOMY}=${encodeURIComponent(
<LinkElement
{...{[pathAttributeKeyName]:`${rootPath}?${FilterActions.TAXONOMY}=${encodeURIComponent(
JSON.stringify({
Source: source.id
})
)}`}
)}`}}
onClick={(e) => {
e.preventDefault();
onSourceClick(source.id);
}}
>
{source.name}
</Link>
</LinkElement>
</li>
))}
</SourcesUl>
Expand Down
2 changes: 1 addition & 1 deletion app/scripts/components/common/catalog/catalog-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export const CatalogCard = (props: CatalogCardProps) => {
overline={
<CardMeta>
<DatasetClassification dataset={dataset} />
<CardSourcesList sources={sources} />
<CardSourcesList sources={sources} linkProperties={linkProperties} />
</CardMeta>
}
linkLabel='View dataset'
Expand Down
9 changes: 6 additions & 3 deletions app/scripts/components/common/featured-slider-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ function FeaturedSliderSection(props: FeaturedSliderSectionProps) {
return sortedFeaturedItems.map((d) => {
const date = new Date(d[dateProperty ?? '']);
const topics = getTaxonomy(d, TAXONOMY_TOPICS)?.values;

const linkProperties = {
pathAttributeKeyName: 'to',
LinkElement: SmartLink
};
return (
<ContinuumGridItem {...bag} key={d.id}>
<Card
Expand All @@ -108,9 +111,8 @@ function FeaturedSliderSection(props: FeaturedSliderSectionProps) {
cardType='featured'
linkLabel='View more'
linkProperties={{
...linkProperties,
linkTo: `${d.asLink?.url ?? getItemPath(d)}`,
pathAttributeKeyName: 'to',
LinkElement: SmartLink,
isLinkExternal: d.isLinkExternal
}}
title={d.name}
Expand All @@ -120,6 +122,7 @@ function FeaturedSliderSection(props: FeaturedSliderSectionProps) {
<DatasetClassification dataset={d} />
)}
<CardSourcesList
linkProperties={linkProperties}
sources={getTaxonomy(d, TAXONOMY_SOURCE)?.values}
/>
<VerticalDivider variation='light' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ function CustomAoI({
// selected, the trash method doesn't do anything. So, in this case, we
// trigger the delete for the whole feature.
const selectedFeatures = mbDraw.getSelected()?.features;

if (
mbDraw.getMode() === DIRECT_SELECT &&
selectedFeatures.length &&
Expand Down Expand Up @@ -241,9 +242,19 @@ function CustomAoI({
mbDraw.trash();
}, [features, aoiDeleteAll, map]);

const isAreaSelected = !!map?._drawControl?.getSelected().features.length;
const isPointSelected =
!!map?._drawControl.getSelectedPoints().features.length;
let isAreaSelected = false;
let isPointSelected = false;

// @NOTE: map?._drawControl?.getSelected() needs access to mapboxgl draw context store,
// but the function gets called before mapboxdraw store is initialized (before being added to map) resulting in an error
// Wrapping with try block so the values get subbed even when the store is not available
try {
isAreaSelected = !!(map?._drawControl?.getSelected().features.length);
isPointSelected = !!(map?._drawControl?.getSelectedPoints()?.features.length);
} catch(e) {
isAreaSelected = false;
isPointSelected = false;
}
const hasFeatures = !!features.length;

return (
Expand Down Expand Up @@ -330,7 +341,6 @@ export default function CustomAoIControl({
// as Mapbox Draw handles this internally when the drawing is completed
useEffect(() => {
if (!main) return;

const mbDraw = main._drawControl;

if (!mbDraw) return;
Expand Down
1 change: 1 addition & 0 deletions app/scripts/components/exploration/atoms/datasets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const timelineDatasetsAtom = atomWithUrlValueStability<
}
// Reconcile the dataset with the internal data (from VEDA config files)
// and then add the url stored settings.
// @TODO - replace datasetLayers
const [reconciled] = reconcileDatasets([enc.id], datasetLayers, []);
if (enc.settings) {
reconciled.settings = enc.settings;
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/components/exploration/atoms/dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export const selectedDateAtom = atomWithUrlValueStability<Date | null>({
if (!prev || !next) return prev === next;
return prev.getTime() === next.getTime();
},
dehydrate: (date) => {
return date?.toISOString() ?? '';
dehydrate: (d) => {
return d?.toISOString() ?? '';
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import React, { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
import { useAtom } from 'jotai';
import {
Modal,
ModalBody,
ModalFooter,
ModalHeader
} from '@devseed-ui/modal';
import { glsp, themeVal } from '@devseed-ui/theme-provider';
import { timelineDatasetsAtom } from '../../atoms/datasets';
import {
reconcileDatasets
reconcileDatasets,
getLayersFromDataset
} from '../../data-utils-no-faux-module';
import { datasetLayers } from '../../data-utils';
import { TimelineDataset } from '../../types.d.ts';

import RenderModalHeader from './header';
import ModalFooterRender from './footer';
import CatalogContent from '$components/common/catalog/catalog-content';
import { useFiltersWithURLAtom } from '$components/common/catalog/controls/hooks/use-filters-with-query';
import { FilterActions } from '$components/common/catalog/utils';

import { DatasetData, LinkProperties, DatasetLayer } from '$types/veda';

const DatasetModal = styled(Modal)`
Expand Down Expand Up @@ -68,16 +69,20 @@ interface DatasetSelectorModalProps {
linkProperties: LinkProperties;
datasets: DatasetData[];
datasetPathName: string;
timelineDatasets: TimelineDataset[];
setTimelineDatasets: (datasets: TimelineDataset[]) => void;
}

export function DatasetSelectorModal(props: DatasetSelectorModalProps) {
const { revealed, linkProperties, datasets, datasetPathName, close } = props;
const { revealed, linkProperties, datasets, datasetPathName, timelineDatasets, setTimelineDatasets, close } = props;
const { LinkElement , pathAttributeKeyName } = linkProperties as { LinkElement: React.ElementType, pathAttributeKeyName: string };

const [timelineDatasets, setTimelineDatasets] = useAtom(timelineDatasetsAtom);
const datasetLayers = getLayersFromDataset(datasets);

const [selectedIds, setSelectedIds] = useState<string[]>(
timelineDatasets.map((dataset) => dataset.data.id)
);
const enhancedDatasetLayers = datasetLayers.flatMap(e => e);

// Use Jotai controlled atoms for query parameter manipulation on new E&A page
const {search: searchTerm, taxonomies, onAction } = useFiltersWithURLAtom();
Expand All @@ -95,11 +100,12 @@ export function DatasetSelectorModal(props: DatasetSelectorModalProps) {

const onConfirm = useCallback(() => {
setTimelineDatasets(
reconcileDatasets(selectedIds, datasetLayers, timelineDatasets)
reconcileDatasets(selectedIds, enhancedDatasetLayers, timelineDatasets)
);
onAction(FilterActions.CLEAR);
close();
}, [close, selectedIds, timelineDatasets, setTimelineDatasets, onAction]);
}, [close, selectedIds, timelineDatasets, enhancedDatasetLayers, setTimelineDatasets, onAction]);

const linkElementProps = {[pathAttributeKeyName]: datasetPathName};
return (
<DatasetModal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { glsp, themeVal } from '@devseed-ui/theme-provider';
import { createButtonStyles } from '@devseed-ui/button';
import { LayerInfo } from 'veda';

import SmartLink from '$components/common/smart-link';
import { getDatasetPath } from '$utils/routes';
import { CollecticonDatasetLayers } from '$components/common/icons/dataset-layers';
import { ParentDatasetTitle } from '$components/common/catalog/catalog-content';
Expand Down Expand Up @@ -54,7 +53,8 @@ const ParentDatasetHeading = styled.h2`
padding: ${glsp(0.5)} 0;
`;

const ButtonStyleLink = styled(SmartLink)<any>`
// override with 'as' as LinkComponent
const ButtonStyleLink = styled.a<any>`
&&& {
${({ variation, size }) => createButtonStyles({ variation, size })}
}
Expand Down Expand Up @@ -101,6 +101,7 @@ const LayerInfoLinerModal = styled.div`

export default function LayerInfoModal(props: LayerInfoModalProps) {
const { revealed, close, layerData } = props;

const { parentData } = layerData;
const dataCatalogPage = getDatasetPath(parentData.id);
return (
Expand Down Expand Up @@ -132,7 +133,7 @@ export default function LayerInfoModal(props: LayerInfoModalProps) {
<div dangerouslySetInnerHTML={{__html: parentData.infoDescription?? 'Currently, we are unable to display the layer information, but you can find it in the data catalog.' }} />
}
footerContent={
<ButtonStyleLink to={dataCatalogPage} onClick={close} variation='primary-fill' size='medium' target='_blank'>
<ButtonStyleLink href={dataCatalogPage} rel='noopener noreferrer' onClick={close} variation='primary-fill' size='medium' target='_blank'>
Open in Data Catalog
</ButtonStyleLink>
}
Expand Down

This file was deleted.

22 changes: 15 additions & 7 deletions app/scripts/components/exploration/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { TourProvider } from '@reactour/tour';
import { DevTools } from 'jotai-devtools';
import { useAtom } from 'jotai';
import { PopoverTourComponent, TourManager } from './tour-manager';
import { timelineDatasetsAtom } from './atoms/datasets';

import { DatasetSelectorModal } from './components/dataset-selector-modal';
import { allExploreDatasets } from './data-utils';
import useTimelineDatasetAtom from './hooks/use-timeline-dataset-atom';
import ExplorationAndAnalysis from '.';
import { urlAtom } from '$utils/params-location-atom/url';
import { DATASETS_PATH, EXPLORATION_PATH } from '$utils/routes';
Expand All @@ -14,6 +15,7 @@ import { PageMainContent } from '$styles/page';
import { LayoutProps } from '$components/common/layout-root';
import PageHero from '$components/common/page-hero';
import SmartLink from '$components/common/smart-link';

/**
* @VEDA2-REFACTOR-WORK
*
Expand All @@ -30,15 +32,15 @@ const tourProviderStyles = {
};

export default function ExplorationAndAnalysisContainer() {
const [datasets, setDatasets] = useAtom(timelineDatasetsAtom);
const [timelineDatasets, setTimelineDatasets] = useTimelineDatasetAtom();
const [datasetModalRevealed, setDatasetModalRevealed] = useState(
!timelineDatasets.length
);

// @NOTE: When Exploration page is preloaded (ex. Linked with react-router)
// atomWithLocation gets initialized outside of Exploration page and returns the previous page's value
// We check if url Atom actually returns the values for exploration page here.
const [currentUrl]= useAtom(urlAtom);
const [datasetModalRevealed, setDatasetModalRevealed] = useState(
!datasets.length
);

if(!currentUrl.pathname?.includes(EXPLORATION_PATH)) return null;

const openModal = () => setDatasetModalRevealed(true);
Expand All @@ -59,11 +61,17 @@ export default function ExplorationAndAnalysisContainer() {
<TourManager />
<PageMainContent>
<PageHero title='Exploration' isHidden />
<ExplorationAndAnalysis datasets={datasets} setDatasets={setDatasets} openDatasetsSelectionModal={openModal} />
<ExplorationAndAnalysis
datasets={timelineDatasets}
setDatasets={setTimelineDatasets}
openDatasetsSelectionModal={openModal}
/>
<DatasetSelectorModal
revealed={datasetModalRevealed}
close={closeModal}
datasets={allExploreDatasets}
timelineDatasets={timelineDatasets}
setTimelineDatasets={setTimelineDatasets}
datasetPathName={DATASETS_PATH}
linkProperties={{
LinkElement: SmartLink,
Expand Down
10 changes: 10 additions & 0 deletions app/scripts/components/exploration/data-utils-no-faux-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ export const getDatasetLayers = (datasets: VedaDatum<DatasetData>) =>
}));
});

export const getLayersFromDataset = (datasets: DatasetData[]) =>
Object.values(datasets).map((dataset: DatasetData) => {
return dataset!.layers.map((l) => ({
...l,
parentDataset: {
id: dataset!.id,
name: dataset!.name
}
}));
});
/**
* Returns an array of metrics based on the given Dataset Layer configuration.
* If the layer has metrics defined, it returns only the metrics that match the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useAtom } from 'jotai';
import { timelineDatasetsAtom } from '../atoms/datasets';
import { TimelineDataset } from '../types.d.ts';

export default function useTimelineDatasetAtom (): [
TimelineDataset[],
(datasets: TimelineDataset[]) => void
] {
const [datasets, setDatasets] = useAtom(timelineDatasetsAtom);
return [datasets, setDatasets];
}
4 changes: 2 additions & 2 deletions app/scripts/components/stories/hub/hub-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export default function HubContent(props:HubContentProps) {
<CardSourcesList
sources={getTaxonomy(d, TAXONOMY_SOURCE)?.values}
rootPath={pathname}
linkProperties={linkProperties}
onSourceClick={(id) => {
onAction(FilterActions.TAXONOMY_MULTISELECT, {
key: TAXONOMY_SOURCE,
Expand All @@ -166,9 +167,8 @@ export default function HubContent(props:HubContentProps) {
}
linkLabel='View more'
linkProperties={{
...linkProperties,
linkTo: `${d.asLink?.url ?? d.path}`,
LinkElement,
pathAttributeKeyName,
isLinkExternal: d.isLinkExternal
}}
title={
Expand Down
Loading

0 comments on commit 7771378

Please sign in to comment.