diff --git a/app/scripts/components/common/card-sources.tsx b/app/scripts/components/common/card-sources.tsx
index d592a1c68..72d47dbd4 100644
--- a/app/scripts/components/common/card-sources.tsx
+++ b/app/scripts/components/common/card-sources.tsx
@@ -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`
@@ -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
@@ -50,19 +50,19 @@ export function CardSourcesList(props: SourcesListProps) {
{sources.map((source) => (
- {
e.preventDefault();
onSourceClick(source.id);
}}
>
{source.name}
-
+
))}
diff --git a/app/scripts/components/common/catalog/catalog-card.tsx b/app/scripts/components/common/catalog/catalog-card.tsx
index 439062461..65ef6b20e 100644
--- a/app/scripts/components/common/catalog/catalog-card.tsx
+++ b/app/scripts/components/common/catalog/catalog-card.tsx
@@ -121,7 +121,7 @@ export const CatalogCard = (props: CatalogCardProps) => {
overline={
-
+
}
linkLabel='View dataset'
diff --git a/app/scripts/components/common/featured-slider-section.tsx b/app/scripts/components/common/featured-slider-section.tsx
index e70a00b15..fb836d054 100644
--- a/app/scripts/components/common/featured-slider-section.tsx
+++ b/app/scripts/components/common/featured-slider-section.tsx
@@ -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 (
)}
diff --git a/app/scripts/components/common/map/controls/aoi/custom-aoi-control.tsx b/app/scripts/components/common/map/controls/aoi/custom-aoi-control.tsx
index 34d8b90ec..98300ca8f 100644
--- a/app/scripts/components/common/map/controls/aoi/custom-aoi-control.tsx
+++ b/app/scripts/components/common/map/controls/aoi/custom-aoi-control.tsx
@@ -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 &&
@@ -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 (
@@ -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;
diff --git a/app/scripts/components/exploration/atoms/datasets.ts b/app/scripts/components/exploration/atoms/datasets.ts
index ed9751f07..f78bbb18d 100644
--- a/app/scripts/components/exploration/atoms/datasets.ts
+++ b/app/scripts/components/exploration/atoms/datasets.ts
@@ -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;
diff --git a/app/scripts/components/exploration/atoms/dates.ts b/app/scripts/components/exploration/atoms/dates.ts
index e79e979a1..022ebcaeb 100644
--- a/app/scripts/components/exploration/atoms/dates.ts
+++ b/app/scripts/components/exploration/atoms/dates.ts
@@ -28,8 +28,8 @@ export const selectedDateAtom = atomWithUrlValueStability({
if (!prev || !next) return prev === next;
return prev.getTime() === next.getTime();
},
- dehydrate: (date) => {
- return date?.toISOString() ?? '';
+ dehydrate: (d) => {
+ return d?.toISOString() ?? '';
}
});
diff --git a/app/scripts/components/exploration/components/dataset-selector-modal/index.tsx b/app/scripts/components/exploration/components/dataset-selector-modal/index.tsx
index cc7bf02bd..6ba6cd34b 100644
--- a/app/scripts/components/exploration/components/dataset-selector-modal/index.tsx
+++ b/app/scripts/components/exploration/components/dataset-selector-modal/index.tsx
@@ -1,6 +1,5 @@
import React, { useCallback, useEffect, useState } from 'react';
import styled from 'styled-components';
-import { useAtom } from 'jotai';
import {
Modal,
ModalBody,
@@ -8,16 +7,18 @@ import {
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)`
@@ -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(
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();
@@ -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 (
`
+// override with 'as' as LinkComponent
+const ButtonStyleLink = styled.a`
&&& {
${({ variation, size }) => createButtonStyles({ variation, size })}
}
@@ -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 (
@@ -132,7 +133,7 @@ export default function LayerInfoModal(props: LayerInfoModalProps) {
}
footerContent={
-
+
Open in Data Catalog
}
diff --git a/app/scripts/components/exploration/components/parent-dataset-link.tsx b/app/scripts/components/exploration/components/parent-dataset-link.tsx
deleted file mode 100644
index 0764b7674..000000000
--- a/app/scripts/components/exploration/components/parent-dataset-link.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import styled from 'styled-components';
-import { themeVal } from '@devseed-ui/theme-provider';
-import { Link } from 'react-router-dom';
-import { CollecticonDatasetLayers } from '$components/common/icons/dataset-layers';
-import { ParentDatset } from '$components/exploration/types.d.ts';
-import { getDatasetPath } from '$utils/routes';
-
-const DatasetLink = styled(Link)<{size: string}>`
- color: ${themeVal('color.link')};
- text-align: left;
- text-transform: none;
- font-size: ${(props => props.size=='small'? '0.75rem': '1rem')};
- line-height: 0.75rem;
- font-weight: normal;
- display: flex;
- align-items: center;
- justify-content: center;
- text-decoration: none;
- gap: 0.1rem;
- > svg {
- fill: ${themeVal('color.link')};
- }
-`;
-
-export default function ParentDatasetLink(props: { parentDataset: ParentDatset, size: string}) {
- const { parentDataset, size } = props;
- const linkTo = getDatasetPath(parentDataset.id);
- return (
-
- {parentDataset.name}
- );
-}
\ No newline at end of file
diff --git a/app/scripts/components/exploration/container.tsx b/app/scripts/components/exploration/container.tsx
index b04936029..434dcd457 100644
--- a/app/scripts/components/exploration/container.tsx
+++ b/app/scripts/components/exploration/container.tsx
@@ -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';
@@ -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
*
@@ -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);
@@ -59,11 +61,17 @@ export default function ExplorationAndAnalysisContainer() {
-
+
) =>
}));
});
+ 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
diff --git a/app/scripts/components/exploration/hooks/use-timeline-dataset-atom.tsx b/app/scripts/components/exploration/hooks/use-timeline-dataset-atom.tsx
new file mode 100644
index 000000000..46811c17d
--- /dev/null
+++ b/app/scripts/components/exploration/hooks/use-timeline-dataset-atom.tsx
@@ -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];
+}
\ No newline at end of file
diff --git a/app/scripts/components/stories/hub/hub-content.tsx b/app/scripts/components/stories/hub/hub-content.tsx
index bcfa813a7..e78ea28f8 100644
--- a/app/scripts/components/stories/hub/hub-content.tsx
+++ b/app/scripts/components/stories/hub/hub-content.tsx
@@ -149,6 +149,7 @@ export default function HubContent(props:HubContentProps) {
{
onAction(FilterActions.TAXONOMY_MULTISELECT, {
key: TAXONOMY_SOURCE,
@@ -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={
diff --git a/app/scripts/index.ts b/app/scripts/index.ts
index 35fe6cbf5..59c0dde25 100644
--- a/app/scripts/index.ts
+++ b/app/scripts/index.ts
@@ -16,9 +16,21 @@ import { PageMainContent } from '$styles/page';
import PageHero from '$components/common/page-hero';
import { useFiltersWithQS } from '$components/common/catalog/controls/hooks/use-filters-with-query';
import ExplorationAndAnalysis from '$components/exploration';
+import useTimelineDatasetAtom from '$components/exploration/hooks/use-timeline-dataset-atom';
import { timelineDatasetsAtom } from '$components/exploration/atoms/datasets';
import { DatasetSelectorModal } from '$components/exploration/components/dataset-selector-modal';
+// Adding .last property to array
+/* eslint-disable-next-line fp/no-mutating-methods */
+Object.defineProperty(Array.prototype, 'last', {
+ enumerable: false,
+ configurable: true,
+ get: function () {
+ return this[this.length - 1];
+ },
+ set: undefined
+});
+
export {
// COMPONENTS
Block,
@@ -41,6 +53,7 @@ export {
ExplorationAndAnalysis,
DatasetSelectorModal,
// HOOKS
+ useTimelineDatasetAtom,
useFiltersWithQS,
// STATE
timelineDatasetsAtom