Skip to content

Commit

Permalink
Merge pull request #308 from RENCI/issue-288-default-startup-layers
Browse files Browse the repository at this point in the history
Default instance name at startup
  • Loading branch information
lstillwe authored Oct 28, 2024
2 parents 11f47bf + 80fd8fe commit 6d240f0
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 68 deletions.
7 changes: 4 additions & 3 deletions package-lock.json

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

10 changes: 7 additions & 3 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ControlPanel } from '@components/control-panel';
import { ComparePanel } from '@components/compare-panel';
import { MapLegend } from '@components/legend';
import { AlertUser } from '@components/alert-user';
import { Config } from '@components/config';

/**
* renders the main content
Expand All @@ -17,7 +18,7 @@ import { AlertUser } from '@components/alert-user';
*/
const Content = () => {
// install the selected observation list from the layer context
const { selectedObservations } = useLayers();
const { selectedObservations, defaultInstanceName } = useLayers();

// render all the application content
return (
Expand All @@ -32,10 +33,13 @@ const Content = () => {
return <ObservationDialog key={obs["station_name"]} obs={obs} />;
})
}
<Config />
<AlertUser />
<Map />
<Sidebar />
<ControlPanel/>
{/* here we are waiting for the retrieval of the default Instance name
before rendering these components */}
{ (defaultInstanceName != null) && <Map/> }
{ (defaultInstanceName != null) && <ControlPanel/> }
<ComparePanel/>
<MapLegend />
</Fragment>
Expand Down
2 changes: 1 addition & 1 deletion src/components/alert-user/alert-user.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const AlertUser = () => {
<Fragment>
<Dialog open={ true } disableEnforceFocus onClick={ () => setAlertMsg(null) }>
<DialogContent sx={{ p:0, m: .5, fontSize: 10, fontStyle: 'italic'}}>
<Tooltip title="Click to close" placement="top">
<Tooltip title="Click anywhere to close" placement="top">
<Alert variant="outlined" severity={ alertMsg['severity'] }>{ alertMsg['msg'] }</Alert>
</Tooltip>
</DialogContent>
Expand Down
95 changes: 95 additions & 0 deletions src/components/config/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { useEffect, useState } from "react";
import { useLayers } from "@context";
import { getNamespacedEnvParam } from "@utils";
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

/**
* gets the default instance name for startup layers
*
*/
export const getDefaultInstanceName = () => {
// init the return
let ret_val = '';

// get the state variable that suppresses using the instance name
const {
defaultInstanceName
} = useLayers();

// if there is a valid default instance name
if (!defaultInstanceName.includes('Error') && defaultInstanceName.length) {
// build the extended query string
ret_val = '&instance_name=' + defaultInstanceName;
}

// return the query string addition
return ret_val;
};

/**
* handles getting the default instance name
*
* @returns JSX.Element
* @constructor
*/
export const Config = () => {
// get the message alert details from state
const { setDefaultInstanceName } = useLayers();

// use this to trigger the data retrieval
const [ dataUrl, setDataUrl ] = useState(null);

/**
* create a url to get the instance name
*/
useEffect( () => {
// get the site branding for the query string
const theUrl = 'get_ui_instance_name?reset=false&site_branding=' + (window.location.href.includes('nopp') ? 'NOPP' : 'APSViz');

// set the data url. this will spawn a data request
setDataUrl(getNamespacedEnvParam('REACT_APP_UI_DATA_URL') + theUrl);
}, [] );

/**
* grab the default instance name
*/
useQuery( {
// specify the data key and url to use
queryKey: ['get_ui_instance_name', dataUrl],

// create the function to call for data
queryFn: async () => {
// create the authorization header
const requestOptions = {
method: 'GET',
headers: { Authorization: `Bearer ${ getNamespacedEnvParam('REACT_APP_UI_DATA_TOKEN') }`}
};

// make the call to get the data
const ret_val = await axios
// make the call to get the data
.get(dataUrl, requestOptions)
// use the data returned
.then (( response ) => {
// return the data
return response.data;
})
.catch (( error ) => {
// make sure we do not render anything
return error.response.status;
});

// if the retrieval did not have an issue
if (typeof ret_val === 'string' && !ret_val.includes('Error'))
// save the instance name value
setDefaultInstanceName(ret_val);
else
// blank the instance name on any http or data gathering error.
setDefaultInstanceName('');

// return something
return true;
}, refetchOnWindowFocus: false
});
};
1 change: 1 addition & 0 deletions src/components/config/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './config';
3 changes: 2 additions & 1 deletion src/components/control-panel/control-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
Waves as HIResMaxElevationIcon,
} from '@mui/icons-material';
import { getBrandingHandler, getNamespacedEnvParam } from "@utils/map-utils";
import { getDefaultInstanceName } from "@components/config";
import { Branding } from './branding';

const layerIcons = {
Expand All @@ -44,7 +45,7 @@ export const ControlPanel = () => {
toggleLayerVisibility,
toggleHurricaneLayerVisibility } = useLayers();

const data_url = `${ getNamespacedEnvParam('REACT_APP_UI_DATA_URL') }` + `get_ui_data_secure?limit=1&use_v3_sp=true${ getBrandingHandler() }`;
const data_url = `${ getNamespacedEnvParam('REACT_APP_UI_DATA_URL') }` + `get_ui_data_secure?limit=1&use_v3_sp=true${ getBrandingHandler() + getDefaultInstanceName() }`;
const layers = [...defaultModelLayers];
const hurrLayers = [...hurricaneTrackLayers];

Expand Down
120 changes: 70 additions & 50 deletions src/components/map/adcirc-raster-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ export const AdcircRasterLayer = (layer) => {

// get the observation points selected, default layers and alert message from state
const {
selectedObservations, setSelectedObservations,
defaultModelLayers,
setAlertMsg,
selectedObservations, setSelectedObservations,
defaultSelected, leftPaneID, rightPaneID
} = useLayers();

// capture the default layers
Expand All @@ -87,7 +88,18 @@ export const AdcircRasterLayer = (layer) => {
return (selectedObservations.find((o) => o.id === id) !== undefined);
};

// create a callback to handle a map click event
/**
* determines if the app is in compare mode
*
* @returns {boolean}
*/
const inCompareMode = () => {
return (leftPaneID !== defaultSelected && rightPaneID !== defaultSelected);
};

/**
* create a callback to handle a map click event
*/
const onClick = useCallback((e) => {
// get the visible layer on the map
const layer = layers.find((layer) => layer.properties['product_type'] !== "obs" && layer.state.visible === true);
Expand All @@ -101,55 +113,63 @@ export const AdcircRasterLayer = (layer) => {

// if the point selected is new
if (!isAlreadySelected(id)) {
// if this is a layer we can geo-point on
if (validLayerTypes.has(layer.properties['product_name'])) {
// create a marker target icon around the observation clicked
markClicked(map, e, id);

// get the FQDN of the UI data server
const data_url = `${getNamespacedEnvParam('REACT_APP_UI_DATA_URL')}`;

// split the URL
const split_url = layer.properties['tds_download_url'].split('/');

// generate the base TDS svr hostname/url
const tds_svr = split_url[0] + '//' + split_url[2] + '/thredds';

// create the correct TDS URL without the hostname
const tds_url = layer.properties['tds_download_url'].replace('catalog', 'dodsC').replace('catalog.html',
(layer.id.indexOf('swan') < 0 ? 'fort' : 'swan_HS') + '.63.nc').split('/thredds')[1];

// generate the full url
const fullTDSURL = data_url + "get_geo_point_data?lon=" + e.latlng.lng + "&lat=" + e.latlng.lat + "&ensemble=nowcast" +
'&tds_svr=' + tds_svr + '&url=' + tds_url;

const l_props = layer.properties;

// create a set of properties for this object
const pointProps =
{
"station_name": l_props['product_name'] + " " + id,
"lat": lat,
"lon": lon,
"location_name": layer.properties['product_name'].split(' ').slice(1).join(' ') + " at (lon, lat): " + id,
"model_run_id": layer.group,
"data_source": (l_props['event_type'] + '_' + l_props['grid_type']).toUpperCase(),
"source_name": l_props['model'],
"source_instance": l_props['instance_name'],
"source_archive": l_props['location'],
"forcing_metclass": l_props['met_class'],
"location_type": "GeoPoint",
"grid_name": l_props['grid_type'].toUpperCase(),
"csvurl": fullTDSURL,
"id": id
};

// populate selectedObservations list with the newly selected observation point
setSelectedObservations(previous => [...previous, pointProps]);
} else
// this can only happen when we are not in compare mode
if (!inCompareMode()) {
// if this is a good layer product
if (validLayerTypes.has(layer.properties['product_name'])) {
// create a marker target icon around the observation clicked
markClicked(map, e, id);

// get the FQDN of the UI data server
const data_url = `${getNamespacedEnvParam('REACT_APP_UI_DATA_URL')}`;

// split the URL
const split_url = layer.properties['tds_download_url'].split('/');

// generate the base TDS svr hostname/url
const tds_svr = split_url[0] + '//' + split_url[2] + '/thredds';

// create the correct TDS URL without the hostname
const tds_url = layer.properties['tds_download_url'].replace('catalog', 'dodsC').replace('catalog.html',
(layer.id.includes('swan') ? 'swan_HS' : 'fort') + '.63.nc').split('/thredds')[1];

// generate the full url
const fullTDSURL = data_url + "get_geo_point_data?lon=" + e.latlng.lng + "&lat=" + e.latlng.lat + "&ensemble=nowcast" +
'&tds_svr=' + tds_svr + '&url=' + tds_url;

const l_props = layer.properties;

// create a set of properties for this object
const pointProps =
{
"station_name": l_props['product_name'] + " " + id,
"lat": lat,
"lon": lon,
"location_name": layer.properties['product_name'].split(' ').slice(1).join(' ') + " at (lon, lat): " + id,
"model_run_id": layer.group,
"data_source": (l_props['event_type'] + '_' + l_props['grid_type']).toUpperCase(),
"source_name": l_props['model'],
"source_instance": l_props['instance_name'],
"source_archive": l_props['location'],
"forcing_metclass": l_props['met_class'],
"location_type": "GeoPoint",
"grid_name": l_props['grid_type'].toUpperCase(),
"csvurl": fullTDSURL,
"id": id
};

// populate selectedObservations list with the newly selected observation point
setSelectedObservations(previous => [...previous, pointProps]);
} else
setAlertMsg({
'severity': 'warning',
'msg': 'Geo-point selection is not available for the ' + layer.properties['product_name'] + ' product.'
});
}
else
setAlertMsg({
'severity': 'warning',
'msg': 'Geo-point selection is not available for the ' + layer.properties['product_name'] + ' product.'
'msg': 'Geo-point selection is not available while in compare mode.'
});
}
});
Expand All @@ -165,7 +185,7 @@ export const AdcircRasterLayer = (layer) => {
sld_body: currentStyle,
}), [currentStyle]);

return currentStyle && (
return currentStyle && productType && (
<WMSTileLayer
url={gs_wms_url}
layers={layer.layer.layers}
Expand Down
4 changes: 3 additions & 1 deletion src/components/map/default-layers.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { AdcircRasterLayer } from './adcirc-raster-layer';
import { markClicked, parseSharedURL, addSharedObservations, getNamespacedEnvParam, getBrandingHandler } from '@utils/map-utils';
import { getDefaultInstanceName } from "@components/config";

const newLayerDefaultState = (layer) => {
const { product_type } = layer.properties;
Expand Down Expand Up @@ -93,7 +94,7 @@ export const DefaultLayers = () => {
const shared_params = parseSharedURL();

// create the URLs to the data endpoints
const data_url = `${ getNamespacedEnvParam('REACT_APP_UI_DATA_URL') }get_ui_data_secure?limit=1&use_new_wb=true&use_v3_sp=true${ getBrandingHandler() }${ shared_params['run_id'] }`;
const data_url = `${ getNamespacedEnvParam('REACT_APP_UI_DATA_URL') }get_ui_data_secure?limit=1&use_new_wb=true&use_v3_sp=true${ getBrandingHandler() + getDefaultInstanceName() }${ shared_params['run_id'] }`;
const gs_wfs_url = `${ getNamespacedEnvParam('REACT_APP_GS_DATA_URL') }`;

// retrieve the catalog member with the provided id
Expand Down Expand Up @@ -136,6 +137,7 @@ export const DefaultLayers = () => {
}
return(data);
};

useQuery({
queryKey: ['apsviz-default-data', data_url],
queryFn: getDefaultLayers,
Expand Down
Loading

0 comments on commit 6d240f0

Please sign in to comment.