Skip to content

Commit 181aaad

Browse files
authored
Firefly-762,764,irsa-4046: Merge PR #1083 from firefly-762,764,irsa-4046
Firefly-762,764,irsa-4046: implement firefly-762, firefly-764, irsa-4046
2 parents aee7852 + 0eb1574 commit 181aaad

File tree

4 files changed

+127
-45
lines changed

4 files changed

+127
-45
lines changed

src/firefly/js/charts/ui/options/BasicOptions.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ export function basicOptions ({activeTrace:pActiveTrace, chartId, tbl_id, groupK
543543
const rgbStr = `rgba(${r},${g},${b},${a})`;
544544
dispatchValueChange({fieldKey: `data.${activeTrace}.marker.color`, groupKey, value: rgbStr, valid: true});
545545
}
546-
}, groupKey)}>
546+
}, groupKey, 'plots.colorpicker', .5)}>
547547
<ToolbarButton icon={MAGNIFYING_GLASS}/>
548548
</div>
549549
</div>),

src/firefly/js/ui/ColorPicker.jsx

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,28 @@ import {PopupPanel} from './PopupPanel.jsx';
99
import CompleteButton from './CompleteButton.jsx';
1010
import DialogRootContainer from './DialogRootContainer.jsx';
1111
import {SketchPicker} from 'react-color';
12+
import HelpIcon from 'firefly/ui/HelpIcon.jsx';
13+
import {getRGBA} from 'firefly/util/Color.js';
1214

1315

16+
const DEF_PRESET_COLORS= ['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#BD10E0',
17+
'#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF'];
1418

15-
export function showColorPickerDialog(color, callbackOnOKOnly, callbackOnBoth, cb, Id = '' ) {
19+
const dialogTip=
20+
`Choose a color:
21+
- graphically
22+
- as an RGB hex color code (does not support alpha)
23+
- by entering RGB values (0-255) and an alpha in percent (0-100)
24+
- from the swatches at the bottom`;
25+
26+
27+
export function showColorPickerDialog(color, callbackOnOKOnly, callbackOnBoth, cb, Id = '',
28+
helpId, presetAlpha, presetColors) {
1629
const popup= (
1730
<PopupPanel title={'Color Picker'+ (Id ? ` - ${Id}`: '')} >
18-
<ColorPickerWrapper callback={cb} color={color} callbackOnOKOnly={callbackOnOKOnly} callbackOnBoth={callbackOnBoth}/>
31+
<ColorPickerWrapper callback={cb} color={color} helpId={helpId}
32+
callbackOnOKOnly={callbackOnOKOnly} callbackOnBoth={callbackOnBoth}
33+
presetColors={presetColors} presetAlpha={presetAlpha} />
1934
</PopupPanel>
2035
);
2136
DialogRootContainer.defineDialog('ColorPickerDialog', popup);
@@ -24,22 +39,48 @@ export function showColorPickerDialog(color, callbackOnOKOnly, callbackOnBoth, c
2439

2540
var lastEv;
2641

27-
function ColorPickerWrapper ({callback,color,callbackOnOKOnly, callbackOnBoth}) {
42+
function ColorPickerWrapper ({callback,color,callbackOnOKOnly, callbackOnBoth,
43+
helpId= 'visualization.colorpicker',
44+
presetAlpha, presetColors=DEF_PRESET_COLORS}) {
2845
const [currentColor, setCurrentColor] = useState(color);
2946

30-
const onChange = (ev) => {
31-
lastEv=ev;
32-
const {r,g,b,a}= ev.rgb;
47+
const updateStateFromRGBA= (rgba) => {
48+
const {r,g,b,a}= rgba;
3349
setCurrentColor(`rgba(${r},${g},${b},${a})`);
34-
if (!callbackOnOKOnly && callback) callback(ev,false);
3550
};
3651

52+
const updateColor= (ev) => {
53+
lastEv=ev;
54+
updateStateFromRGBA(ev.rgb);
55+
if (!callbackOnOKOnly) callback?.(ev,false);
56+
};
57+
58+
const psColors= !presetAlpha ? presetColors :
59+
presetColors.map( (c) => {
60+
const [r,g,b]= getRGBA(c);
61+
return `rgba(${r},${g},${b},${presetAlpha})`;
62+
});
63+
64+
3765
return (
3866
<div>
39-
<SketchPicker onChange={onChange}
40-
color={currentColor} />
41-
<CompleteButton onSuccess={() => callbackOnOKOnly||callbackOnBoth ? callback(lastEv,true): null}
42-
dialogId='ColorPickerDialog'/>
67+
<div title={dialogTip}>
68+
<SketchPicker color={currentColor} presetColors={psColors}
69+
onChangeComplete={updateColor}
70+
onChange={(ev) => updateStateFromRGBA(ev.rgb)}/>
71+
</div>
72+
<div style={{
73+
display:'flex',
74+
justifyContent: 'space-between',
75+
alignItems: 'center',
76+
padding: '3px 5px 3px 6px'
77+
}}>
78+
<CompleteButton onSuccess={() => (callbackOnOKOnly||callbackOnBoth) && callback(lastEv,true)}
79+
dialogId='ColorPickerDialog'/>
80+
<div style={{ textAlign:'center'}}>
81+
<HelpIcon helpId={helpId} />
82+
</div>
83+
</div>
4384
</div>
4485
);
4586
}
@@ -48,5 +89,7 @@ ColorPickerWrapper.propTypes= {
4889
callback: PropTypes.func.isRequired,
4990
color: PropTypes.string.isRequired,
5091
callbackOnOKOnly: PropTypes.bool.isRequired,
51-
callbackOnBoth: PropTypes.bool.isRequired
92+
callbackOnBoth: PropTypes.bool.isRequired,
93+
presetAlpha: PropTypes.number,
94+
presetColors: PropTypes.arrayOf(PropTypes.string)
5295
};

src/firefly/js/ui/FileUploadDropdown.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@ import React, {useState} from 'react';
66
import {FormPanel} from './FormPanel.jsx';
77
import {dispatchHideDropDown} from '../core/LayoutCntlr.js';
88
import {panelKey, FileUploadViewPanel, resultSuccess, resultFail} from '../visualize/ui/FileUploadViewPanel.jsx';
9+
import {getAppOptions} from 'firefly/api/ApiUtil.js';
910

1011
const dropdownName = 'FileUploadDropDownCmd';
11-
const helpId = 'basics.searching';
1212

1313
const maskWrapper= { position:'absolute', left:0, top:0, width:'100%', height:'100%' };
1414

1515
export const FileUploadDropdown= () =>{
1616
const [doMask, changeMasking]= useState(() => false);
17+
const helpId = getAppOptions()?.uploadPanelHelpId ?? 'basics.searching';
1718
return (
1819
<div style={{width: '100%'}}>
1920
<FormPanel

src/firefly/js/visualize/ui/FileUploadViewPanel.jsx

Lines changed: 69 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {makeFileRequest} from '../../tables/TableRequestUtil.js';
2121
import {SelectInfo} from '../../tables/SelectInfo.js';
2222
import {getAViewFromMultiView, getMultiViewRoot, IMAGE} from '../MultiViewCntlr.js';
2323
import WebPlotRequest from '../WebPlotRequest.js';
24-
import {dispatchPlotHiPS, dispatchPlotImage, visRoot} from '../ImagePlotCntlr.js';
24+
import {dispatchPlotImage, visRoot} from '../ImagePlotCntlr.js';
2525
import {RadioGroupInputField} from '../../ui/RadioGroupInputField.jsx';
2626
import {showInfoPopup} from '../../ui/PopupUtil.jsx';
2727
import {WorkspaceUpload} from '../../ui/WorkspaceViewer.jsx';
@@ -44,7 +44,7 @@ import {FileAnalysisType, Format} from '../../data/FileAnalysis';
4444
import {dispatchValueChange} from 'firefly/fieldGroup/FieldGroupCntlr.js';
4545
import {CompleteButton,NONE} from 'firefly/ui/CompleteButton.jsx';
4646
import {createNewRegionLayerId} from 'firefly/drawingLayers/RegionPlot.js';
47-
import {PLOT_ID} from 'firefly/visualize/saga/CoverageWatcher.js';
47+
import {getAppOptions} from 'firefly/core/AppDataCntlr.js';
4848

4949

5050
export const panelKey = 'FileUploadAnalysis';
@@ -66,6 +66,14 @@ const SUPPORTED_TYPES=[
6666
FileAnalysisType.REGION,
6767
];
6868

69+
const TABLES_ONLY_SUPPORTED_TYPES=[
70+
FileAnalysisType.Table,
71+
];
72+
73+
74+
const isTablesOnly= () => getAppOptions()?.uploadPanelLimit==='tablesOnly';
75+
76+
6977
const uploadOptions = 'uploadOptions';
7078

7179
let currentAnalysisResult, currentReport, currentSummaryModel, currentDetailsModel;
@@ -88,6 +96,8 @@ export function FileUploadViewPanel() {
8896
}
8997
});
9098

99+
const tablesOnly= isTablesOnly();
100+
91101
const workspace = getWorkspaceConfig();
92102
const uploadMethod = [{value: FILE_ID, label: 'Upload file'},
93103
{value: URL_ID, label: 'Upload from URL'}
@@ -117,7 +127,7 @@ export function FileUploadViewPanel() {
117127
{report && <CompleteButton text='Clear File' groupKey={NONE} onSuccess={() =>clearReport()}/> }
118128
</div>
119129
</div>
120-
<FileAnalysis {...{report, summaryModel, detailsModel}}/>
130+
<FileAnalysis {...{report, summaryModel, detailsModel,tablesOnly}}/>
121131
<ImageDisplayOption/>
122132
</div>
123133
</FieldGroup>
@@ -134,18 +144,49 @@ const getPartCnt= () => currentReport?.parts?.length ?? 1;
134144
const getFirstPartType= () => currentSummaryModel?.tableData.data[0]?.[1];
135145
const getFileFormat= () => currentReport?.fileFormat;
136146
const isRegion= () => getFirstPartType()===FileAnalysisType.REGION;
137-
const isSupported= () => getFirstPartType() && (SUPPORTED_TYPES.includes(getFirstPartType()) || getFileFormat()===Format.FITS);
147+
148+
function isSinglePartFileSupported() {
149+
const supportedTypes= isTablesOnly() ? TABLES_ONLY_SUPPORTED_TYPES : SUPPORTED_TYPES;
150+
return getFirstPartType() && (supportedTypes.includes(getFirstPartType()));
151+
}
152+
153+
function isFileSupported() {
154+
return getFirstPartType() && (SUPPORTED_TYPES.includes(getFirstPartType()) || getFileFormat()===Format.FITS);
155+
}
156+
157+
158+
function getFirstExtWithData(parts) {
159+
return isTablesOnly() ?
160+
parts.findIndex((p) => p.type.includes(FileAnalysisType.Table)) :
161+
parts.findIndex((p) => !p.type.includes(FileAnalysisType.HeaderOnly));
162+
}
138163

139164

140165

166+
function tablesOnlyResultSuccess() {
167+
const tableIndices = getSelectedRows(FileAnalysisType.Table);
168+
const imageIndices = getSelectedRows(FileAnalysisType.Image);
169+
170+
if (tableIndices.length>0) {
171+
imageIndices.length>0 && showInfoPopup('Only loading the tables, ignoring the images.');
172+
sendTableRequest(tableIndices, getFileCacheKey());
173+
return true;
174+
}
175+
else {
176+
showInfoPopup('You may only upload tables.');
177+
return false;
178+
}
179+
}
180+
141181

142182
export function resultSuccess(request) {
183+
if (isTablesOnly()) return tablesOnlyResultSuccess();
143184
const fileCacheKey = getFileCacheKey();
144185

145-
const tableIndices = getSelectedRows('Table');
146-
const imageIndices = getSelectedRows('Image');
186+
const tableIndices = getSelectedRows(FileAnalysisType.Table);
187+
const imageIndices = getSelectedRows(FileAnalysisType.Image);
147188

148-
if (!isSupported()) {
189+
if (!isFileSupported()) {
149190
showInfoPopup(`File type of ${getFirstPartType()} is not supported.`);
150191
return false;
151192
}
@@ -210,11 +251,12 @@ function getNextState() {
210251
};
211252
modelToUseForDetails= currentSummaryModel;
212253

213-
const firstExtWithData = parts.findIndex((p) => !p.type.includes('HeaderOnly'));
254+
const firstExtWithData= getFirstExtWithData(parts);
214255
if (firstExtWithData >= 0) {
215256
const selectInfo = SelectInfo.newInstance({rowCount: data.length});
216257
selectInfo.setRowSelect(firstExtWithData, true); // default select first extension/part with data
217258
currentSummaryModel.selectInfo = selectInfo.data;
259+
modelToUseForDetails.highlightedRow= firstExtWithData;
218260
}
219261

220262
}
@@ -337,7 +379,7 @@ function AnalysisTable({summaryModel, detailsModel, report}) {
337379
);
338380
}
339381

340-
function SingleDataSet({type, desc, detailsModel, report, supported=isSupported()}) {
382+
function SingleDataSet({type, desc, detailsModel, report, supported=isSinglePartFileSupported()}) {
341383
const showDetails= supported && detailsModel;
342384
return (
343385
<div style={{display:'flex', flex:'1 1 auto', justifyContent: showDetails?'start':'center'}}>
@@ -375,18 +417,24 @@ function Details({detailsModel}) {
375417
}
376418

377419

378-
const FileAnalysis = React.memo( ({report, summaryModel, detailsModel}) => {
379-
const isUnknownFormat = get(report, 'fileFormat') === UNKNOWN_FORMAT;
380-
const tableArea = isUnknownFormat ?
381-
<div style={{flexGrow: 1, marginTop: 40, textAlign:'center', fontSize: 'larger', color: 'red'}}>
382-
Error: Unrecognized Format
383-
</div> :
384-
<AnalysisTable {...{summaryModel, detailsModel, report}} />;
420+
function getTableArea(report, summaryModel, detailsModel) {
421+
if (report?.fileFormat === UNKNOWN_FORMAT) {
422+
return (
423+
<div style={{flexGrow: 1, marginTop: 40, textAlign:'center', fontSize: 'larger', color: 'red'}}>
424+
Error: Unrecognized Format
425+
</div>
426+
);
427+
}
428+
return <AnalysisTable {...{summaryModel, detailsModel, report}} />;
429+
}
430+
431+
432+
const FileAnalysis = React.memo( ({report, summaryModel, detailsModel, tablesOnly}) => {
385433
if (report) {
386434
return (
387435
<div className='FileUpload__report'>
388436
{summaryModel.tableData.data.length>1 && <AnalysisInfo report={report} />}
389-
{tableArea}
437+
{getTableArea(report, summaryModel, detailsModel)}
390438
</div>
391439
);
392440
}
@@ -396,9 +444,9 @@ const FileAnalysis = React.memo( ({report, summaryModel, detailsModel}) => {
396444
You can load any of the following types of files:
397445
<ul>
398446
<li style={liStyle}>Custom catalog in IPAC, CSV, TSV, VOTABLE, or FITS table format</li>
399-
<li style={liStyle}>Any FITS file with tables or images (including multiple HDUs)</li>
400-
<li style={liStyle}>A Region file</li>
401-
<li style={liStyle}>A MOC FITS file</li>
447+
{!tablesOnly && <li style={liStyle}>Any FITS file with tables or images (including multiple HDUs)</li>}
448+
{!tablesOnly && <li style={liStyle}>A Region file</li> }
449+
{!tablesOnly && <li style={liStyle}>A MOC FITS file</li> }
402450
</ul>
403451
</div>);
404452

@@ -428,17 +476,7 @@ function getSelectedRows(type) {
428476
function sendRegionRequest(fileCacheKey) {
429477
const drawLayerId = createNewRegionLayerId();
430478
const title= currentReport.fileName ?? 'Region File';
431-
// if (!getPlotViewAry(visRoot())?.length) {
432-
// const wpRequest= WebPlotRequest.makeHiPSRequest('ivo://CDS/P/2MASS/color');
433-
// const {viewerId=''} = getAViewFromMultiView(getMultiViewRoot(), IMAGE) || {};
434-
// dispatchPlotHiPS({plotId: PLOT_ID, viewerId, wpRequest, pvOptions: {displayFixedTarget:false} });
435-
// setTimeout(() => {
436-
// dispatchCreateRegionLayer(drawLayerId, title, fileCacheKey, null);
437-
// }, 2000);
438-
// }
439-
// else {
440-
dispatchCreateRegionLayer(drawLayerId, title, fileCacheKey, null);
441-
// }
479+
dispatchCreateRegionLayer(drawLayerId, title, fileCacheKey, null);
442480
if (!getPlotViewAry(visRoot())?.length) {
443481
showInfoPopup('The region file is loaded but you will not be able to see it until you load an image (FITS or HiPS)', 'Warning');
444482
}

0 commit comments

Comments
 (0)