Skip to content

Commit e8fb27b

Browse files
committed
IRSA-5700, FIREFLY-1289, FIREFLY-1375: packaging and zoom, perfered hips
- IRSA-5700 : packaging uses filename - Firefly-1289: better zoom level - Firefly-1375: TAP can have a per service preferred hips for coverage
1 parent 96b4875 commit e8fb27b

File tree

7 files changed

+108
-29
lines changed

7 files changed

+108
-29
lines changed

src/firefly/java/edu/caltech/ipac/firefly/server/query/ObsCorePackager.java

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package edu.caltech.ipac.firefly.server.query;
22

3-
import edu.caltech.ipac.firefly.data.*;
3+
import edu.caltech.ipac.firefly.data.DownloadRequest;
4+
import edu.caltech.ipac.firefly.data.FileInfo;
5+
import edu.caltech.ipac.firefly.data.HttpResultInfo;
6+
import edu.caltech.ipac.firefly.data.ServerRequest;
47
import edu.caltech.ipac.firefly.server.ServerContext;
58
import edu.caltech.ipac.firefly.server.db.EmbeddedDbUtil;
69
import edu.caltech.ipac.firefly.server.network.HttpServiceInput;
@@ -9,12 +12,17 @@
912
import edu.caltech.ipac.table.DataGroup;
1013
import edu.caltech.ipac.table.MappedData;
1114
import edu.caltech.ipac.table.io.VoTableReader;
15+
import edu.caltech.ipac.util.FileUtil;
1216
import edu.caltech.ipac.util.download.URLDownload;
1317

1418
import java.io.File;
1519
import java.io.IOException;
16-
import java.util.*;
1720
import java.net.URL;
21+
import java.util.ArrayList;
22+
import java.util.Arrays;
23+
import java.util.HashMap;
24+
import java.util.List;
25+
import java.util.Map;
1826

1927
import static edu.caltech.ipac.util.FileUtil.getUniqueFileNameForGroup;
2028
import static org.apache.commons.lang.StringUtils.substringAfterLast;
@@ -55,27 +63,32 @@ private List<FileGroup> computeFileGroup(DownloadRequest request) throws DataAcc
5563
String contentType = tmpFileInfo.getAttribute(HttpResultInfo.CONTENT_TYPE);
5664

5765
String colNames = request.getSearchRequest().getParam("templateColNames");
66+
boolean useSourceUrlFileName= request.getSearchRequest().getBooleanParam("useSourceUrlFileName",false);
5867
String[] cols = colNames != null ? colNames.split(",") : null;
5968

60-
String ext_file_name = getFileName(idx,cols,dgDataUrl);
69+
String ext_file_name = getFileName(idx,cols,useSourceUrlFileName,dgDataUrl,url);
6170
String extension;
6271

6372
if (access_format != null) {
6473
if (access_format.contains("datalink")) {
6574
ext_file_name = getUniqueFileNameForGroup(ext_file_name, dataLinkFolders);
66-
List<FileInfo> tmpFileInfos = parseDatalink(url, ext_file_name);
75+
List<FileInfo> tmpFileInfos = parseDatalink(url, ext_file_name, useSourceUrlFileName);
6776
fileInfos.addAll(tmpFileInfos);
6877
}
6978
else { //non datalink entry - such as fits,jpg etc.
70-
extension = access_format.replaceAll(".*/", "");
71-
ext_file_name += "." + extension;
79+
if (!useSourceUrlFileName || !FileUtil.getExtension(ext_file_name).isEmpty()) {
80+
extension = access_format.replaceAll(".*/", "");
81+
ext_file_name += "." + extension;
82+
}
7283
FileInfo fileInfo = new FileInfo(tmpFile.getPath(), ext_file_name, 0);
7384
fileInfos.add(fileInfo);
7485
}
7586
}
7687
else { //access_format is null, so try and get it from the url's Content_Type
77-
extension = getExtFromURL(contentType);
78-
ext_file_name += "." + extension;
88+
if (!useSourceUrlFileName || !FileUtil.getExtension(ext_file_name).isEmpty()) {
89+
extension = getExtFromURL(contentType);
90+
ext_file_name += "." + extension;
91+
}
7992
FileInfo fileInfo = new FileInfo(tmpFile.getPath(), ext_file_name, 0);
8093
fileInfos.add(fileInfo);
8194
}
@@ -89,7 +102,7 @@ private List<FileGroup> computeFileGroup(DownloadRequest request) throws DataAcc
89102
return Arrays.asList(new FileGroup(fileInfos, null, 0, "ObsCore Download Files"));
90103
}
91104

92-
public static List<FileInfo> parseDatalink(URL url, String prepend_file_name) {
105+
public static List<FileInfo> parseDatalink(URL url, String prepend_file_name, boolean useSourceUrlFileName) {
93106
List<FileInfo> fileInfos = new ArrayList<>();;
94107
try {
95108
File tmpFile = File.createTempFile("datlink-", ".xml", ServerContext.getTempWorkDir());
@@ -125,13 +138,26 @@ public static List<FileInfo> parseDatalink(URL url, String prepend_file_name) {
125138

126139
if (testSem(sem,"#this") || testSem(sem,"#thumbnail") ||testSem(sem,"#preview") ||
127140
testSem(sem,"#preview-plot")) {
128-
String ext_file_name = prepend_file_name;
129-
ext_file_name = testSem(sem, "#this") ? ext_file_name : ext_file_name + "-" + substringAfterLast(sem, "#");
130-
String extension = "unknown";
131-
extension = content_type != null ? getExtFromURL(content_type) : getExtFromURL(accessUrl);
132-
ext_file_name += "." + extension;
133-
//create a folder only if makeDataLinkFolder is true
134-
ext_file_name = makeDataLinkFolder ? prepend_file_name + "/" + ext_file_name : ext_file_name;
141+
142+
String ext_file_name= null;
143+
if (useSourceUrlFileName) {
144+
String fileName= new URL(accessUrl).getFile();
145+
String ext= FileUtil.getExtension(fileName);
146+
if (!ext.isEmpty()) ext_file_name= fileName;
147+
}
148+
if (ext_file_name==null){
149+
ext_file_name = prepend_file_name;
150+
ext_file_name = testSem(sem, "#this") ? ext_file_name : ext_file_name + "-" + substringAfterLast(sem, "#");
151+
String extension = "unknown";
152+
extension = content_type != null ? getExtFromURL(content_type) : getExtFromURL(accessUrl);
153+
ext_file_name += "." + extension;
154+
//create a folder only if makeDataLinkFolder is true
155+
ext_file_name = makeDataLinkFolder ? prepend_file_name + "/" + ext_file_name : ext_file_name;
156+
}
157+
158+
159+
160+
135161
FileInfo fileInfo = new FileInfo(accessUrl, ext_file_name, 0);
136162
fileInfos.add(fileInfo);
137163
}
@@ -170,13 +196,20 @@ public static String makeValidString(String val) {
170196
//remove spaces and replace all non-(alphanumeric,period,underscore,hyphen) chars with underscore
171197
return val.replaceAll("\\s", "").replaceAll("[^a-zA-Z0-9._-]", "_");
172198
}
173-
public static String getFileName(int idx, String[] colNames, MappedData dgDataUrl) {
199+
public static String getFileName(int idx, String[] colNames, boolean useSourceUrlFileName, MappedData dgDataUrl, URL url) {
174200
String obs_collection = (String) dgDataUrl.get(idx, "obs_collection");
175201
String instrument_name = (String) dgDataUrl.get(idx, "instrument_name");
176202
String obs_id = (String) dgDataUrl.get(idx, "obs_id");
177203
String obs_title = (String) dgDataUrl.get(idx, "obs_title");
178204
String file_name = "";
179205

206+
//option 0: if useSourceUrlFileName is true the try to get it from the URL
207+
if (useSourceUrlFileName) {
208+
String fileName= url.getFile();
209+
String ext= FileUtil.getExtension(fileName);
210+
if (!ext.isEmpty()) return fileName;
211+
}
212+
180213
//option 1: use productTitleTemplate (colNames) if available to construct file name
181214
if (colNames != null) {
182215
for(String col : colNames) {

src/firefly/js/templates/common/ttFeatureWatchers.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {dispatchAddTableTypeWatcherDef} from '../../core/MasterSaga.js';
55
import {dispatchTableUiUpdate} from '../../tables/TablesCntlr.js';
66
import {getActiveTableId, getMetaEntry, getTableUiByTblId, getTblById} from '../../tables/TableUtil.js';
77
import {DownloadButton, DownloadOptionPanel} from '../../ui/DownloadDialog.jsx';
8-
import {getTapObsCoreOptions} from '../../ui/tap/TableSearchHelpers.jsx';
8+
import {getTapObsCoreOptions, getTapObsCoreOptionsGuess} from '../../ui/tap/TableSearchHelpers.jsx';
99
import {isObsCoreLike} from '../../voAnalyzer/TableAnalysis.js';
1010
import {getCatalogWatcherDef} from '../../visualize/saga/CatalogWatcher.js';
1111
import {getUrlLinkWatcherDef} from '../../visualize/saga/UrlLinkWatcher.js';
@@ -66,11 +66,17 @@ function setupObsCorePackaging(tbl_id) {
6666
}
6767

6868
function updateSearchRequest( tbl_id='', dlParams='', sRequest=null) {
69-
const template= getAppOptions().tapObsCore?.productTitleTemplate;
69+
const hostname= new URL(sRequest.source)?.hostname;
70+
71+
const template= getTapObsCoreOptionsGuess(hostname)?.productTitleTemplate;
72+
const useSourceUrlFileName= getTapObsCoreOptionsGuess(hostname)?.packagerUsesSourceUrlFileName;
73+
74+
7075
const templateColNames= template && getColNameFromTemplate(template);
7176
const searchRequest = cloneDeep( sRequest);
7277
searchRequest.template = template;
7378
searchRequest.templateColNames = templateColNames?.toString();
79+
searchRequest.useSourceUrlFileName= useSourceUrlFileName;
7480
return searchRequest;
7581
}
7682

@@ -85,7 +91,7 @@ const PrepareDownload = React.memo(() => {
8591
<div>
8692
<DownloadButton>
8793
<DownloadOptionPanel {...{
88-
updateSearchRequest: updateSearchRequest,
94+
updateSearchRequest,
8995
showZipStructure: false, //flattened files, except for datalink (with more than one valid file)
9096
dlParams: {
9197
FileGroupProcessor:'ObsCorePackager',

src/firefly/js/ui/tap/TableSearchHelpers.jsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import HelpIcon from 'firefly/ui/HelpIcon';
2-
import {isEqual} from 'lodash';
2+
import {isEqual, isObject} from 'lodash';
33
import Prism from 'prismjs';
44
import PropTypes from 'prop-types';
55
import React, {useEffect, useRef} from 'react';
@@ -30,6 +30,17 @@ const DEF_ERR_MSG= 'Constraints Error';
3030
export const getTapObsCoreOptions= (serviceLabel) =>
3131
getAppOptions().tapObsCore?.[serviceLabel] ?? getAppOptions().tapObsCore ?? {};
3232

33+
34+
35+
export function getTapObsCoreOptionsGuess(serviceLabelGuess) {
36+
const {tapObsCore={}}= getAppOptions();
37+
if (!serviceLabelGuess) return tapObsCore;
38+
const guessKey= Object.entries(tapObsCore)
39+
.find( ([key,value]) => isObject(value) && serviceLabelGuess.includes(key))?.[0];
40+
return getTapObsCoreOptions(guessKey);
41+
}
42+
43+
3344
/**
3445
* make a FieldErrorList object
3546
* @returns {FieldErrorList}

src/firefly/js/ui/tap/TapSearchRootPanel.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {dispatchTableSearch} from 'firefly/tables/TablesCntlr.js';
1717
import {showInfoPopup, showYesNoPopup} from 'firefly/ui/PopupUtil.jsx';
1818
import {dispatchHideDialog} from 'firefly/core/ComponentCntlr.js';
1919
import {dispatchHideDropDown} from 'firefly/core/LayoutCntlr.js';
20+
import {MetaConst} from '../../data/MetaConst.js';
2021
import {
2122
ConstraintContext, getTapUploadSchemaEntry, getUploadServerFile, getUploadTableName,
2223
getHelperConstraints, getUploadConstraint,
@@ -32,6 +33,7 @@ import {
3233
import {SectionTitle, AdqlUI, BasicUI} from 'firefly/ui/tap/TableSelectViewPanel.jsx';
3334
import {useFieldGroupMetaState} from '../SimpleComponent.jsx';
3435
import {PREF_KEY} from 'firefly/tables/TablePref.js';
36+
import {getTapObsCoreOptions} from './TableSearchHelpers.jsx';
3537

3638

3739

@@ -98,6 +100,10 @@ export function getServiceLabel(serviceUrl) {
98100
return (serviceUrl && (tapOps.find( (e) => e.value===serviceUrl)?.labelOnly)) || '';
99101
}
100102

103+
export function getServiceHiPS(serviceUrl) {
104+
const tapOps= getTapServices();
105+
return (serviceUrl && (tapOps.find( (e) => e.value===serviceUrl)?.hipsUrl)) || '';
106+
}
101107

102108

103109
export function TapSearchPanel({initArgs= {}, titleOn=true}) {
@@ -384,6 +390,7 @@ function onTapSearchSubmit(request,serviceUrl,tapBrowserState) {
384390
const hasMaxrec = !isNaN(parseInt(maxrec));
385391
const doSubmit = () => {
386392
const serviceLabel= getServiceLabel(serviceUrl);
393+
const hips= getServiceHiPS(serviceUrl);
387394
const adqlClean = adql.replace(/\s/g, ' '); // replace all whitespaces with spaces
388395
const params = {serviceUrl, QUERY: adqlClean};
389396
if (isUpload) {
@@ -399,6 +406,8 @@ function onTapSearchSubmit(request,serviceUrl,tapBrowserState) {
399406
additionalMeta[PREF_KEY]= `${tapBrowserState.schemaName}-${tapBrowserState.tableName}`;
400407
}
401408
additionalMeta.serviceLabel= serviceLabel;
409+
if (hips) additionalMeta[MetaConst.COVERAGE_HIPS]= hips;
410+
402411
treq.META_INFO= {...treq.META_INFO, ...additionalMeta };
403412
dispatchTableSearch(treq, {backgroundable: true, showFilters: true, showInfoButton: true});
404413
};

src/firefly/js/visualize/ZoomUtil.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,28 @@ import {convertAngle} from './VisUtil.js';
2121
*/
2222
export const FullType = new Enum(['ONLY_WIDTH', 'WIDTH_HEIGHT', 'ONLY_HEIGHT']);
2323

24-
export const imageLevels= [.0125, .025, .05,.1,.25,.3, .4, .5, .75, .8, .9, 1, 1.25, 1.5,2, 2.5,3, 3.5,
25-
4,5, 6, 7,8, 9, 10, 11, 12, 13, 14, 15, 16, 18,20,22,24,28, 32];
24+
/**
25+
* This is the master list of zoom levels for Firefly image displays.
26+
* These zoom levels are used when clicking on the +/- icons, and are
27+
* also used to construct the zoom-level dialog. Scroll-wheel zooming
28+
* can reach levels between the steps.
29+
*/
30+
31+
export const imageLevels = [
32+
/* For zoomed-out images we use large steps - factors of 2. */
33+
0.015625, 0.03125, 0.0625, 0.125, 0.25,
34+
/* Otherwise we use four steps per factor of two, */
35+
/* i.e., the 4th root of 2 or about 1.189 / 19%, */
36+
/* rounded to three digits after the decimal. */
37+
0.297, 0.354, 0.420, 0.5,
38+
0.595, 0.707, 0.841, 1,
39+
1.189, 1.414, 1.682, 2,
40+
2.378, 2.828, 3.364, 4,
41+
4.757, 5.657, 6.727, 8,
42+
9.514, 11.314, 13.454, 16,
43+
19.027, 22.627, 26.909, 32
44+
];
45+
2646
export const imageLevelsReversed= [...imageLevels].reverse();
2747

2848

src/firefly/js/visualize/reducer/HandlePlotCreation.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -327,12 +327,11 @@ function plotOverlayFail(state,action) {
327327
}
328328

329329
function plotFail(state,action) {
330-
const {description, plotId}= action.payload;
331-
const {plotViewAry}= state;
332-
const plotView= getPlotViewById(state,plotId);
333-
if (!plotView) return state;
330+
const {description, plotId, plotIdAry:inPlotIdAry=[]}= action.payload;
331+
const plotIdAry= plotId ? [plotId] : inPlotIdAry;
334332
const changes= {plottingStatusMsg:description,serverCall:'fail', nonRecoverableFail:true };
335-
return {...state, plotViewAry:clonePvAry(plotViewAry,plotId,changes)};
333+
const plotViewAry= state.plotViewAry?.map( (pv) => plotIdAry.includes(pv.plotId) ? {...pv,...changes} : pv);
334+
return {...state, plotViewAry};
336335
}
337336

338337
function hipsFail(state,action) {

src/firefly/js/visualize/task/PlotImageTask.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ async function executeGroupSearch(rawAction, dispatcher) {
8888
const wpResult= await callGetWebPlotGroup(wpRequestAry, requestKey);
8989
processPlotImageSuccessResponse(dispatcher,rawAction.payload,wpResult);
9090
} catch (e) {
91-
dispatcher( { type: ImagePlotCntlr.PLOT_IMAGE_FAIL, payload: {wpRequestAry, error:e} } );
91+
const plotIdAry= wpRequestAry.map( (r) => r.getPlotId()).filter( (id) => id);
92+
dispatcher( { type: ImagePlotCntlr.PLOT_IMAGE_FAIL, payload: {plotIdAry, wpRequestAry, error:e} } );
9293
logger.error('plot group error', e);
9394
}
9495
}

0 commit comments

Comments
 (0)