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

EIC Features > main #752

Merged
merged 46 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
41ad6fa
Start work for external link
hanbyul-here Nov 2, 2023
d1f0a2c
Add example story, Add default data for storiesBanner, fix type
hanbyul-here Nov 3, 2023
581e354
Fix types
hanbyul-here Nov 6, 2023
cb11e30
Add Content Override option to stories hub
hanbyul-here Nov 6, 2023
17a995e
Add an option to use local nav or not
hanbyul-here Nov 7, 2023
375d671
Remove Page Local Nav
hanbyul-here Nov 7, 2023
b42061f
Make route to reflect story's customized string
hanbyul-here Nov 7, 2023
b5b617f
Add storiesHubHero to component override
hanbyul-here Nov 7, 2023
efada31
Make the path lowercase
hanbyul-here Nov 7, 2023
bc459ce
Revert stories path back to be hard coded
hanbyul-here Nov 7, 2023
90147cf
Lint
hanbyul-here Nov 8, 2023
9477d2a
Update parcel-resolver-veda/defaults.js
hanbyul-here Nov 8, 2023
5c4713b
Use component override
hanbyul-here Nov 8, 2023
f1c2f3b
Revert type change back, Add style to external flag
hanbyul-here Nov 8, 2023
99a1ae7
Move external link logic to card level, type fix
hanbyul-here Nov 8, 2023
17a6c6a
Style External link
hanbyul-here Nov 8, 2023
bdcd56e
Adjust excessive zindex
hanbyul-here Nov 8, 2023
99f7ff1
Use Content override for hub content
hanbyul-here Nov 9, 2023
f073371
Make iframe lazyload
hanbyul-here Nov 9, 2023
5165da6
Add Embed example
hanbyul-here Nov 9, 2023
ca9d3d1
Add stacApiEndpoint and tileApiEndpoint to data mdx
hanbyul-here Nov 9, 2023
da4527b
Throw error if aslink story is accessed on the single level
hanbyul-here Nov 9, 2023
56dee23
Add types, fix compare layer
hanbyul-here Nov 9, 2023
12ea71a
Give an option to be an 'external link' for story (#735)
danielfdsilva Nov 10, 2023
e05bf8c
Merge branch 'eic' into stories-hub-override
danielfdsilva Nov 10, 2023
52c8335
Add Content Override option to stories hub (#736)
hanbyul-here Nov 10, 2023
3f6c3d7
Add stacApiEndpoint to query key
hanbyul-here Nov 10, 2023
b1c735f
Handle multi stac endpoints in analysis
hanbyul-here Nov 10, 2023
cb762ac
Delete oco2 dataset for testing
hanbyul-here Nov 10, 2023
4c6348f
Set up an example with different datasets compare
hanbyul-here Nov 10, 2023
1839e50
Lazy iframe (#743)
hanbyul-here Nov 13, 2023
5c4780f
Add user page items to main nav
hanbyul-here Nov 14, 2023
de65b6d
Add userpage title as a layoutprops
hanbyul-here Nov 14, 2023
9e98edc
Pass other props for iframe
hanbyul-here Nov 14, 2023
bebe36e
Fix typo, var name bug
hanbyul-here Nov 15, 2023
b2bc5dc
Use set to get unique values
hanbyul-here Nov 15, 2023
b6f35d3
Make mainNavItem an object
hanbyul-here Nov 15, 2023
3aad447
Put an emtpy tag back
hanbyul-here Nov 15, 2023
b88a9f9
Use reduce over filter/map
hanbyul-here Nov 15, 2023
b604650
Bring your own stac, tile endpoint (#744)
hanbyul-here Nov 15, 2023
11bbc49
Pass other props for iframe (#749)
hanbyul-here Nov 15, 2023
89ec5e4
Add user page items to main nav (#748)
hanbyul-here Nov 15, 2023
fc29820
Pass styled props to wrapper level
hanbyul-here Nov 16, 2023
236792c
Use suffix, get rid of unnecessary check
hanbyul-here Nov 27, 2023
8e3d656
Fix iframe styled component props (#753)
hanbyul-here Nov 28, 2023
e838378
Merge branch 'main' into eic
danielfdsilva Dec 4, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import axios from 'axios';
import { useQuery } from '@tanstack/react-query';
import booleanIntersects from '@turf/boolean-intersects';
import bboxPolygon from '@turf/bbox-polygon';
import {
areIntervalsOverlapping
} from 'date-fns';
import { areIntervalsOverlapping } from 'date-fns';
import { DatasetLayer } from 'veda';

import { MAX_QUERY_NUM } from '../constants';
Expand All @@ -25,7 +23,7 @@ interface UseStacSearchProps {
export type DatasetWithTimeseriesData = TimeseriesDataResult &
DatasetLayer & { numberOfItems: number };

const collectionUrl = `${process.env.API_STAC_ENDPOINT}/collections`;
const collectionEndpointSuffix = '/collections';

export function useStacCollectionSearch({
start,
Expand All @@ -37,10 +35,31 @@ export function useStacCollectionSearch({
const result = useQuery({
queryKey: ['stacCollection'],
queryFn: async ({ signal }) => {
const collectionResponse = await axios.get(collectionUrl, {
signal
});
return collectionResponse.data.collections;
const collectionUrlsFromDataSets = allAvailableDatasetsLayers.reduce(
(filtered, { stacApiEndpoint }) => {
return stacApiEndpoint
? [...filtered, `${stacApiEndpoint}${collectionEndpointSuffix}`]
: filtered;
},
[]
);
// Get unique values of stac api endpoints from layer data, concat with api_stac_endpoiint from env var
const collectionUrls = Array.from(
new Set(collectionUrlsFromDataSets)
).concat(`${process.env.API_STAC_ENDPOINT}${collectionEndpointSuffix}`);

const collectionRequests = collectionUrls.map((url: string) =>
axios.get(url, { signal }).then((response) => {
return response.data.collections.map((col) => ({
...col,
stacApiEndpoint: url.replace(collectionEndpointSuffix, '')
}));
})
);
return axios.all(collectionRequests).then(
// Merge all responses into one array
axios.spread((...responses) => [].concat(...responses))
);
},
enabled: readyToLoadDatasets
});
Expand Down Expand Up @@ -86,13 +105,15 @@ export function useStacCollectionSearch({

function getInTemporalAndSpatialExtent(collectionData, aoi, timeRange) {
const matchingCollectionIds = collectionData.reduce((acc, col) => {
const id = col.id;
const { id, stacApiEndpoint } = col;

// Is is a dataset defined in the app?
// If not, skip other calculations.
const isAppDataset = allAvailableDatasetsLayers.some(
(l) => l.stacCol === id
);
const isAppDataset = allAvailableDatasetsLayers.some((l) => {
const stacApiEndpointUsed =
l.stacApiEndpoint ?? process.env.API_STAC_ENDPOINT;
return l.stacCol === id && stacApiEndpointUsed === stacApiEndpoint;
hanbyul-here marked this conversation as resolved.
Show resolved Hide resolved
});

if (
!isAppDataset ||
Expand Down Expand Up @@ -130,7 +151,11 @@ function getInTemporalAndSpatialExtent(collectionData, aoi, timeRange) {
);

const filteredDatasetsWithCollections = filteredDatasets.map((l) => {
const collection = collectionData.find((c) => c.id === l.stacCol);
const stacApiEndpointUsed =
l.stacApiEndpoint ?? process.env.API_STAC_ENDPOINT;
const collection = collectionData.find(
(c) => c.id === l.stacCol && stacApiEndpointUsed === c.stacApiEndpoint
);
return {
...l,
isPeriodic: collection['dashboard:is_periodic'],
Expand Down
23 changes: 18 additions & 5 deletions app/scripts/components/analysis/results/timeseries-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,24 +137,33 @@ export function requestStacDatasetsTimeseries({

interface DatasetAssetsRequestParams {
stacCol: string;
stacApiEndpoint?: string;
assets: string;
dateStart: Date;
dateEnd: Date;
aoi: FeatureCollection<Polygon>;
}

async function getDatasetAssets(
{ dateStart, dateEnd, stacCol, assets, aoi }: DatasetAssetsRequestParams,
{
dateStart,
dateEnd,
stacApiEndpoint,
stacCol,
assets,
aoi
}: DatasetAssetsRequestParams,
opts: AxiosRequestConfig,
concurrencyManager: ConcurrencyManagerInstance
) {
const stacApiEndpointToUse = stacApiEndpoint ?? process.env.API_STAC_ENDPOINT;
const data = await concurrencyManager.queue(async () => {
const collectionReqRes = await axios.get(
`${process.env.API_STAC_ENDPOINT}/collections/${stacCol}`
`${stacApiEndpointToUse}/collections/${stacCol}`
);

const searchReqRes = await axios.post(
`${process.env.API_STAC_ENDPOINT}/search`,
`${stacApiEndpointToUse}/search`,
{
'filter-lang': 'cql2-json',
limit: 10000,
Expand Down Expand Up @@ -238,6 +247,7 @@ async function requestTimeseries({
getDatasetAssets(
{
stacCol: layer.stacCol,
stacApiEndpoint: layer.stacApiEndpoint,
assets: layer.sourceParams?.assets || 'cog_default',
aoi,
dateStart: start,
Expand Down Expand Up @@ -267,7 +277,10 @@ async function requestTimeseries({
}
});

const analysisParams = layersBase.layer.analysis?.sourceParams;
const tileEndpointToUse =
layer.tileApiEndpoint ?? process.env.API_RASTER_ENDPOINT;

const analysisParams = layersBase.layer.analysis?.sourceParams ?? {};

const layerStatistics = await Promise.all(
assets.map(async ({ date, url }) => {
Expand All @@ -276,7 +289,7 @@ async function requestTimeseries({
async ({ signal }) => {
return concurrencyManager.queue(async () => {
const { data } = await axios.post(
`${process.env.API_RASTER_ENDPOINT}/cog/statistics`,
`${tileEndpointToUse}/cog/statistics?url=${url}`,
// Making a request with a FC causes a 500 (as of 2023/01/20)
combineFeatureCollection(aoi),
{ params: { ...analysisParams, url }, signal }
Expand Down
14 changes: 10 additions & 4 deletions app/scripts/components/common/blocks/embed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import BrowserFrame from '$styles/browser-frame';

const EmbedWrapper = styled.div`
width: 100%;

> div {
width: 100%;
}
Expand All @@ -18,19 +18,25 @@ const IframeWrapper = styled.iframe`
`;

interface EmbedProps {
className?: string;
src: string;
height: number;
}

export default function Embed({ src, height = 800 }: EmbedProps) {
export default function Embed({
className,
src,
height = 800,
...props
}: EmbedProps) {
if (!src) {
throw new HintedError('Embed block requires a URL');
}

return (
<EmbedWrapper>
<EmbedWrapper className={className}>
<BrowserFrame link={src}>
<IframeWrapper src={src} height={height} />
<IframeWrapper loading='lazy' src={src} height={height} {...props} />
</BrowserFrame>
</EmbedWrapper>
);
Expand Down
21 changes: 20 additions & 1 deletion app/scripts/components/common/blocks/lazy-components.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import T from 'prop-types';
import LazyLoad from 'react-lazyload';

import Chart from '$components/common/chart/block';
Expand All @@ -8,7 +9,7 @@ import Table, { tableHeight } from '$components/common/table';
import CompareImage from '$components/common/blocks/images/compare';

import Map, { mapHeight } from '$components/common/blocks/block-map';

import Embed from '$components/common/blocks/embed';
import {
ScrollytellingBlock,
scrollyMapHeight
Expand Down Expand Up @@ -72,3 +73,21 @@ export function LazyTable(props) {
</LazyLoad>
);
}

export function LazyEmbed(props) {
return (
<LazyLoad
// eslint-disable-next-line react/prop-types
placeholder={<LoadingSkeleton height={props.height} />}
offset={50}
once
>
<Embed {...props} />
</LazyLoad>
);
}

LazyEmbed.propTypes = {
src: T.string,
height: T.number
};
2 changes: 2 additions & 0 deletions app/scripts/components/common/blocks/scrollytelling/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ function Scrollytelling(props) {
key={runtimeData.id}
id={runtimeData.id}
mapInstance={mapRef.current}
stacApiEndpoint={layer.stacApiEndpoint}
tileApiEndpoint={layer.tileApiEndpoint}
stacCol={layer.stacCol}
date={runtimeData.datetime}
sourceParams={layer.sourceParams}
Expand Down
50 changes: 43 additions & 7 deletions app/scripts/components/common/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { MouseEventHandler, ReactNode } from 'react';
import styled, { css } from 'styled-components';
import { Link } from 'react-router-dom';
import { format } from 'date-fns';
import { CollecticonExpandTopRight } from '@devseed-ui/collecticons';
import { VerticalDivider } from '@devseed-ui/toolbar';

import {
Expand Down Expand Up @@ -198,11 +199,11 @@ export const CardMeta = styled.div`
}
}

> ${/* sc-selector */VerticalDivider}:last-child {
> ${/* sc-selector */ VerticalDivider}:last-child {
display: none;
}

> ${/* sc-selector */VerticalDivider}:first-child {
> ${/* sc-selector */ VerticalDivider}:first-child {
display: none;
}
`;
Expand Down Expand Up @@ -284,6 +285,38 @@ const CardFigure = styled(Figure)`
}
`;

const ExternalLinkMark = styled.div`
display: flex;
align-items: center;
position: absolute;
top: ${variableGlsp(0.25)};
right: ${variableGlsp(0.25)};
padding: ${variableGlsp(0.125)} ${variableGlsp(0.25)};
background-color: ${themeVal('color.primary')};
color: ${themeVal('color.surface')};
text-transform: none;
border-radius: calc(
${multiply(themeVal('shape.rounded'), 2)} - ${variableGlsp(0.125)}
);
z-index: 1;
`;

const FlagText = styled.div`
display: inline;
font-weight: bold;
font-size: 0.825rem;
margin-right: ${variableGlsp(0.25)};
`;

export function ExternalLinkFlag() {
return (
<ExternalLinkMark>
<FlagText>External Link</FlagText>
<CollecticonExpandTopRight size='small' meaningful={false} />
</ExternalLinkMark>
);
}

interface CardComponentProps {
title: ReactNode;
linkLabel: string;
Expand Down Expand Up @@ -319,23 +352,26 @@ function CardComponent(props: CardComponentProps) {
onCardClickCapture
} = props;

const isExternalLink = linkTo.match(/^https?:\/\//);
const linkProps = isExternalLink
? { href: linkTo }
: { as: Link, to: linkTo };

return (
<ElementInteractive
as={CardSelf}
cardType={cardType}
className={className}
linkLabel={linkLabel || 'View more'}
linkProps={{
as: Link,
to: linkTo
}}
linkProps={linkProps}
onClickCapture={onCardClickCapture}
>
<CardHeader>
<CardHeadline>
<CardTitle>{title}</CardTitle>
<CardOverline as='div'>
{parentName && parentTo && (
{isExternalLink && <ExternalLinkFlag />}
{!isExternalLink && parentName && parentTo && (
<CardLabel as={Link} to={parentTo}>
{parentName}
</CardLabel>
Expand Down
2 changes: 1 addition & 1 deletion app/scripts/components/common/featured-slider-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ function FeaturedSliderSection(props: FeaturedSliderSectionProps) {
}}
cardType='featured'
linkLabel='View more'
linkTo={getItemPath(d)}
linkTo={d.asLink?.url ?? getItemPath(d)}
title={d.name}
overline={
<CardMeta>
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/components/common/layout-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function LayoutRoot(props: { children?: ReactNode }) {

useGoogleTagManager();

const { title, thumbnail, description, hideFooter, localNavProps } =
const { title, thumbnail, description, hideFooter } =
useContext(LayoutRootContext);

const truncatedTitle =
Expand All @@ -57,7 +57,7 @@ function LayoutRoot(props: { children?: ReactNode }) {
description={description || appDescription}
thumbnail={thumbnail}
/>
<NavWrapper localNavProps={localNavProps} />
<NavWrapper />
<PageBody>
<Outlet />
{children}
Expand Down
7 changes: 6 additions & 1 deletion app/scripts/components/common/mapbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ function MapboxMapComponent(

return [data, getLayerComponent(!!data.timeseries, data.type)];
}, [compareLayer, resolverBag]);

// Get the compare to date.
// The compare date is specified by the user.
// If no date is specified anywhere we just use the same.
Expand Down Expand Up @@ -416,6 +416,8 @@ function MapboxMapComponent(
BaseLayerComponent && (
<BaseLayerComponent
id={`base-${baseLayerResolvedData.id}`}
stacApiEndpoint={baseLayerResolvedData.stacApiEndpoint}
tileApiEndpoint={baseLayerResolvedData.tileApiEndpoint}
stacCol={baseLayerResolvedData.stacCol}
mapInstance={mapRef.current}
isPositionSet={!!initialPosition}
Expand Down Expand Up @@ -470,12 +472,15 @@ function MapboxMapComponent(
<CompareLayerComponent
id={`compare-${compareLayerResolvedData.id}`}
stacCol={compareLayerResolvedData.stacCol}
stacApiEndpoint={compareLayerResolvedData.stacApiEndpoint}
tileApiEndpoint={compareLayerResolvedData.tileApiEndpoint}
mapInstance={mapCompareRef.current}
date={compareToDate ?? undefined}
sourceParams={compareLayerResolvedData.sourceParams}
zoomExtent={compareLayerResolvedData.zoomExtent}
bounds={compareLayerResolvedData.bounds}
onStatusChange={onCompareLayerStatusChange}
idSuffix='compare-suffix'
/>
)}
<SimpleMap
Expand Down
Loading
Loading