Skip to content

Commit

Permalink
Merge pull request #4014 from nasa-gibs/develop
Browse files Browse the repository at this point in the history
v3.35.0
  • Loading branch information
minniewong authored Oct 25, 2022
2 parents fe713fd + 9203054 commit e763eaf
Show file tree
Hide file tree
Showing 59 changed files with 1,563 additions and 287 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ RUN cd /usr/src && \
pip --version
RUN mkdir -p /usr/local/nvm
ENV NVM_DIR=/usr/local/nvm
ENV NODE_VERSION=16.16.0
ENV NODE_VERSION=16.18.0
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash && \
. "$NVM_DIR/nvm.sh" && \
nvm install v${NODE_VERSION} && \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ The MOPITT Carbon Monoxide (Level 2, Daily, Day/Night, Total Column) layer shows

The MOPITT Carbon Monoxide (L2, Daily, Day/Night, Total Column) layer is available from the Measurements of Pollution in the Troposphere (MOPITT) instrument on the Terra satellite. The sensor resolution is 22 km at nadir, imagery resolution is 2 km, and the temporal resolution is daily.

References: [MOP02R_NRT] (https://cmr.earthdata.nasa.gov/search/concepts/C1398625065-MOPITT.html)
Data Download: [Level 2 NRT](http://lance1.acom.ucar.edu/data/L2/)

References: [MOPITT Near Real-Time Data Download Service](http://lance1.acom.ucar.edu/)


Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ The fusion product is produced for each 6-minute granule. It performs best withi

The VIIRS+CrIS Band 33 Fusion Brightness Temperature layer is available from the joint NASA/NOAA NOAA 20 satellite. The sensor resolution is 750m, the imagery resolution is 1 km, and the temporal resolution is daily.

References: FSNRAD_L2_VIIRS_CrIS_NOAA20 [doi:10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_NOAA20.001](https://doi.org/10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_NOAA20.001)
References: FSNRAD_L2_VIIRS_CrIS_NOAA20 [doi:10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_NOAA20.002](https://doi.org/10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_NOAA20.002)
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ The fusion product is produced for each 6-minute granule. It performs best withi

The VIIRS+CrIS Band 33 Fusion Brightness Temperature layer is available from the joint NASA/NOAA NOAA 20 satellite. The sensor resolution is 750m, the imagery resolution is 1 km, and the temporal resolution is daily.

References: FSNRAD_L2_VIIRS_CrIS_NOAA20 [doi:10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_NOAA20.001](https://doi.org/10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_NOAA20.001)
References: FSNRAD_L2_VIIRS_CrIS_NOAA20 [doi:10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_NOAA20.002](https://doi.org/10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_NOAA20.002)
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ The fusion product is produced for each 6-minute granule. It performs best withi

The VIIRS+CrIS Band 33 Fusion Brightness Temperature layer is available from the joint NASA/NOAA Suomi National Polar orbiting Partnership (Suomi NPP) satellite. The sensor resolution is 750m, the imagery resolution is 1 km, and the temporal resolution is daily.

References: FSNRAD_L2_VIIRS_CrIS_SNPP [doi:10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_SNPP.001](https://doi.org/10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_SNPP.001)
References: FSNRAD_L2_VIIRS_CrIS_SNPP [doi:10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_SNPP.002](https://doi.org/10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_SNPP.002)
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ The fusion product is produced for each 6-minute granule. It performs best withi

The VIIRS+CrIS Band 33 Fusion Brightness Temperature layer is available from the joint NASA/NOAA Suomi National Polar orbiting Partnership (Suomi NPP) satellite. The sensor resolution is 750m, the imagery resolution is 1 km, and the temporal resolution is daily.

References: FSNRAD_L2_VIIRS_CrIS_SNPP [doi:10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_SNPP.001](https://doi.org/10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_SNPP.001)
References: FSNRAD_L2_VIIRS_CrIS_SNPP [doi:10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_SNPP.002](https://doi.org/10.5067/VIIRS/FSNRAD_L2_VIIRS_CRIS_SNPP.002)
3 changes: 2 additions & 1 deletion config/default/common/config/wv.json/naturalEvents.json
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,7 @@
]
]
}
}
},
"defaultLayer": "BlueMarble_NextGeneration"
}
}
45 changes: 45 additions & 0 deletions e2e/features/animation/mobile-animation-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const localQueryStrings = require('../../reuseables/querystrings.js');

const TIME_LIMIT = 10000;

module.exports = {
before: (c) => {
c.url(c.globals.url + localQueryStrings.knownDate);
c.pause(1000);
c.setWindowSize(375, 667);
c.pause(1000);
},

'Mobile animate button opens widget': (c) => {
c.waitForElementVisible('.mobile-animate-button', TIME_LIMIT);
c.useCss().click('.mobile-animate-button');
c.pause(500);
c.waitForElementPresent('#wv-animation-widget', TIME_LIMIT);
c.expect.element('.custom-interval-delta-input').to.have.value.that.equals('1');
c.expect.element('.dropdown-toggle').text.to.equal('DAY');
},

'Minimizing mobile animation widget opens collapsed animation widget': (c) => {
c.useCss().click('.wv-minimize');
c.waitForElementVisible('#collapsed-animate-widget-phone-portrait', TIME_LIMIT);
},

'Playing the animation changes the date of the mobile date picker': (c) => {
c.useCss().click('#collapsed-animate-widget-phone-portrait');
// this pause is the minimum amount of time needed to load & play the animation on a throttled connection
c.pause(20000);
c.expect.element('.mobile-date-picker-select-btn-text span').text.to.equal('2019 AUG 01');
},

'Pressing the animation button brings up the mobile animation widget with the same information': (c) => {
c.useCss().click('.mobile-animate-button');
c.pause(500);
c.waitForElementVisible('#wv-animation-widget', TIME_LIMIT);
c.expect.element('#mobile-animation-start-date .mobile-date-picker-select-btn span').text.to.equal('2019 JUL 22');
c.expect.element('#mobile-animation-end-date .mobile-date-picker-select-btn span').text.to.equal('2019 AUG 01');
},

after(c) {
c.end();
},
};
4 changes: 2 additions & 2 deletions e2e/features/image-download/layers-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = {
},

'List layers in draw order': function(c) {
bookmark(c, startParams.concat(['l=MODIS_Terra_CorrectedReflectance_TrueColor,MODIS_Terra_Aerosol,Reference_Features_15m']));
bookmark(c, startParams.concat(['l=MODIS_Terra_CorrectedReflectance_TrueColor,Reference_Features_15m,MODIS_Terra_Aerosol']));
openImageDownloadPanel(c);
clickDownload(c);
c.expect.element('#wv-image-download-url').to.have.attribute('url')
Expand All @@ -28,7 +28,7 @@ module.exports = {
openImageDownloadPanel(c);
clickDownload(c);
c.expect.element('#wv-image-download-url').to.have.attribute('url')
.and.to.contain('LAYERS=MODIS_Terra_CorrectedReflectance_TrueColor,MODIS_Terra_Aerosol,Reference_Features_15m');
.and.to.contain('LAYERS=MODIS_Terra_CorrectedReflectance_TrueColor,Reference_Features_15m,MODIS_Terra_Aerosol');
},

'Do not include obscured layers': function(c) {
Expand Down
16 changes: 9 additions & 7 deletions e2e/features/layers/layers-sidebar-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ const groupedLayerIdOrder = [
'active-MODIS_Combined_MAIAC_L2G_AerosolOpticalDepth',
];
const ungroupedReorderdLayerIdOrder = [
'active-MODIS_Combined_MAIAC_L2G_AerosolOpticalDepth',
'active-MODIS_Combined_Value_Added_AOD',
'active-Reference_Features_15m',
'active-VIIRS_SNPP_Thermal_Anomalies_375m_All',
'active-VIIRS_NOAA20_Thermal_Anomalies_375m_All',
'active-MODIS_Combined_Value_Added_AOD',
'active-MODIS_Combined_MAIAC_L2G_AerosolOpticalDepth',
];

module.exports = {
Expand All @@ -75,7 +75,8 @@ module.exports = {
c.expect.element(infoDialog).to.not.be.present;
},
'Toggle Layer Options': (c) => {
c.moveToElement(firesLayer, 0, 0);
c.pause(500);
// c.moveToElement(firesLayer, 0, 0);
c.waitForElementVisible(optionsButton, TIME_LIMIT);
c.click(optionsButton);
c.waitForElementVisible(optionsDialog, TIME_LIMIT);
Expand Down Expand Up @@ -179,9 +180,9 @@ module.exports = {
c.pause(500);
c.useCss();
c.expect.element('#group-overlays-checkbox-case').to.not.have.attribute('checked');

c.moveToElement(firesLayer, 0, 0);
c.moveToElement(overlaysGroupHeader, 0, 0);
c.waitForElementVisible(`${overlaysGroupHeader} ${groupOptionsBtn}`);
c.waitForElementPresent(`${overlaysGroupHeader} ${groupOptionsBtn}`);
c.click(`${overlaysGroup} ${groupOptionsBtn}`).pause(200);
c.click(`${overlaysGroup} ${groupRemove}`).pause(200);

Expand All @@ -207,6 +208,7 @@ module.exports = {
const actions = this.actions({ async: true });
const layerGroupHeader = c.findElement(aodGroupHeader);
const firesHeader = c.findElement(firesGroupHeader);
c.pause(500);
return actions
.click(layerGroupHeader)
.pause(300)
Expand All @@ -226,9 +228,9 @@ module.exports = {
.pause(300)
.release()
.pause(300);
// .dragAndDrop(layerGroupHeader, { x: -50, y: -150})
});
c.click(groupCheckbox).pause(200);
c.click(groupCheckbox);
c.pause(500);
checkElementOrdering(c, `${overlaysGroup} ul > li`, ungroupedReorderdLayerIdOrder);
},

Expand Down
4 changes: 4 additions & 0 deletions e2e/reuseables/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ module.exports = {
animationIntervalSelector: '#wv-animation-widget #current-interval',
animationFrameSlider: '#wv-animation-widget .rc-slider',

// mobile animations
mobileAnimateButton: '#animate-button',
mobileAnimationWidget: '.wv-animation-widget-wrapper-mobile',

// sidebar, layers
sidebarContainer: '#products-holder',
infoButton: '.wv-layers-info',
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "worldview",
"version": "3.34.0",
"version": "3.35.0",
"description": "Interactive interface for browsing full-resolution, global satellite imagery",
"keywords": [
"NASA",
Expand All @@ -23,7 +23,7 @@
"license": "NASA-1.3",
"repository": "nasa-gibs/worldview",
"engines": {
"node": "16.16.0"
"node": "16.18.0"
},
"husky": {
"hooks": {
Expand Down
5 changes: 1 addition & 4 deletions tasks/python3/getCapabilities.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
#!/usr/bin/env python

from concurrent.futures import ThreadPoolExecutor
from optparse import OptionParser
from collections import OrderedDict
import os
import sys
import json
import xmltodict
import traceback
import httpx
import asyncio

Expand Down Expand Up @@ -110,7 +108,6 @@ async def process_remote(client, entry):

except Exception as e:
print(('ERROR: %s: %s' % (url, str(e))))
print((str(traceback.format_exc())))

async def process_metadata(client, link, dir, ext):
try:
Expand All @@ -133,7 +130,7 @@ async def gather_process(type, typeStr, client, dir, ext):
async def main():
if "wv-options-fetch" in config:
limits = httpx.Limits(max_keepalive_connections=10, max_connections=10)
async with httpx.AsyncClient(limits=limits) as client:
async with httpx.AsyncClient(limits=limits, timeout=20.0) as client:
await asyncio.gather(*[process_remote(client, entry) for entry in config["wv-options-fetch"]])
if colormaps:
await gather_process(colormaps, 'colormaps', client, colormaps_dir, '.xml')
Expand Down
2 changes: 1 addition & 1 deletion tasks/python3/getVisMetadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ async def main(url):
print('%s: Pulling vis metadata for %s layers... ' % (prog, len(filtered_ids)))

limits = httpx.Limits(max_keepalive_connections=10, max_connections=10)
async with httpx.AsyncClient(limits=limits) as client:
async with httpx.AsyncClient(limits=limits, timeout=10.0) as client:
await asyncio.gather(*[get_metadata(client, layer_id, url) for layer_id in filtered_ids])
await asyncio.gather(*[get_metadata(client, layer_id, url) for layer_id in failed_requests])

Expand Down
2 changes: 1 addition & 1 deletion web/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class App extends React.Component {
<div id="eventsHolder" />
<div id="imagedownload" />
<Timeline />
<div id="wv-animation-widget-case">
<div>
{isAnimationWidgetActive ? <AnimationWidget key={locationKey || '2'} /> : null}
</div>
<MeasureButton />
Expand Down
18 changes: 11 additions & 7 deletions web/js/components/animation-widget/loop-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { UncontrolledTooltip } from 'reactstrap';
* @class LoopButton
* @extends React.Component
*/
const LoopButton = ({ looping, onLoop }) => {
const LoopButton = ({ looping, onLoop, isMobile }) => {
const labelText = looping ? 'Disable animation loop' : 'Enable animation loop';
const buttonId = 'loop-button';
return (
Expand All @@ -22,12 +22,15 @@ const LoopButton = ({ looping, onLoop }) => {
}
onClick={onLoop}
>
<UncontrolledTooltip
placement="top"
target={buttonId}
>
{labelText}
</UncontrolledTooltip>
{isMobile ? null
: (
<UncontrolledTooltip
placement="top"
target={buttonId}
>
{labelText}
</UncontrolledTooltip>
)}
<FontAwesomeIcon icon="retweet" className="wv-animation-widget-icon" />
</a>
);
Expand All @@ -36,6 +39,7 @@ const LoopButton = ({ looping, onLoop }) => {
LoopButton.propTypes = {
looping: PropTypes.bool,
onLoop: PropTypes.func,
isMobile: PropTypes.bool,
};

export default LoopButton;
1 change: 0 additions & 1 deletion web/js/components/animation-widget/play-queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ class PlayQueue extends React.Component {
}

const totalLoadTime = ((avgFetchTime * numberOfFrames) / msPerSec / CONCURRENT_REQUESTS).toFixed(2);
console.log(this.fetchTimes);
console.debug('Total frames: ', numberOfFrames);
console.debug('Avg fetch time: ', (avgFetchTime / msPerSec).toFixed(2));
console.debug('Play time (t/r): ', (totalPlayTime / msPerSec).toFixed(2), (remainingPlayTime / msPerSec).toFixed(2));
Expand Down
6 changes: 3 additions & 3 deletions web/js/components/layer/settings/granule-count-slider.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import Slider from 'rc-slider';
import lodashDebounce from 'lodash/debounce';
import { DEFAULT_NUM_GRANULES } from '../../../modules/layers/constants';
import { DEFAULT_NUM_GRANULES, MIN_GRANULES, MAX_GRANULES } from '../../../modules/layers/constants';

class GranuleCountSlider extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -30,8 +30,8 @@ class GranuleCountSlider extends React.Component {
<div className="layer-granule-count-select settings-component">
<h2 className="wv-header">Granule Count</h2>
<Slider
min={1}
max={50}
min={MIN_GRANULES}
max={MAX_GRANULES}
defaultValue={count}
onChange={(val) => {
this.setState({ value: val });
Expand Down
22 changes: 22 additions & 0 deletions web/js/components/sidebar/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@ import MonospaceDate from '../util/monospace-date';

function Event (props) {
const {
defaultEventLayer,
deselectEvent,
event,
eventLayers,
isSelected,
layers,
removeGroup,
selectedDate,
selectEvent,
sources,
toggleGroupVisibility,
toggleVisibility,
} = props;
const dateString = formatDisplayDate(event.geometry[0].date);
const itemClass = isSelected
Expand All @@ -39,9 +45,19 @@ function Event (props) {
*/
function onEventSelect(date) {
if (isSelected && (!date || date === selectedDate)) {
const layersToHide = [];
layers.forEach((layer) => {
if (layer.group === 'overlays' && layer.layergroup !== 'Reference') {
layersToHide.push(layer.id);
}
});
toggleGroupVisibility(layersToHide, false);
removeGroup(eventLayers);
toggleVisibility(defaultEventLayer, true);
deselectEvent();
} else {
const selectedEventDate = date || getDefaultEventDate(event);
toggleVisibility(defaultEventLayer, false);
selectEvent(event.id, selectedEventDate);
googleTagManager.pushEvent({
event: 'natural_event_selected',
Expand Down Expand Up @@ -178,12 +194,18 @@ function Event (props) {
}

Event.propTypes = {
defaultEventLayer: PropTypes.string,
deselectEvent: PropTypes.func,
event: PropTypes.object,
eventLayers: PropTypes.array,
isSelected: PropTypes.bool,
layers: PropTypes.array,
removeGroup: PropTypes.func,
selectedDate: PropTypes.string,
selectEvent: PropTypes.func,
sources: PropTypes.array,
toggleGroupVisibility: PropTypes.func,
toggleVisibility: PropTypes.func,
};

export default Event;
Loading

0 comments on commit e763eaf

Please sign in to comment.