diff --git a/src/firefly/js/ui/dynamic/EmbeddedPositionSearchPanel.jsx b/src/firefly/js/ui/dynamic/EmbeddedPositionSearchPanel.jsx
index c4c9a9adc..e03a25242 100644
--- a/src/firefly/js/ui/dynamic/EmbeddedPositionSearchPanel.jsx
+++ b/src/firefly/js/ui/dynamic/EmbeddedPositionSearchPanel.jsx
@@ -3,7 +3,7 @@ import React, {Fragment, useContext, useEffect, useState} from 'react';
import {oneOf, bool, string, number, arrayOf, object, func, shape, elementType} from 'prop-types';
import {defaultsDeep} from 'lodash';
import CoordinateSys from '../../visualize/CoordSys.js';
-import {CONE_AREA_OPTIONS, CONE_AREA_OPTIONS_UPLOAD, CONE_CHOICE_KEY, POLY_CHOICE_KEY, UPLOAD_CHOICE_KEY
+import {CONE_CHOICE_KEY, POLY_CHOICE_KEY, UPLOAD_CHOICE_KEY
} from '../../visualize/ui/CommonUIKeys.js';
import {HiPSTargetView} from '../../visualize/ui/TargetHiPSPanel.jsx';
import {showInfoPopup} from '../PopupUtil';
@@ -82,7 +82,7 @@ export const emptyHeaderSx = {
*
*/
export function EmbeddedPositionSearchPanel({
- initSelectToggle= CONE_CHOICE_KEY,
+ initSelectToggle,
nullAllowed= false,
insetSpacial=true,
usePosition= true,
@@ -106,25 +106,36 @@ export function EmbeddedPositionSearchPanel({
//conditionally show UploadTableChooser only when uploadInfo is empty - TAP like behavior
useEffect(() => {
if (doGetSearchTypeOp() === UPLOAD_CHOICE_KEY) {
- if (!uploadInfo.columns) showUploadTableChooser(setUploadInfo);
+ if (!uploadInfo?.columns) showUploadTableChooser(setUploadInfo);
else setUploadInfo(uploadInfo);
}
}, [uploadInfo]);
- if (!usePolygon && !usePosition && !useUpload) return false;
- const doToggle= usePosition && usePolygon;
- const initToggle= initSelectToggle;
+ const searchTypes = [
+ {key: CONE_CHOICE_KEY, use: usePosition, label: 'Cone'},
+ {key: POLY_CHOICE_KEY, use: usePolygon, label: 'Polygon'},
+ {key: UPLOAD_CHOICE_KEY, use: useUpload, label: 'Multi-object'},
+ ];
+
+ const enabledSearchTypes = searchTypes.filter((searchType)=>searchType.use);
+ if (enabledSearchTypes.length===0) return false;
+ const doToggle= enabledSearchTypes.length > 1;
+ const initToggle= initSelectToggle ?? enabledSearchTypes[0].key;
+ const searchTypeToggleOptions = enabledSearchTypes.map(({label, key:value})=>({label, value}));
const doGetSearchTypeOp= () => {
if (doToggle) return getSearchTypeOp() ?? initToggle;
- if (usePolygon) return POLY_CHOICE_KEY;
- if (useUpload) return UPLOAD_CHOICE_KEY;
- return CONE_CHOICE_KEY;
+ return initToggle;
};
const {targetKey=DEF_TARGET_PANEL_KEY}= slotProps.targetPanel ?? {};
const {polygonKey=DEFAULT_POLYGON_KEY, }= slotProps.polygonField ?? {};
- const {sizeKey= DEFAULT_SIZE_KEY, min= 1 / 3600, max= 1}= slotProps.sizeInput ?? {};
+ const {sizeKey= DEFAULT_SIZE_KEY, min= 1 / 3600, max= 1, enabled:sizeEnabled=true}= slotProps.sizeInput ?? {};
+
+ if (useUpload && !sizeEnabled && enabledSearchTypes.length===2) {
+ // because in this case, 'Cone' or 'Polygon' label won't make sense
+ searchTypeToggleOptions[0].label = 'Single-object';
+ }
const {
hipsUrl= DEFAULT_HIPS,
@@ -151,7 +162,6 @@ export function EmbeddedPositionSearchPanel({
overflow: 'auto',
};
- const sizeEnabled= slotProps?.sizeInput?.enabled ?? true;
return (
{
@@ -219,7 +229,7 @@ export function EmbeddedPositionSearchPanel({
>
{children}
@@ -341,6 +351,7 @@ function SearchSummary({request, targetKey, sizeKey, polygonKey, searchTypeKey,
//Label/Key & Value pairs do display, calculating here to determine easily where the last comma should be
const keyValuePairs = [
+ //TODO: Search Type's 'v' needs to come from label of toggle options, not hard-coded searchType strings in this function
{ k: 'Search Type', v: searchType },
...(radius && searchType === 'Cone' ? [{ k: 'Search Radius', v: radius }] : []),
...(coords && searchType !== 'Multi-Object' ? [{ k: 'Coordinates', v: coords }] : []),
@@ -362,7 +373,7 @@ function SearchSummary({request, targetKey, sizeKey, polygonKey, searchTypeKey,
}
function SpatialSearch({rootSlotProps: slotProps, insetSpacial, uploadInfo, setUploadInfo, searchTypeOp, doToggle,
- initToggle, nullAllowed, useUpload}) {
+ initToggle, nullAllowed, searchTypeToggleOptions}) {
const { searchTypeKey=CONE_AREA_KEY, sx } = slotProps.spatialSearch ?? {};
return (
@@ -371,7 +382,7 @@ function SpatialSearch({rootSlotProps: slotProps, insetSpacial, uploadInfo, setU
sx:{alignSelf: 'center'},
fieldKey: searchTypeKey, orientation: 'horizontal',
tooltip: 'Chose type of search', initialState: {value: initToggle},
- options: useUpload ? CONE_AREA_OPTIONS_UPLOAD : CONE_AREA_OPTIONS
+ options: searchTypeToggleOptions
}} />}
{searchTypeOp === CONE_CHOICE_KEY && }
{searchTypeOp === POLY_CHOICE_KEY && }
@@ -438,7 +449,8 @@ function UploadOp({slotProps, uploadInfo, setUploadInfo}) {
sizeKey= DEFAULT_SIZE_KEY,
min= 1 / 3600,
max= 1,
- initValue= DEFAULT_INIT_SIZE_VALUE
+ initValue= DEFAULT_INIT_SIZE_VALUE,
+ enabled= true
}= slotProps.sizeInput ?? {};
return (
@@ -448,15 +460,15 @@ function UploadOp({slotProps, uploadInfo, setUploadInfo}) {
centerColsInnerStack: {sx: {ml: 1, pt: 1.5}}
}
}}/>
-
+ }} />}
);
diff --git a/src/firefly/js/ui/tap/WavelengthPanel.jsx b/src/firefly/js/ui/tap/WavelengthPanel.jsx
index 9c525d3f9..4a39f10f3 100644
--- a/src/firefly/js/ui/tap/WavelengthPanel.jsx
+++ b/src/firefly/js/ui/tap/WavelengthPanel.jsx
@@ -6,7 +6,7 @@ import {CheckboxGroupInputField} from '../CheckboxGroupInputField.jsx';
import {FieldGroupCtx, ForceFieldGroupValid} from '../FieldGroup.jsx';
import {ListBoxInputField} from '../ListBoxInputField.jsx';
import {RadioGroupInputField} from '../RadioGroupInputField.jsx';
-import {useFieldGroupRerender, useFieldGroupWatch} from '../SimpleComponent.jsx';
+import {useFieldGroupRerender, useFieldGroupValue, useFieldGroupWatch} from '../SimpleComponent.jsx';
import {ValidationField} from '../ValidationField.jsx';
import {makeAdqlQueryRangeFragment, ConstraintContext, siaQueryRange} from './Constraints.js';
import {getTapObsCoreOptions} from './ObsCoreOptions';
@@ -21,6 +21,15 @@ const panelTitle = 'Spectral Coverage';
const panelValue = 'Wavelength';
const panelPrefix = getPanelPrefix(panelValue);
+const obsCoreWvlFieldKeys = {
+ selectionType: 'obsCoreWavelengthSelectionType',
+ rangeType: 'obsCoreWavelengthRangeType',
+ wvlContains: 'obsCoreWavelengthContains',
+ wvlMin: 'obsCoreWavelengthMinRange',
+ wvlMax: 'obsCoreWavelengthMaxRange',
+ wvlUnits: 'obsCoreWavelengthUnits',
+};
+
function getExponent(units) {
switch (units) {
case 'nm': return 'e-9';
@@ -31,17 +40,18 @@ function getExponent(units) {
}
-function makeWavelengthConstraints(wavelengthSelection, rangeType, filterDefinitions, fldObj) {
+function makeWavelengthConstraints(filterDefinitions, fldObj) {
const errList= makeFieldErrorList();
const siaConstraints= [];
const adqlConstraintsAry = [];
- const {obsCoreWavelengthContains:wlContains, obsCoreWavelengthMinRange:wlMinRange,
- obsCoreWavelengthMaxRange:wlMaxRange, obsCoreWavelengthUnits:wlUnits}= fldObj;
+ const {[obsCoreWvlFieldKeys.selectionType]:wavelengthSelection, [obsCoreWvlFieldKeys.rangeType]:rangeType,
+ [obsCoreWvlFieldKeys.wvlContains]:wlContains, [obsCoreWvlFieldKeys.wvlMin]:wlMinRange,
+ [obsCoreWvlFieldKeys.wvlMax]:wlMaxRange, [obsCoreWvlFieldKeys.wvlUnits]:wlUnits} = fldObj;
// pull out the fields we care about
- if (wavelengthSelection === 'filter') {
+ if (wavelengthSelection?.value === 'filter') {
const rangeList = [];
filterDefinitions.forEach((filterDefinition) => {
const fieldKey = 'filter' + filterDefinition.name;
@@ -66,9 +76,9 @@ function makeWavelengthConstraints(wavelengthSelection, rangeType, filterDefinit
// Need at least one field to be non-empty
errList.addError('at least one filter must be checked');
}
- } else if (wavelengthSelection === 'numerical') {
+ } else { //wavelengthSelection fld is undefined (because of no filters), or 'numerical' (radio option)
const exponent= getExponent(wlUnits?.value);
- if (rangeType === 'contains') {
+ if (rangeType?.value === 'contains') {
errList.checkForError(wlContains);
if (wlContains?.valid) {
const range = wlContains.value;
@@ -82,7 +92,7 @@ function makeWavelengthConstraints(wavelengthSelection, rangeType, filterDefinit
}
}
}
- if (rangeType === 'overlaps') {
+ if (rangeType?.value === 'overlaps') {
errList.checkForError(wlMinRange);
errList.checkForError(wlMaxRange);
const anyHasValue = wlMinRange?.value || wlMaxRange?.value;
@@ -110,29 +120,170 @@ function makeWavelengthConstraints(wavelengthSelection, rangeType, filterDefinit
const checkHeaderCtl= makeCollapsibleCheckHeader(getPanelPrefix(panelValue));
const {CollapsibleCheckHeader, collapsibleCheckHeaderKeys}= checkHeaderCtl;
-const fldKeys= ['obsCoreWavelengthContains', 'obsCoreWavelengthMinRange','obsCoreWavelengthSelectionType',
- 'obsCoreWavelengthRangeType', 'obsCoreWavelengthMaxRange', 'obsCoreWavelengthUnits'];
-export function ObsCoreWavelengthSearch({initArgs, serviceLabel, slotProps,useSIAv2}) {
+export function WavelengthOptions({initArgs, fieldKeys, filterDefinitions, slotProps }) {
+ const [getSelectionType,] = useFieldGroupValue(fieldKeys.selectionType);
+ const [getRangeType,] = useFieldGroupValue(fieldKeys.rangeType);
+
+ const hasFilters = filterDefinitions?.length > 0;
+ const useNumerical = !hasFilters || getSelectionType() === 'numerical';
+
+ const units = (
+
+
+
+
+ );
+
+ return (
+
+ {hasFilters && (
+
+ )}
+
+ {hasFilters && getSelectionType() === 'filter' && (
+
+ Require coverage at the approximate center of these filters:
+
+ {filterDefinitions.map((filterDefinition) => (
+
+ ))}
+
+
+ )}
+
+ {useNumerical && (
+
+
+
+
+ {getRangeType() === 'contains' && (
+
+
+
+ )}
+ {getRangeType() === 'overlaps' && (
+
+
+ to
+
+ {units}
+
+ )}
+
+ )}
+
+ );
+}
+
+WavelengthOptions.propTypes = {
+ initArgs: PropTypes.object,
+ fieldKeys: PropTypes.shape({
+ selectionType: PropTypes.string,
+ rangeType: PropTypes.string,
+ wvlContains: PropTypes.string,
+ wvlMin: PropTypes.string,
+ wvlMax: PropTypes.string,
+ wvlUnits: PropTypes.string,
+ }).isRequired,
+ filterDefinitions: PropTypes.arrayOf(PropTypes.shape({
+ name: PropTypes.string,
+ options: PropTypes.arrayOf(PropTypes.shape({ value: PropTypes.string, label: PropTypes.string }))
+ })),
+ slotProps: PropTypes.shape({
+ selectionType: PropTypes.object,
+ rangeType: PropTypes.object,
+ wvlContains: PropTypes.object,
+ wvlMin: PropTypes.object,
+ wvlMax: PropTypes.object,
+ wvlUnits: PropTypes.object,
+ filterDefOptionsGroup: PropTypes.object,
+ numericalWvlOptions: PropTypes.object,
+ filterBandsWvlOptions: PropTypes.object,
+ })
+};
+
+
+export function ObsCoreWavelengthSearch({ initArgs, serviceLabel, slotProps, useSIAv2 }) {
const filterDefinitions = getTapObsCoreOptions(serviceLabel).filterDefinitions ?? [];
- const fdDefsKeys= filterDefinitions.length ? filterDefinitions.map((fd) =>'filter' +fd.name ) : [];
+ const fdDefsKeys = filterDefinitions.length ? filterDefinitions.map((fd) => 'filter' + fd.name) : [];
+ const fldKeys = Object.values(obsCoreWvlFieldKeys);
- const {getVal,makeFldObj}= useContext(FieldGroupCtx);
- const {setConstraintFragment}= useContext(ConstraintContext);
+ const { makeFldObj } = useContext(FieldGroupCtx);
+ const { setConstraintFragment } = useContext(ConstraintContext);
const [constraintResult, setConstraintResult] = useState({});
- useFieldGroupRerender([...fldKeys,...fdDefsKeys, ...collapsibleCheckHeaderKeys]); // force rerender on any change
+ useFieldGroupRerender([...fldKeys, ...fdDefsKeys, ...collapsibleCheckHeaderKeys]); // force rerender on any change
-
- const rangeType= getVal('obsCoreWavelengthRangeType');
- const selectionType= getVal('obsCoreWavelengthSelectionType') ?? 'numerical';
- const hasFilters = filterDefinitions?.length > 0;
- const useNumerical = !hasFilters || selectionType === 'numerical';
- const updatePanelStatus= makePanelStatusUpdater(checkHeaderCtl.isPanelActive(), panelValue);
+ const updatePanelStatus = makePanelStatusUpdater(checkHeaderCtl.isPanelActive(), panelValue);
useEffect(() => {
- const fldObj= makeFldObj([...fdDefsKeys, ...fldKeys]);
- const constraints= makeWavelengthConstraints(selectionType,rangeType, filterDefinitions, fldObj);
- updatePanelStatus(constraints, constraintResult, setConstraintResult,useSIAv2);
+ const fldObj = makeFldObj([...fdDefsKeys, ...fldKeys]);
+ const constraints = makeWavelengthConstraints(filterDefinitions, fldObj);
+ updatePanelStatus(constraints, constraintResult, setConstraintResult, useSIAv2);
});
useEffect(() => {
@@ -140,114 +291,23 @@ export function ObsCoreWavelengthSearch({initArgs, serviceLabel, slotProps,useSI
return () => setConstraintFragment(panelPrefix, '');
}, [constraintResult]);
- useFieldGroupWatch([...fdDefsKeys,
- // 'obsCoreWavelengthContains', 'obsCoreWavelengthMinRange', 'obsCoreWavelengthMaxRange', 'obsCoreWavelengthUnits' ],
- 'obsCoreWavelengthContains', 'obsCoreWavelengthMinRange', 'obsCoreWavelengthMaxRange' ],
- (valAry,isInit) => {
- !isInit && valAry.some((v)=>v) && checkHeaderCtl.setPanelActive(true);
- });
-
- const units= (
-
-
-
-
- );
-
-
+ useFieldGroupWatch([...fdDefsKeys, obsCoreWvlFieldKeys.wvlContains, obsCoreWvlFieldKeys.wvlMin, obsCoreWvlFieldKeys.wvlMax],
+ (valAry, isInit) => {
+ !isInit && valAry.some((v) => v) && checkHeaderCtl.setPanelActive(true);
+ });
return (
-
-
+
+
- {hasFilters && }
- {hasFilters && selectionType === 'filter' &&
-
- Require coverage at the approximate center of these filters:
-
- {filterDefinitions.map((filterDefinition) => {
- return (
- );
- })}
-
-
- }
- {useNumerical &&
-
-
-
-
- {rangeType === 'contains' &&
-
-
-
- }
- {rangeType === 'overlaps' &&
-
-
- to
-
- {units}
-
- }
-
- }
-
+
+
@@ -259,9 +319,7 @@ ObsCoreWavelengthSearch.propTypes = {
serviceLabel: PropTypes.string,
useSIAv2: PropTypes.bool,
slotProps: PropTypes.shape({
- obsCoreWavelengthUnits: PropTypes.object,
- obsCoreFilterDefinitions: PropTypes.object,
- obsCoreWavelengthSelectionType: PropTypes.object,
- obsCoreWavelengthRangeType: PropTypes.object,
+ root: PropTypes.object,
+ wavelengthOptions: WavelengthOptions.propTypes.slotProps
})
};