Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/RENCI/APSViz-UI-V3 into iss…
Browse files Browse the repository at this point in the history
…ue-312-compare-mode-alert-removal

# Conflicts:
#	src/components/map/adcirc-raster-layer.js
  • Loading branch information
PhillipsOwen committed Oct 29, 2024
2 parents 6d9ecd9 + 6d240f0 commit a617e23
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 64 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
106 changes: 60 additions & 46 deletions src/components/map/adcirc-raster-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ 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 +87,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,52 +112,55 @@ 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
};
// 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]);
}
}
}
});

Expand All @@ -161,7 +175,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
24 changes: 16 additions & 8 deletions src/context/map-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,28 @@ const layerTypes = {
};

export const LayersProvider = ({ children }) => {
// default and hurricane layer states
const [defaultModelLayers, setDefaultModelLayers] = useState([]);
const [hurricaneTrackLayers, setHurricaneTrackLayers] = useState([]);

// this object contains data for graph rendering
const [selectedObservations, setSelectedObservations] = useState([]);

// map reference state
const [map, setMap] = useState(null);

// base map state
const [baseMap, setBaseMap] = useState();

// used to track the view state of the share comment
const [showShareComment, setShowShareComment] = useState(true);

// used to show alerts
const [alertMsg, setAlertMsg] = useState(null);

// state to capture the default startup instance name
const [defaultInstanceName, setDefaultInstanceName] = useState(null);

/**
* this section is for the side-by-side compare mode items
* @type {string}
Expand Down Expand Up @@ -361,20 +375,14 @@ export const LayersProvider = ({ children }) => {
setDefaultModelLayers([...newLayers]);
};

const [baseMap, setBaseMap] = React.useState();

// used to track the view state of the share comment
const [showShareComment, setShowShareComment] = useState(true);

// used to show alerts
const [alertMsg, setAlertMsg] = useState(null);

return (
<LayersContext.Provider
value={{
map, setMap,
baseMap, setBaseMap,

defaultInstanceName, setDefaultInstanceName,

defaultModelLayers, setDefaultModelLayers,
hurricaneTrackLayers, setHurricaneTrackLayers,
selectedObservations, setSelectedObservations,
Expand Down
3 changes: 2 additions & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ module.exports = {
'@share': path.resolve(__dirname, 'src/components/trays/share/'),
'@utils': path.resolve(__dirname, 'src/utils/'),
'@side-by-side': path.resolve(__dirname, 'src/components/side-by-side/'),
'@alert-user': path.resolve(__dirname, 'src/components/alert-user/')
'@alert-user': path.resolve(__dirname, 'src/components/alert-user/'),
'@config': path.resolve(__dirname, 'src/components/config/')
}
},

Expand Down

0 comments on commit a617e23

Please sign in to comment.