Skip to content

Commit

Permalink
Merge pull request #70 from developmentseed/feature/create-mosaic
Browse files Browse the repository at this point in the history
Enable mosaic creation
  • Loading branch information
vgeorge authored Jan 24, 2024
2 parents d57c8a2 + 9de078b commit d57efd5
Show file tree
Hide file tree
Showing 15 changed files with 542 additions and 118 deletions.
3 changes: 2 additions & 1 deletion app/assets/scripts/components/common/card-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ Card.propTypes = {

const CardListContainer = styled.ol`
display: grid;
height: min-content;
grid-template-columns: ${({ numColumns }) => {
if (numColumns) {
return css`repeat(${numColumns}, 1fr)`;
Expand All @@ -185,7 +186,7 @@ const CardListScroll = styled(ShadowScrollbar)`
flex: 1;
`;
const CardListWrapper = styled(PanelBlockBody)`
height: 100%;
height: min-content;
${({ nonScrolling }) =>
nonScrolling &&
css`
Expand Down
2 changes: 2 additions & 0 deletions app/assets/scripts/components/common/map/constants.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export const BOUNDS_PADDING = [25, 25];

export const MOSAIC_LAYER_OPACITY = 0.8;
12 changes: 7 additions & 5 deletions app/assets/scripts/components/common/tabbed-block-body.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ const TabbedBlockHeader = styled(PanelBlockHeader)`
${listReset}
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
padding: 0 ${glsp(1.5)};
justify-content: ${({ leftAligned }) =>
leftAligned ? 'flex-start' : 'space-between'};
gap: ${glsp()};
padding: ${({ leftAligned }) => (leftAligned ? '0' : '0 1.5rem')};
box-shadow: inset 0 -1px 0 0 ${themeVal('color.baseAlphaB')};
}
/* PanelBlockHeader sets z-index. This causes
Expand All @@ -108,11 +110,11 @@ const PanelBlockScroll = styled(ScrollableBody)`
`;

function TabbedBlock(props) {
const { children, activeTab } = props;
const { children, activeTab, leftAligned } = props;

return (
<>
<TabbedBlockHeader as='nav' role='navigation'>
<TabbedBlockHeader as='nav' role='navigation' leftAligned={leftAligned}>
<ul>
{Children.map(children, (child, ind) => {
const { name, icon, tabId, disabled, tabTooltip } = child.props;
Expand Down Expand Up @@ -153,7 +155,6 @@ function TabbedBlock(props) {
<>
{React.cloneElement(child, {
active: active,
//style: active ? {} : { display: 'none' },
className: active ? className : `${className} inactive-panel`,
})}
</>
Expand All @@ -167,5 +168,6 @@ function TabbedBlock(props) {
TabbedBlock.propTypes = {
children: T.node.isRequired,
activeTab: T.number.isRequired,
leftAligned: T.bool,
};
export default TabbedBlock;
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function MosaicSelectorModal({
<ModalHeader>
<Headline>
{' '}
<Heading>Select an base mosaic</Heading>
<Heading>Select a base mosaic</Heading>
<Button
hideText
variation='base-plain'
Expand Down
6 changes: 4 additions & 2 deletions app/assets/scripts/components/project/map/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ import { RETRAIN_MAP_MODES } from '../../../fsm/project/constants';
import FreehandDrawControl from './freehand-draw-control';
import PolygonDrawControl from './polygon-draw-control';
import selectors from '../../../fsm/project/selectors';
import { BOUNDS_PADDING } from '../../common/map/constants';
import {
BOUNDS_PADDING,
MOSAIC_LAYER_OPACITY,
} from '../../common/map/constants';

const center = [19.22819, -99.995841];
const zoom = 12;

const DEFAULT_PREDICTION_LAYER_OPACITY = 0.7;
const MOSAIC_LAYER_OPACITY = 0.8;

const Container = styled.div`
height: 100%;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function ImagerySourceSelectorModal({ showModal, setShowModal }) {
<ModalContent>
<HeadingWrapper>
<Heading size='small' as='h4'>
Available mosaics for the AOI
Imagery sources available for the selected AOI
</Heading>
</HeadingWrapper>
<CardList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function MosaicSelector() {
/>
<HeadOption>
<HeadOptionHeadline usePadding>
<Subheading>Base Mosaic</Subheading>
<Subheading>Imagery Mosaic Date Range</Subheading>
</HeadOptionHeadline>
<SubheadingStrong
data-cy='mosaic-selector-label'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import React from 'react';
import React, { useMemo } from 'react';
import T from 'prop-types';
import styled from 'styled-components';
import { Modal } from '@devseed-ui/modal';
import { glsp } from '@devseed-ui/theme-provider';
import { Button } from '@devseed-ui/button';
import { Heading } from '@devseed-ui/typography';
import CardList, { Card } from '../../../../../common/card-list';
import { ExistingMosaicsSection } from './sections/list-mosaics';
import { CreateMosaicSection } from './sections/create-mosaic';
import TabbedBlock from '../../../../../common/tabbed-block-body';
import { ProjectMachineContext } from '../../../../../../fsm/project';
import selectors from '../../../../../../fsm/project/selectors';
import { formatDateTime } from '../../../../../../utils/format';

const ModalHeader = styled.header`
padding: ${glsp(2)} ${glsp(2)} 0;
`;

const ModalContent = styled.div`
display: block;
display: flex;
flex-flow: column;
height: 60vh;
`;

const Headline = styled.div`
Expand All @@ -34,26 +36,19 @@ const Headline = styled.div`
}
`;

const HeadingWrapper = styled.div`
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: baseline;
`;
export function MosaicSelectorModal({ showModal, setShowModal }) {
const [activeTab, setActiveTab] = React.useState(0);

export function MosaicSelectorModal({ showModal, setShowModal, isProjectNew }) {
const actorRef = ProjectMachineContext.useActorRef();
const mosaicsList = ProjectMachineContext.useSelector(selectors.mosaicsList);
const currentMosaic = ProjectMachineContext.useSelector(
selectors.currentMosaic
);
const currentImagerySource = ProjectMachineContext.useSelector(
selectors.currentImagerySource
const mapRef = ProjectMachineContext.useSelector(
({ context }) => context.mapRef
);

const selectableMosaics = mosaicsList.filter(
(mosaic) => mosaic.imagery_source_id === currentImagerySource?.id
);
// Get the current map zoom and center on modal open
const [mapZoom, mapCenter] = useMemo(() => {
if (!showModal || !mapRef) return [null, null];
const { lng, lat } = mapRef.getCenter();
return [mapRef.getZoom(), [lat, lng]];
}, [mapRef, showModal]);

return (
<Modal
Expand All @@ -66,8 +61,7 @@ export function MosaicSelectorModal({ showModal, setShowModal, isProjectNew }) {
renderHeader={() => (
<ModalHeader>
<Headline>
{' '}
<Heading>Select an base mosaic</Heading>
<Heading>Set Mosaic Date Range</Heading>
<Button
hideText
variation='base-plain'
Expand All @@ -84,62 +78,34 @@ export function MosaicSelectorModal({ showModal, setShowModal, isProjectNew }) {
)}
content={
<ModalContent>
<HeadingWrapper>
<Heading size='small' as='h4'>
Available mosaics for the AOI
</Heading>
</HeadingWrapper>
<CardList
nonScrolling
numColumns={2}
data={selectableMosaics}
renderCard={(mosaic) => {
const { name, mosaic_ts_end, mosaic_ts_start } = mosaic;

return (
<Card
data-cy={`select-mosaic-${mosaic.id}-card`}
key={mosaic.id}
title={mosaic.name}
details={{
name,
'Mosaic Start Date': mosaic_ts_start
? formatDateTime(mosaic_ts_start)
: 'N/A',
'Mosaic End Date': mosaic_ts_end
? formatDateTime(mosaic_ts_end)
: 'N/A',
}}
borderlessMedia
selected={currentMosaic && currentMosaic.id === mosaic.id}
onClick={() => {
if (isProjectNew) {
if (!currentMosaic || currentMosaic.id !== mosaic.id) {
actorRef.send({
type: 'Mosaic was selected',
data: { mosaic },
});
}
} else if (currentMosaic?.id !== mosaic.id) {
actorRef.send({
type: 'Mosaic was selected',
data: { mosaic },
});
}
setShowModal(false);
}}
/>
);
}}
/>
<TabbedBlock activeTab={activeTab} leftAligned={true}>
<ExistingMosaicsSection
name='Select Preset'
className='select-preset-mosaic'
tabId='select-preset-mosaic-tab-trigger'
onTabClick={() => setActiveTab(0)}
setShowModal={setShowModal}
/>
<CreateMosaicSection
name='Create Mosaic'
className='create-mosaic'
tabId='create-mosaic-tab-trigger'
initialMapZoom={mapZoom}
initialMapCenter={mapCenter}
onTabClick={() => setActiveTab(1)}
onMosaicCreated={() => {
setActiveTab(0);
setShowModal(false);
}}
/>
</TabbedBlock>
</ModalContent>
}
/>
);
}

MosaicSelectorModal.propTypes = {
isProjectNew: T.bool,
showModal: T.bool,
setShowModal: T.func.isRequired,
};
Loading

0 comments on commit d57efd5

Please sign in to comment.