From 4232035744a7af53dc0a079a60f453bbec4bf5cf Mon Sep 17 00:00:00 2001 From: Patrick Moulden <4834892+PatchesMaps@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:59:22 -0400 Subject: [PATCH] WV-3246 Describe Domains (#5392) * initial work * fix: await processLayer in extractConfigFromWMTS.js * feat: only show "View Dates" in the layer info if the layer is not ongoing --- tasks/build-options/extractConfigFromWMTS.js | 4 +- tasks/build-options/processTemporalLayer.js | 161 +++++++++++-------- web/js/components/layer/info/info.js | 3 +- 3 files changed, 99 insertions(+), 69 deletions(-) diff --git a/tasks/build-options/extractConfigFromWMTS.js b/tasks/build-options/extractConfigFromWMTS.js index 2d7bdcf99c..d4525a77fd 100644 --- a/tasks/build-options/extractConfigFromWMTS.js +++ b/tasks/build-options/extractConfigFromWMTS.js @@ -139,7 +139,7 @@ async function processEntry (entry) { for (const gcLayer of gcContents.Layer) { try { layerCount += 1 - processLayer(gcLayer, wvLayers, entry) + await processLayer(gcLayer, wvLayers, entry) } catch (error) { if (error instanceof SkipException) { warningCount += 1 @@ -184,7 +184,7 @@ async function processLayer (gcLayer, wvLayers, entry) { const dimension = gcLayer.Dimension if (dimension['ows:Identifier']._text === 'Time') { try { - wvLayer = await processTemporalLayer(wvLayer, dimension.Value) + wvLayer = await processTemporalLayer(wvLayer, dimension.Value, entry.source) } catch (e) { console.error(e) console.error(`${prog}: ERROR: [${ident}] Error processing time values.`) diff --git a/tasks/build-options/processTemporalLayer.js b/tasks/build-options/processTemporalLayer.js index c7a836c225..de8860a9f4 100644 --- a/tasks/build-options/processTemporalLayer.js +++ b/tasks/build-options/processTemporalLayer.js @@ -1,88 +1,117 @@ const moment = require('moment') +const xml2js = require('xml2js') + +const projDict = { + 'GIBS:geographic': 'epsg4326', + 'GIBS:arctic': 'epsg3413', + 'GIBS:antarctic': 'epsg3031' +} function toList (val) { return val instanceof Array ? val : [val] } -async function processTemporalLayer (wvLayer, value) { +async function processTemporalLayer (wvLayer, value, source = 'GIBS:geographic') { const dateFormat = 'YYYY-MM-DD' const dateTimeFormat = 'YYYY-MM-DD HH:mm:ss' try { - const ranges = toList(value) - if (ranges && ranges[0] && ranges[0]._text && ranges[0]._text.includes('T')) { - wvLayer.period = 'subdaily' - } else { - if (ranges && ranges[0] && ranges[0]._text && ranges[0]._text.endsWith('Y')) { - wvLayer.period = 'yearly' - } else if (ranges && ranges[0] && ranges[0]._text && ranges[0]._text.endsWith('M')) { - wvLayer.period = 'monthly' - } else { - wvLayer.period = 'daily' - } - } - let startDate = moment.min() - let endDate = moment.max() - const dateRangeStart = [] - const dateRangeEnd = [] - const rangeInterval = [] - for (const range of ranges) { - const [start, end, interval] = range._text.split('/') - if ( - wvLayer.period === 'daily' || - wvLayer.period === 'monthly' || - wvLayer.period === 'yearly' - ) { - startDate = moment.min(startDate, moment(start, dateFormat)) - endDate = moment.max(endDate, moment(end, dateFormat)) - if (start) { - startDate = moment(start, dateFormat).format('YYYY-MM-DDTHH:mm:ss[Z]') - dateRangeStart.push(startDate) - } - if (end) { - endDate = moment(end, dateFormat).format('YYYY-MM-DDTHH:mm:ss[Z]') + let ranges = toList(value) + const describeDomainsUrl = `https://gibs.earthdata.nasa.gov/wmts/${projDict[source]}/best/1.0.0/${wvLayer.id}/default/250m/all/all.xml` + try { + const describeDomainsResponse = await fetch(describeDomainsUrl) + if (describeDomainsResponse?.ok) { + const describeDomainsText = await describeDomainsResponse?.text?.() || '' + const parser = new xml2js.Parser() + const describeDomainsJson = await parser.parseStringPromise(describeDomainsText) + const domain = describeDomainsJson?.Domains?.DimensionDomain?.[0]?.Domain?.[0] || '' + const domains = domain.split(',') + if (domains?.length) { + const formattedDomains = domains.map((d) => { + return { + _text: d + } + }) + ranges = toList(formattedDomains) } - if (interval !== 'P1D') { - endDate = moment.utc(endDate).add(moment.duration(interval)).format('YYYY-MM-DDTHH:mm:ss[Z]') - // For monthly products subtract 1 day - if (wvLayer.period === 'monthly') { - endDate = moment.utc(endDate).subtract(1, 'day').format('YYYY-MM-DDTHH:mm:ss[Z]') - } - } - const regex = /\d+/g - const match = regex.exec(interval) - rangeInterval.push(match) - if (endDate.endsWith('T00:00:00Z')) { - endDate = endDate.replace('T00:00:00Z', 'T23:59:59Z') - } - dateRangeEnd.push(endDate) + } + } catch (error) { + console.error(`Error fetching ${describeDomainsUrl}: ${error}`) + } finally { + if (ranges && ranges[0] && ranges[0]._text && ranges[0]._text.includes('T')) { + wvLayer.period = 'subdaily' } else { - // Subdaily Layers - startDate = moment(start, dateTimeFormat).format('YYYY-MM-DDTHH:mm:ss[Z]') - endDate = moment(end, dateTimeFormat).format('YYYY-MM-DDTHH:mm:ss[Z]') - - if (start) { - dateRangeStart.push(startDate) + if (ranges && ranges[0] && ranges[0]._text && ranges[0]._text.endsWith('Y')) { + wvLayer.period = 'yearly' + } else if (ranges && ranges[0] && ranges[0]._text && ranges[0]._text.endsWith('M')) { + wvLayer.period = 'monthly' + } else { + wvLayer.period = 'daily' } - if (end) { + } + let startDate = moment.min() + let endDate = moment.max() + const dateRangeStart = [] + const dateRangeEnd = [] + const rangeInterval = [] + for (const range of ranges) { + const [start, end, interval] = range._text.split('/') + if ( + wvLayer.period === 'daily' || + wvLayer.period === 'monthly' || + wvLayer.period === 'yearly' + ) { + startDate = moment.min(startDate, moment(start, dateFormat)) + endDate = moment.max(endDate, moment(end, dateFormat)) + if (start) { + startDate = moment(start, dateFormat).format('YYYY-MM-DDTHH:mm:ss[Z]') + dateRangeStart.push(startDate) + } + if (end) { + endDate = moment(end, dateFormat).format('YYYY-MM-DDTHH:mm:ss[Z]') + } + if (interval !== 'P1D') { + endDate = moment.utc(endDate).add(moment.duration(interval)).format('YYYY-MM-DDTHH:mm:ss[Z]') + // For monthly products subtract 1 day + if (wvLayer.period === 'monthly') { + endDate = moment.utc(endDate).subtract(1, 'day').format('YYYY-MM-DDTHH:mm:ss[Z]') + } + } + const regex = /\d+/g + const match = regex.exec(interval) + rangeInterval.push(match) + if (endDate.endsWith('T00:00:00Z')) { + endDate = endDate.replace('T00:00:00Z', 'T23:59:59Z') + } dateRangeEnd.push(endDate) - } + } else { + // Subdaily Layers + startDate = moment(start, dateTimeFormat).format('YYYY-MM-DDTHH:mm:ss[Z]') + endDate = moment(end, dateTimeFormat).format('YYYY-MM-DDTHH:mm:ss[Z]') - rangeInterval.push(interval.match(/\d+/)[0]) - } + if (start) { + dateRangeStart.push(startDate) + } + if (end) { + dateRangeEnd.push(endDate) + } - wvLayer.startDate = dateRangeStart[0] - wvLayer.endDate = dateRangeEnd[dateRangeEnd.length - 1] + rangeInterval.push(interval.match(/\d+/)[0]) + } - if (dateRangeStart.length && dateRangeEnd.length) { - wvLayer.dateRanges = dateRangeStart.map((s, i) => ({ - startDate: s, - endDate: dateRangeEnd[i], - dateInterval: rangeInterval[i] - })) + wvLayer.startDate = dateRangeStart[0] + wvLayer.endDate = dateRangeEnd[dateRangeEnd.length - 1] + + if (dateRangeStart.length && dateRangeEnd.length) { + wvLayer.dateRanges = dateRangeStart.map((s, i) => ({ + startDate: s, + endDate: dateRangeEnd[i], + dateInterval: rangeInterval[i] + })) + } } } } catch (e) { - throw new Error(`Error processing temporal layer: ${e}`) + throw new Error(`Error processing temporal layer ${wvLayer.id}: ${e}`) } return wvLayer } diff --git a/web/js/components/layer/info/info.js b/web/js/components/layer/info/info.js index 37d813d7da..044854a8a6 100644 --- a/web/js/components/layer/info/info.js +++ b/web/js/components/layer/info/info.js @@ -11,6 +11,7 @@ export default function LayerInfo ({ layer, measurementDescriptionPath }) { id, period, startDate, + ongoing, } = layer; const [layerMetadata, setLayerMetadata] = useState(); @@ -47,7 +48,7 @@ export default function LayerInfo ({ layer, measurementDescriptionPath }) { const overlapDateRanges = hasLayerDateRange ? dateOverlap(period, dateRanges) : []; - return hasLayerDateRange && overlapDateRanges.overlap === false; + return hasLayerDateRange && overlapDateRanges.overlap === false && !ongoing; }; const needDateRanges = getDateOverlapDateRanges();