diff --git a/src/firefly/java/edu/caltech/ipac/firefly/data/ServerRequest.java b/src/firefly/java/edu/caltech/ipac/firefly/data/ServerRequest.java
index e4d04db86c..53266e2039 100644
--- a/src/firefly/java/edu/caltech/ipac/firefly/data/ServerRequest.java
+++ b/src/firefly/java/edu/caltech/ipac/firefly/data/ServerRequest.java
@@ -3,6 +3,7 @@
*/
package edu.caltech.ipac.firefly.data;
+import edu.caltech.ipac.firefly.util.MathUtil;
import edu.caltech.ipac.util.StringUtils;
import edu.caltech.ipac.visualize.plot.ResolvedWorldPt;
import edu.caltech.ipac.visualize.plot.WorldPt;
@@ -276,6 +277,10 @@ public double getDoubleParam(String key) {
return StringUtils.getDouble(getParam(key));
}
+ public double getDoubleParam(String key, double def) {
+ return StringUtils.getDouble(getParam(key), def);
+ }
+
public float getFloatParam(String key) {
return StringUtils.getFloat(getParam(key));
}
@@ -294,6 +299,15 @@ public WorldPt getWorldPtParam(String key) {
return wpt;
}
+ public double getSizeParam(String key, MathUtil.Units units) {
+ double sizeInDeg = getDoubleParam(key); // client sends size in degrees
+ return MathUtil.convert(MathUtil.Units.DEGREE, units, sizeInDeg);
+ }
+
+ public double getSizeParam(String key) {
+ return getSizeParam(key, MathUtil.Units.DEGREE);
+ }
+
//====================================================================
//
//====================================================================
diff --git a/src/firefly/js/charts/ChartsCntlr.js b/src/firefly/js/charts/ChartsCntlr.js
index 43a39a6013..340931a38b 100644
--- a/src/firefly/js/charts/ChartsCntlr.js
+++ b/src/firefly/js/charts/ChartsCntlr.js
@@ -86,6 +86,7 @@ function reducers() {
* @param {string} [p.viewerId] – viewer where chart will be displayed
* @param {boolean} [p.deletable] - is the chart deletable, if undefined: single chart in a group is not deletable, multiple are deletable
* @param {string} [p.help_id] - help id, if undefined, no help icon shows up
+ * @param {boolean} [p.activateViewer] - activate the chart viewer (tab) when chart is added
* @param {Function} [p.dispatcher=flux.process] - only for special dispatching uses such as remote
* @public
* @function dispatchChartAdd
diff --git a/src/firefly/js/core/LayoutCntlr.js b/src/firefly/js/core/LayoutCntlr.js
index a3fee5f642..32dc4a62a6 100644
--- a/src/firefly/js/core/LayoutCntlr.js
+++ b/src/firefly/js/core/LayoutCntlr.js
@@ -18,7 +18,8 @@ import { TBL_RESULTS_ADDED, TBL_RESULTS_REMOVE, TABLE_REMOVE, TABLE_SPACE_PATH,
} from '../tables/TablesCntlr.js';
import {CHART_ADD, CHART_REMOVE, CHART_SPACE_PATH} from '../charts/ChartsCntlr.js';
import {
- DEFAULT_FITS_VIEWER_ID, getMultiViewRoot, getViewer, PINNED_CHART_VIEWER_ID, REPLACE_VIEWER_ITEMS
+ DEFAULT_FITS_VIEWER_ID,
+ DEFAULT_PLOT2D_VIEWER_ID, getMultiViewRoot, getViewer, PINNED_CHART_VIEWER_ID, REPLACE_VIEWER_ITEMS
} from '../visualize/MultiViewCntlr.js';
import {COMMAND, getMenu, REINIT_APP} from './AppDataCntlr.js';
import {getDefaultChartProps} from '../charts/ChartUtil.js';
@@ -66,6 +67,8 @@ export const REMOVE_CELL = `${LAYOUT_PATH}.removeCell`;
export const ENABLE_SPECIAL_VIEWER= `${LAYOUT_PATH}.enableSpecialViewer`;
+/*------------------ Layout Constants ---------------------------- */
+
export const TRIVIEW_ICov_Ch_T= 'TRIVIEW_ICov_Ch_T'; //top left: image/cov, top right: charts, bottom: tables
export const TRIVIEW_I_ChCov_T= 'TRIVIEW_I_ChCov_T';//top left: image, top right: charts/cov, bottom: tables
export const BIVIEW_ICov_Ch= 'BIVIEW_ICov_Ch'; //left: image/cov, right: charts
@@ -73,8 +76,15 @@ export const BIVIEW_I_ChCov= 'BIVIEW_I_ChCov'; //left: image, right: charts/cov
export const BIVIEW_T_IChCov= 'BIVIEW_T_IChCov'; //left: tables, right: image/charts/cov
export const BIVIEW_IChCov_T= 'BIVIEW_IChCov_T'; //left: image/charts/cov, right: tables
-
-
+/* IDs of all the tabs other than TablesContainer inside the "Results" panel */
+export const TAB_IDS = {
+ ACTIVE_CHART: 'activeCharts',
+ PINNED_CHART: 'pinnedCharts',
+ COVERAGE: 'coverage',
+ DP: 'meta',
+ PINNED_IMAGE: 'fits',
+ PROPERTY_SHEET: 'rowDetails',
+};
/*---------------------------- Reducers ----------------------------*/
@@ -435,7 +445,9 @@ export function dropDownHandler(layoutInfo, action) {
// calculate dropDown when new UI elements are added or removed from results
switch (action.type) {
case CHART_ADD:
- return smartMerge(layoutInfo, {dropDown: resultsViewDropdown});
+ const {viewerId, activateViewer} = action.payload;
+ const updates = activateViewer ? getChartViewerLayout(viewerId) : {};
+ return smartMerge(layoutInfo, {...updates, dropDown: resultsViewDropdown});
case TBL_RESULTS_ADDED:
case TBL_RESULTS_ACTIVE:
case TABLE_LOADED:
@@ -571,3 +583,15 @@ function getColFitIdx(gridView, row, testIdx, gridColumns, testWidth) {
export const MENU_TAB_NODES = 'menuTabNodes';
export const getMenuTabNodes = () => getLayouInfo()?.[MENU_TAB_NODES] ?? {};
export const dispatchUpdateMenuTabNodes = (menuTabNodes) => dispatchUpdateLayoutInfo({[MENU_TAB_NODES]: menuTabNodes});
+
+// get LayoutInfo based on the viewerId of the chart add action
+const getChartViewerLayout = (viewerId) => {
+ switch (viewerId) {
+ case DEFAULT_PLOT2D_VIEWER_ID:
+ return {rightSide: {selectedTab: TAB_IDS.ACTIVE_CHART}};
+ case PINNED_CHART_VIEWER_ID:
+ return {rightSide: {selectedTab: TAB_IDS.PINNED_CHART}};
+ default:
+ return {};
+ }
+};
\ No newline at end of file
diff --git a/src/firefly/js/core/background/BackgroundUtil.js b/src/firefly/js/core/background/BackgroundUtil.js
index 539f2efa8c..03381d1881 100644
--- a/src/firefly/js/core/background/BackgroundUtil.js
+++ b/src/firefly/js/core/background/BackgroundUtil.js
@@ -318,15 +318,20 @@ function getMimeLoader(mimeType, href) {
}
}
+const handleLayoutChanges = (jobInfo) => {
+ showJobMonitor(false);
+ const {submitTo} = getMetadata({jobInfo});
+ if (submitTo) dispatchFormSubmit({submitTo}); // if this is a routed app, submit the form to update the route
+};
+
export function loadTableResult({jobInfo, request, href}) {
- const {submitTo, tbl_id} = getMetadata({jobInfo});
+ const {tbl_id} = getMetadata({jobInfo});
const tblRequest= makeFileRequest(null, href, null, {tbl_id});
copyRequestOptions(request, tblRequest);
const {tbl_ui_id} = getTableUiByTblId(tbl_id) || {}; // re-use existing table UI if exists
dispatchTableSearch(tblRequest, {tbl_ui_id});
- showJobMonitor(false);
- if (submitTo) dispatchFormSubmit({submitTo}); // if this is a routed app, submit the form to update the route
+ handleLayoutChanges(jobInfo);
}
export function getMetadata({jobInfo, resultIdx=0}) {
@@ -350,5 +355,6 @@ export function loadImageResult({jobInfo, href}) {
wpRequest.setPlotGroupId(viewerId);
const plotId = `${href.replace('.', '_')}-${jobInfo.jobId}`;
dispatchPlotImage({plotId, wpRequest, viewerId});
+ handleLayoutChanges(jobInfo);
}
diff --git a/src/firefly/js/core/background/JobInfo.jsx b/src/firefly/js/core/background/JobInfo.jsx
index 0350f9db8b..e74249f375 100644
--- a/src/firefly/js/core/background/JobInfo.jsx
+++ b/src/firefly/js/core/background/JobInfo.jsx
@@ -121,18 +121,22 @@ export function JobProgress({jobInfo, ...props}) {
if (!isActive(jobInfo)) return null;
const pct = getJobPctComplete(jobInfo);
- const lpProps = pct >= 0 ? {determinate:true, value:pct} : {size:'md'};
+ const lpProps = pct >= 0 ? {determinate:true, value:pct} : {};
return (
-
-
- Progress:
-
+
+
+ Progress:
+
+ {msg}
+
+
+ {elapsed}
+
-
- {elapsed} —
- {msg}
-
-
+
+
);
}
@@ -155,7 +159,7 @@ function JobInfoDetails({jobInfo={}}) {
-
+
diff --git a/src/firefly/js/templates/fireflyviewer/TriViewPanel.jsx b/src/firefly/js/templates/fireflyviewer/TriViewPanel.jsx
index f2e2506d44..63d6a4da07 100644
--- a/src/firefly/js/templates/fireflyviewer/TriViewPanel.jsx
+++ b/src/firefly/js/templates/fireflyviewer/TriViewPanel.jsx
@@ -12,11 +12,11 @@ import React, {memo, useContext} from 'react';
import {getExpandedChartProps} from '../../charts/ChartsCntlr.js';
import {allowPinnedCharts} from '../../charts/ChartUtil.js';
import {ActiveChartsPanel} from '../../charts/ui/ChartsContainer.jsx';
-import {dispatchUpdateLayoutInfo, getLayouInfo, getResultCounts, LO_VIEW} from '../../core/LayoutCntlr.js';
+import {dispatchUpdateLayoutInfo, getLayouInfo, getResultCounts, LO_VIEW, TAB_IDS} from '../../core/LayoutCntlr.js';
import {TablesContainer} from '../../tables/ui/TablesContainer.jsx';
import {AppInitLoadingMessage} from '../../ui/AppInitLoadingMessage.jsx';
import {AppPropertiesCtx} from '../../ui/AppPropertiesCtx.jsx';
-import {Tab, Tabs} from '../../ui/panel/TabPanel.jsx';
+import {Tab, TabPanel} from '../../ui/panel/TabPanel.jsx';
import {useStoreConnector} from '../../ui/SimpleComponent.jsx';
import {DEFAULT_PLOT2D_VIEWER_ID, PINNED_CHART_VIEWER_ID} from '../../visualize/MultiViewCntlr.js';
import {
@@ -94,21 +94,14 @@ TriViewPanel.propTypes = {
let lastSelected;
-const ACTIVE_CHART_TAB_ID= 'activeCharts';
-const PINNED_CHART_TAB_ID= 'pinnedCharts';
-const COVERAGE_TAB_ID= 'coverage';
-const DP_TAB_ID='meta';
-const PINNED_IMAGE_TAB_ID='fits';
-const PROPERTY_SHEET_TAB_ID='rowDetails';
-
function getSelectedTab(idObj,coverageRight,showXyPlots,showFits,anyTables,anyPinnedCharts) {
const tabIds= Object.entries(idObj).filter(([,v]) => v).map(([k]) => k);
if (tabIds.includes(lastSelected)) return lastSelected;
if (!anyTables) {
- if (showFits) return PINNED_IMAGE_TAB_ID;
- if (anyPinnedCharts) return PINNED_CHART_TAB_ID;
+ if (showFits) return TAB_IDS.PINNED_IMAGE;
+ if (anyPinnedCharts) return TAB_IDS.PINNED_CHART;
}
- return coverageRight ? COVERAGE_TAB_ID : showXyPlots ? ACTIVE_CHART_TAB_ID : PINNED_CHART_TAB_ID;
+ return coverageRight ? TAB_IDS.COVERAGE : showXyPlots ? TAB_IDS.ACTIVE_CHART : TAB_IDS.PINNED_CHART;
}
function makeKey(idObj) {
@@ -121,7 +114,7 @@ function makeKey(idObj) {
function RightSide({expanded, closeable, showXyPlots, showMeta, showFits, dataProductTableId, coverageRight, imagesWithCharts }) {
-
+ const selectedTab = useStoreConnector(()=>getLayouInfo()?.rightSide?.selectedTab);
const onTabSelect = (id) => {
lastSelected= id;
dispatchUpdateLayoutInfo({rightSide:{selectedTab:id}});
@@ -144,32 +137,32 @@ function RightSide({expanded, closeable, showXyPlots, showMeta, showFits, dataPr
const anyTables= Boolean(tableCnt);
const anyPinnedCharts= Boolean(pinChartCnt);
const idObj= {
- [ACTIVE_CHART_TAB_ID]: anyTables && showXyPlots,
- [PINNED_CHART_TAB_ID]: allowPinnedCharts() && showPinnedTab,
- [COVERAGE_TAB_ID]: anyTables && (imagesWithCharts || coverageRight),
- [DP_TAB_ID]: imagesWithCharts && showMeta,
- [PINNED_IMAGE_TAB_ID]: imagesWithCharts && showFits,
- [PROPERTY_SHEET_TAB_ID]:anyTables,
+ [TAB_IDS.ACTIVE_CHART]: anyTables && showXyPlots,
+ [TAB_IDS.PINNED_CHART]: allowPinnedCharts() && showPinnedTab,
+ [TAB_IDS.COVERAGE]: anyTables && (imagesWithCharts || coverageRight),
+ [TAB_IDS.DP]: imagesWithCharts && showMeta,
+ [TAB_IDS.PINNED_IMAGE]: imagesWithCharts && showFits,
+ [TAB_IDS.PROPERTY_SHEET]:anyTables,
};
const style= {height: '100%'};
const defaultSelected= getSelectedTab(idObj,coverageRight,showXyPlots,showFits,anyTables,anyPinnedCharts);
- if (idObj[PINNED_IMAGE_TAB_ID] && Object.values(idObj).filter( (v) => v).length===1) {
- return makeFitsPinnedTab({id:PINNED_IMAGE_TAB_ID,asTab:false});
+ if (idObj[TAB_IDS.PINNED_IMAGE] && Object.values(idObj).filter( (v) => v).length===1) {
+ return makeFitsPinnedTab({id:TAB_IDS.PINNED_IMAGE,asTab:false});
}
return(
-
- {idObj[ACTIVE_CHART_TAB_ID] && makeActiveChartTab({activeLabel, chartExpandedMode, closeable, asTab:true, id:ACTIVE_CHART_TAB_ID}) }
- {idObj[PINNED_CHART_TAB_ID] && makePinnedChartTab({pinnedLabel, chartExpandedMode, closeable, asTab:true, id:PINNED_CHART_TAB_ID}) }
- {idObj[COVERAGE_TAB_ID] && makeCoverageTab({id:COVERAGE_TAB_ID})}
- {idObj[DP_TAB_ID] && makeMultiProductViewerTab({dataProductTableId,id:DP_TAB_ID})}
- {idObj[PINNED_IMAGE_TAB_ID] && makeFitsPinnedTab({id:PINNED_IMAGE_TAB_ID,asTab:true})}
- {idObj[PROPERTY_SHEET_TAB_ID] && makePropertySheetTab({id:PROPERTY_SHEET_TAB_ID})}
-
+
+ {idObj[TAB_IDS.ACTIVE_CHART] && makeActiveChartTab({activeLabel, chartExpandedMode, closeable, asTab:true, id:TAB_IDS.ACTIVE_CHART}) }
+ {idObj[TAB_IDS.PINNED_CHART] && makePinnedChartTab({pinnedLabel, chartExpandedMode, closeable, asTab:true, id:TAB_IDS.PINNED_CHART}) }
+ {idObj[TAB_IDS.COVERAGE] && makeCoverageTab({id:TAB_IDS.COVERAGE})}
+ {idObj[TAB_IDS.DP] && makeMultiProductViewerTab({dataProductTableId,id:TAB_IDS.DP})}
+ {idObj[TAB_IDS.PINNED_IMAGE] && makeFitsPinnedTab({id:TAB_IDS.PINNED_IMAGE,asTab:true})}
+ {idObj[TAB_IDS.PROPERTY_SHEET] && makePropertySheetTab({id:TAB_IDS.PROPERTY_SHEET})}
+
);
}
diff --git a/src/firefly/js/ui/TargetPanel.jsx b/src/firefly/js/ui/TargetPanel.jsx
index e9fb7c9fa1..dd12f3ff8c 100644
--- a/src/firefly/js/ui/TargetPanel.jsx
+++ b/src/firefly/js/ui/TargetPanel.jsx
@@ -29,7 +29,7 @@ const simbadThenNed= 'simbadthenned';
const TargetPanelView = (props) =>{
const {showHelp, feedback, valid, message, onChange, value, button, slotProps, fieldKey,
children, resolver, showResolveSourceOp= true, showExample= true,
- label= LABEL_DEFAULT,
+ label= LABEL_DEFAULT, inputFieldLabel,
targetPanelExampleRow1, targetPanelExampleRow2,
connectedMarker=false, placeholderHighlight=true,
examples, onUnmountCB, sx}= props;
@@ -41,6 +41,7 @@ const TargetPanelView = (props) =>{
const positionField = (
onChange(ev.target.value, TARGET),
endDecorator,
@@ -74,6 +75,7 @@ const TargetPanelView = (props) =>{
TargetPanelView.propTypes = {
label : string,
+ inputFieldLabel: string,
sx: object,
valid : bool.isRequired,
showHelp : bool.isRequired,
diff --git a/src/firefly/js/ui/dynamic/EmbeddedPositionSearchPanel.jsx b/src/firefly/js/ui/dynamic/EmbeddedPositionSearchPanel.jsx
index e8184f497e..97cab9aba6 100644
--- a/src/firefly/js/ui/dynamic/EmbeddedPositionSearchPanel.jsx
+++ b/src/firefly/js/ui/dynamic/EmbeddedPositionSearchPanel.jsx
@@ -452,14 +452,15 @@ function ConeOp({slotProps,nullAllowed}) {
}= slotProps.sizeInput ?? {};
const {
targetKey=DEF_TARGET_PANEL_KEY,
+ inputFieldLabel,
targetPanelExampleRow1,
- targetPanelExampleRow2
+ targetPanelExampleRow2,
}= slotProps.targetPanel ?? {};
return (
);
- }
+ const selectedTab = useStoreConnector(() => getLayouInfo()?.images?.selectedTab);
const onTabSelect = (id) => dispatchUpdateLayoutInfo({images:{selectedTab:id}});
const key= (showCoverage&&coverageSide==='LEFT') +'--'+ showFits +'--' + showMeta;
+ const defaultSelected=getDefSelected(showCoverage,showFits,showMeta,dataProductTableId);
+
+ if (imageExpandedMode) {
+ return ( );
+ }
if (showCoverage || showFits || showMeta) {
return (
-
- { showCoverage && coverageSide==='LEFT' && makeCoverageTab({id:'coverage'}) }
- { showMeta && makeMultiProductViewerTab({dataProductTableId,id:'meta'}) }
- { showFits && makeFitsPinnedTab({id:'fits',asTab:true}) }
-
+
+ { showCoverage && coverageSide==='LEFT' && makeCoverageTab({id:TAB_IDS.COVERAGE}) }
+ { showMeta && makeMultiProductViewerTab({dataProductTableId,id:TAB_IDS.DP}) }
+ { showFits && makeFitsPinnedTab({id:TAB_IDS.PINNED_IMAGE,asTab:true}) }
+
);
}
@@ -125,24 +134,24 @@ TriViewImageSection.propTypes= {
closeable: PropTypes.bool,
dataProductTableId: PropTypes.string,
chartMetaId: PropTypes.string,
- selectedTab: PropTypes.oneOf(['fits', 'meta', 'coverage']),
+ selectedTab: PropTypes.oneOf([TAB_IDS.PINNED_IMAGE, TAB_IDS.DP, TAB_IDS.COVERAGE]),
coverageSide: PropTypes.string,
style: PropTypes.object
};
function getDefSelected(showCoverage, showFits, showMeta, tbl_id) {
- if (showFits) return 'fits';
+ if (showFits) return TAB_IDS.PINNED_IMAGE;
if (showMeta) {
- if (!showCoverage || isObsCoreLike(tbl_id)) return 'meta';
+ if (!showCoverage || isObsCoreLike(tbl_id)) return TAB_IDS.DP;
const sdAry= getServiceDescriptors(tbl_id);
if (sdAry) {
- if (sdAry.some((sd) => isDataLinkServiceDesc(sd) )) return 'meta'; // treat just like an obbscore table
- return 'coverage'; // probably a catalog with some secondary data products, a pretty common case
+ if (sdAry.some((sd) => isDataLinkServiceDesc(sd) )) return TAB_IDS.DP; // treat just like an obbscore table
+ return TAB_IDS.COVERAGE; // probably a catalog with some secondary data products, a pretty common case
}
- return 'meta'; // probably not obscore but some other data product table (like an upload of images)
+ return TAB_IDS.DP; // probably not obscore but some other data product table (like an upload of images)
}
- if (showCoverage) return 'coverage';
+ if (showCoverage) return TAB_IDS.COVERAGE;
}
export function startImagesLayoutWatcher() {
@@ -233,12 +242,12 @@ function handleNewTable(layoutInfo, action) {
const showCoverage= hasCoverageTable(tblList)|| hasCoverageData(tbl_id) || isOrbitalPathTable(tbl_id) || isCatalog(tbl_id);
if (isMeta || showTables ) {
- if (!showFits) selectedTab = 'coverage';
+ if (!showFits) selectedTab = TAB_IDS.COVERAGE;
showFits= showFits || shouldShowFits();
}
if (isMeta && showTables) {
showImages = true;
- selectedTab = 'meta';
+ selectedTab = TAB_IDS.DP;
showMeta = true;
dataProductTableId = tbl_id;
}
@@ -306,11 +315,11 @@ function onNewImage(layoutInfo, action) {
const {viewerId} = action.payload || {};
if (viewerId === META_VIEWER_ID) {
// select meta tab when new images are added to meta image group.
- selectedTab = 'meta';
+ selectedTab = TAB_IDS.DP;
showMeta = true;
} else if (viewerId === DEFAULT_FITS_VIEWER_ID) {
// select fits tab when new images are added to default group.
- selectedTab = 'fits';
+ selectedTab = TAB_IDS.PINNED_IMAGE;
showFits = true;
}