From ada6adfae4e537c451c9349e8173465fb83ec902 Mon Sep 17 00:00:00 2001 From: PatchesMaps Date: Thu, 31 Oct 2024 15:08:32 -0400 Subject: [PATCH] Refactor layer metadata retrieval and rendering - Update features.json to include cmrVisualizationsUrl - Modify getVisMetadata.js to fetch metadata from cmrVisualizationsUrl if available - Update renderSplitTitle.js and selectors.js to handle title and subtitle properties in different cases --- config/default/common/features.json | 1 + tasks/build-options/getVisMetadata.js | 72 +++++++++++++------ .../layer/product-picker/renderSplitTitle.js | 3 +- web/js/modules/layers/selectors.js | 4 +- 4 files changed, 57 insertions(+), 23 deletions(-) diff --git a/config/default/common/features.json b/config/default/common/features.json index 354b3c61bd..7f9b092f73 100644 --- a/config/default/common/features.json +++ b/config/default/common/features.json @@ -11,6 +11,7 @@ "googleTagManager": true, "vismetadata": { "url": "https://gibs.earthdata.nasa.gov/layer-metadata/v1.0/", + "cmrVisualizationsUrl": "https://cmr.uat.earthdata.nasa.gov/search/visualizations", "daacMap": { "ASIPS": "Atmosphere SIPS", "GES_DISC": "GES DISC", diff --git a/tasks/build-options/getVisMetadata.js b/tasks/build-options/getVisMetadata.js index 88f0da4b10..5364dd0ced 100644 --- a/tasks/build-options/getVisMetadata.js +++ b/tasks/build-options/getVisMetadata.js @@ -3,6 +3,7 @@ const path = require('path') const yargs = require('yargs') const console = require('console') const axios = require('axios').default +const xml2js = require('xml2js') const prog = path.basename(__filename) @@ -26,6 +27,12 @@ const options = yargs type: 'string', description: 'layer-metadata/all.json file' }) + .option('mode', { + demandOption: true, + alias: 'm', + type: 'string', + description: 'mode' + }) .epilog('Creates a layer-metadata file containing all layers') const { argv } = options @@ -56,7 +63,7 @@ if (fs.existsSync(layerOrderFile)) { const outputFile = argv.layerMetadata const metadataConfig = features.features.vismetadata -const url = metadataConfig.url +const { url, cmrVisualizationsUrl } = metadataConfig const daacMap = metadataConfig.daacMap || {} const layerMetadata = {} @@ -104,6 +111,7 @@ const skipLayers = [ // NOTE: Only using these properties at this time const useKeys = [ 'conceptIds', + 'ConceptIds', 'dataCenter', 'daynight', 'orbitTracks', @@ -111,17 +119,21 @@ const useKeys = [ 'ongoing', 'layerPeriod', 'title', - 'subtitle' + 'Title', + 'subtitle', + 'Subtitle', + 'What' ] -async function main (url) { +async function main (url, cmrVisualizationsUrl) { layerOrder = layerOrder.layerOrder layerOrder = layerOrder.filter(x => !skipLayers.includes(x)) console.warn(`${prog}: Fetching ${layerOrder.length} layer-metadata files`) for (const layerId of layerOrder) { if (!layerId.includes('_STD') && !layerId.includes('_NRT')) { - await getMetadata(layerId, url) + if (argv.mode === 'verbose') console.warn(`${prog}: Fetching metadata for ${layerId}`) + await getMetadata(layerId, url, cmrVisualizationsUrl) } } @@ -138,10 +150,11 @@ async function main (url) { } async function getDAAC (metadata) { - if (!Array.isArray(metadata.conceptIds) || !metadata.conceptIds.length) { + const conceptIds = metadata.conceptIds || metadata.ConceptIds + if (!Array.isArray(conceptIds) || !conceptIds.length) { return metadata } - for (const collection of metadata.conceptIds) { + for (const collection of conceptIds) { const origDataCenter = collection.dataCenter const dataCenter = daacMap[origDataCenter] if (!dataCenter) { @@ -157,36 +170,55 @@ async function getDAAC (metadata) { return metadata } -async function getMetadata (layerId, baseUrl, count) { +async function getMetadata (layerId, baseUrl, ummVisUrl, count) { if (count) console.warn(`retry #${count} for ${layerId}`) - return axios({ - method: 'get', - url: `${baseUrl}${layerId}.json`, - responseType: 'json', - timeout: 10000 - }).then(async (response) => { - const metadata = response.data + const searchReq = await fetch(`${ummVisUrl}?identifier=${layerId}`, { signal: AbortSignal.timeout(10000) }) + const searchText = await searchReq?.text?.() || '' + const parser = new xml2js.Parser() + const searchJson = await parser.parseStringPromise(searchText) + const location = searchJson?.results?.references?.[0]?.reference?.[0]?.location?.[0] + if (location) { + const ummVisReq = await fetch(location, { signal: AbortSignal.timeout(10000) }) + const metadata = await ummVisReq.json() layerMetadata[layerId] = await getDAAC(metadata) let metadataKeys = Object.keys(layerMetadata[layerId]) metadataKeys = metadataKeys.filter(x => !useKeys.includes(x)) for (const key of metadataKeys) { delete layerMetadata[layerId][key] } - }).catch((error) => { - handleException(error, layerId, url, count) - }) + if (argv.mode === 'verbose') console.warn(layerMetadata[layerId]) + } else { + return axios({ + method: 'get', + url: `${baseUrl}${layerId}.json`, + responseType: 'json', + timeout: 10000 + }).then(async (response) => { + const metadata = response.data + layerMetadata[layerId] = await getDAAC(metadata) + let metadataKeys = Object.keys(layerMetadata[layerId]) + metadataKeys = metadataKeys.filter(x => !useKeys.includes(x)) + for (const key of metadataKeys) { + delete layerMetadata[layerId][key] + } + if (argv.mode === 'verbose') console.warn(layerMetadata[layerId]) + }).catch((error) => { + if (argv.mode === 'verbose') console.warn(`\n ${prog} WARN: Unable to fetch ${layerId} ${error}`) + handleException(error, layerId, url, ummVisUrl, count) + }) + } } -async function handleException (error, layerId, url, count) { +async function handleException (error, layerId, url, ummVisUrl, count) { if (!count) count = 0 count++ if (count <= 5) { - await getMetadata(layerId, url, count) + await getMetadata(layerId, url, ummVisUrl, count) } else { console.warn(`\n ${prog} WARN: Unable to fetch ${layerId} ${error}`) } } -main(url).catch((err) => { +main(url, cmrVisualizationsUrl).catch((err) => { console.error(err.stack) }) diff --git a/web/js/components/layer/product-picker/renderSplitTitle.js b/web/js/components/layer/product-picker/renderSplitTitle.js index 6707e6b798..bfd4a4b49c 100644 --- a/web/js/components/layer/product-picker/renderSplitTitle.js +++ b/web/js/components/layer/product-picker/renderSplitTitle.js @@ -9,7 +9,8 @@ import { getOrbitTrackTitle } from '../../../modules/layers/util'; */ export default function RenderSplitLayerTitle(props) { const { layer } = props; - const { title, subtitle } = layer; + const title = layer.title || layer.Title; + const subtitle = layer.subtitle || layer.Subtitle; const layerIsOrbitTrack = layer.layergroup === 'Orbital Track'; const layerTitle = !layerIsOrbitTrack ? title : `${title} (${getOrbitTrackTitle(layer, false)})`; let splitIdx; diff --git a/web/js/modules/layers/selectors.js b/web/js/modules/layers/selectors.js index ab3e9b4304..e7443410ef 100644 --- a/web/js/modules/layers/selectors.js +++ b/web/js/modules/layers/selectors.js @@ -647,8 +647,8 @@ export function getTitles(config, layerId, projId) { tags = forProj.tags; } const forLayer = config.layers[layerId]; - title = title || forLayer.title || `[${layerId}]`; - subtitle = subtitle || forLayer.subtitle || ''; + title = title || forLayer.title || forLayer.Title || `[${layerId}]`; + subtitle = subtitle || forLayer.subtitle || forLayer.Subtitle || ''; tags = tags || forLayer.tags || ''; return { title,