Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default instance name at startup #308

Merged
merged 15 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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