diff --git a/src/firefly/html/css/global.css b/src/firefly/html/css/global.css
index a7314c9c6..229873115 100644
--- a/src/firefly/html/css/global.css
+++ b/src/firefly/html/css/global.css
@@ -308,30 +308,6 @@ div.rootStyle img {
/*-------------------< loading mask ---------------------*/
-.mask-only {
- position: absolute;
- width: 100%;
- height: 100%;
- background-color: var(--joy-palette-background-backdrop);
- backdrop-filter: blur(8px);
-}
-
-.loading-mask {
- position: absolute;
- width: 100%;
- height: 100%;
-}
-
-.loading-mask::before {
- content: '';
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: var(--joy-palette-background-backdrop);
- backdrop-filter: blur(8px);
-}
@-webkit-keyframes spin {
from { transform: rotate(0deg);}
to {transform: rotate(359deg);}
@@ -353,23 +329,6 @@ div.rootStyle img {
animation-iteration-count: infinite;
animation-timing-function: linear;
}
-
-.loading-mask::after {
- content: "";
- position: absolute;
- border-width: 3px;
- border-style: solid;
- border-color: transparent rgb(255, 255, 255) rgb(255, 255, 255);
- border-radius: 50%;
- width: 24px;
- height: 24px;
- top: calc(50% - 12px);
- left: calc(50% - 12px);
- animation-name: spin;
- animation-duration: 2s;
- animation-iteration-count: infinite;
- animation-timing-function: linear;
-}
/*------------------- loading mask >---------------------*/
.lost-connection--small {
diff --git a/src/firefly/js/charts/ui/PlotlyWrapper.jsx b/src/firefly/js/charts/ui/PlotlyWrapper.jsx
index c94b96b93..d0abcbd2d 100644
--- a/src/firefly/js/charts/ui/PlotlyWrapper.jsx
+++ b/src/firefly/js/charts/ui/PlotlyWrapper.jsx
@@ -14,6 +14,7 @@ import {logger} from '../../util/Logger.js';
import BrowserInfo from '../../util/BrowserInfo.js';
import Enum from 'enum';
import {showPlotLySaveDialog} from 'firefly/charts/ui/PlotlySaveDialog.jsx';
+import {Skeleton} from '@mui/joy';
const PLOTLY_BASE_ID= 'plotly-plot';
const MASKING_DELAY= 400;
@@ -397,7 +398,7 @@ export class PlotlyWrapper extends Component {
return (
- {showMask &&
}
+ {showMask &&
}
);
}
diff --git a/src/firefly/js/core/ComponentCntlr.js b/src/firefly/js/core/ComponentCntlr.js
index bc16f2e2e..337ced0c0 100644
--- a/src/firefly/js/core/ComponentCntlr.js
+++ b/src/firefly/js/core/ComponentCntlr.js
@@ -3,7 +3,7 @@
*/
import {flux} from './ReduxFlux';
-import {get} from 'lodash';
+import {get, isNil} from 'lodash';
import update from 'immutability-helper';
import {REINIT_APP} from './AppDataCntlr.js';
@@ -168,6 +168,14 @@ const hideAllDialogsChange= function(state) {
const changeComponentState= function(state, action) {
const {componentId, componentState} = action.payload;
if (!componentId) {return state;}
+
+ if (isNil(componentState)) {
+ return update(state,
+ {
+ [COMPONENT_KEY]: {[componentId]: {$set: undefined}}
+ });
+ }
+
if (!state[COMPONENT_KEY][componentId]) {
state = update(state,
{
diff --git a/src/firefly/js/core/background/BackgroundCntlr.js b/src/firefly/js/core/background/BackgroundCntlr.js
index c934a87b3..e7b1aef08 100644
--- a/src/firefly/js/core/background/BackgroundCntlr.js
+++ b/src/firefly/js/core/background/BackgroundCntlr.js
@@ -203,7 +203,7 @@ function bgPackage(action) {
}
}
} else {
- showInfoPopup(jobInfo?.error);
+ jobInfo?.error && showInfoPopup(jobInfo.error);
}
};
doPackageRequest({dlRequest, searchRequest, selectInfo:selectionInfo, bgKey, onComplete});
diff --git a/src/firefly/js/core/background/BackgroundMonitor.css b/src/firefly/js/core/background/BackgroundMonitor.css
deleted file mode 100644
index 1feb99690..000000000
--- a/src/firefly/js/core/background/BackgroundMonitor.css
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt
- */
-
-
-.JobInfo__items--link {
- height: 16px;
- margin-left: 3px;
-}
-.JobInfo__items--link:hover {
- cursor: pointer;
-}
-
-
-.BgMaskPanel__msg {
- text-align: center;
- margin: 7px 5px;
- font-size: larger;
- font-style: italic;
-}
-
-
-.BgMaskPanel {
- position: relative;
- width: 100%;
- height: 100%;
- box-sizing: border-box;
- border: 1px solid rgba(0, 0, 0, 0.3);
- display: flex;
- justify-content: center;
-}
-
-.BgMaskPanel__content {
- margin-top: 95px;
- position: relative;
- color: white;
- display: flex;
- flex-direction: column;
-}
-
-.BgMaskPanel__actions {
- display: inline-flex;
- align-items: center;
- margin-top: 3px;
-}
\ No newline at end of file
diff --git a/src/firefly/js/core/background/BackgroundMonitor.jsx b/src/firefly/js/core/background/BackgroundMonitor.jsx
index e4a30ad99..4b739f7c5 100644
--- a/src/firefly/js/core/background/BackgroundMonitor.jsx
+++ b/src/firefly/js/core/background/BackgroundMonitor.jsx
@@ -29,7 +29,6 @@ import CANCEL from 'html/images/stop.gif';
import DOWNLOAED from 'html/images/blue_check-on_10x10.gif';
import FAILED from 'html/images/exclamation16x16.gif';
import INFO from 'html/images/info-icon.png';
-import './BackgroundMonitor.css';
import CompleteButton from 'firefly/ui/CompleteButton';
diff --git a/src/firefly/js/core/background/BgMaskPanel.jsx b/src/firefly/js/core/background/BgMaskPanel.jsx
index 7ef2042c4..b815d15d3 100644
--- a/src/firefly/js/core/background/BgMaskPanel.jsx
+++ b/src/firefly/js/core/background/BgMaskPanel.jsx
@@ -1,15 +1,14 @@
import React, {useEffect} from 'react';
-import PropTypes from 'prop-types';
-import {Button, Stack} from '@mui/joy';
-import shallowequal from 'shallowequal';
+import {bool, string, func, object, element} from 'prop-types';
+import {Button, LinearProgress, Skeleton, Stack, Typography} from '@mui/joy';
import {dispatchJobAdd, dispatchJobCancel} from './BackgroundCntlr.js';
import {dispatchComponentStateChange, getComponentState} from '../ComponentCntlr.js';
-import {useStoreConnector} from '../../ui/SimpleComponent.jsx';
+import {useStoreConnector, Slot} from '../../ui/SimpleComponent.jsx';
import {Logger} from '../../util/Logger.js';
import {showJobInfo} from './JobInfo.jsx';
import {getJobInfo} from './BackgroundUtil.js';
-import INFO from 'html/images/info-icon.png';
+import {InfoButton} from 'firefly/visualize/ui/Buttons.jsx';
const logger = Logger('BgMaskPanel');
@@ -23,16 +22,13 @@ const logger = Logger('BgMaskPanel');
*/
-export const BgMaskPanel = React.memo(({componentKey, onMaskComplete, style={}}) => {
-
- const {inProgress, jobInfo} = useStoreConnector((oldState={}) => {
- const {inProgress:oProg, jobInfo:oInfo} = oldState;
- const {inProgress=false, jobId} = getComponentState(componentKey);
- const jobInfo = getJobInfo(jobId);
- if (oProg === inProgress && shallowequal(oInfo, jobInfo)) return oldState;
- return {inProgress, jobInfo};
- });
+export const BgMaskPanel = React.memo(({componentKey, onMaskComplete, mask, showError= true, ...props}) => {
+ const inProgress = useStoreConnector(() => getComponentState(componentKey)?.inProgress || false);
+ const jobInfo = useStoreConnector(() => {
+ const {jobId} = getComponentState(componentKey);
+ return jobId && getJobInfo(jobId);
+ });
const sendToBg = () => {
if (jobInfo) {
dispatchComponentStateChange(componentKey, {inProgress:false});
@@ -46,16 +42,12 @@ export const BgMaskPanel = React.memo(({componentKey, onMaskComplete, style={}})
}
};
- const showInfo = () => {
- jobInfo && showJobInfo(jobInfo.jobId);
- };
-
const msg = jobInfo?.errorSummary?.message || jobInfo?.jobInfo?.progressDesc || 'Working...';
- const Options = () => ( (inProgress || true) &&
+ const Options = () => (
-
-
+
+
);
@@ -69,39 +61,42 @@ export const BgMaskPanel = React.memo(({componentKey, onMaskComplete, style={}})
logger.debug(inProgress ? 'show' : 'hide');
if (inProgress) {
return (
-
-
-
-
-
-
{msg}
-
-
-
-
-
-
+
+
+
);
- } else if (errorInJob) {
+ } else if (errorInJob && showError) {
return (
-
-
-
-
-
-
{jobInfo.phase}
-
-
-
{msg}
-
-
-
+
);
} else return null;
});
+function MaskP({msg, jobInfo, children, mask=
, ...props}) {
+ const showInfo = () => {
+ showJobInfo(jobInfo.jobId);
+ };
+
+ return (
+
+ {mask}
+
+
+ {msg}
+
+
+ {children}
+
+
+
+
+ );
+}
+
BgMaskPanel.propTypes = {
- componentKey: PropTypes.string.isRequired, // key used to identify this background job
- style: PropTypes.object, // used for overriding default styling
- onMaskComplete: PropTypes.func
+ componentKey: string.isRequired, // key used to identify this background job
+ style: object, // used for overriding default styling
+ onMaskComplete: func,
+ showError: bool,
+ mask: element
};
diff --git a/src/firefly/js/core/background/JobInfo.jsx b/src/firefly/js/core/background/JobInfo.jsx
index d7713accf..0baa8a44d 100644
--- a/src/firefly/js/core/background/JobInfo.jsx
+++ b/src/firefly/js/core/background/JobInfo.jsx
@@ -9,12 +9,17 @@ import {dispatchShowDialog} from '../ComponentCntlr.js';
import {HelpIcon} from '../../ui/HelpIcon.jsx';
import {CollapsibleItem, CollapsibleGroup} from 'firefly/ui/panel/CollapsiblePanel.jsx';
import {uwsJobInfo} from 'firefly/rpc/SearchServicesJson.js';
-import {Box, Button, Stack} from '@mui/joy';
+import {Box, Button, Skeleton, Stack} from '@mui/joy';
import {OverflowMarker} from 'firefly/tables/ui/TablePanel.jsx';
-const popupSx = {justifyContent: 'space-between', resize: 'both', overflow: 'auto',
- minHeight: 200, minWidth: 450};
+const popupSx = {
+ justifyContent: 'space-between',
+ resize: 'both',
+ overflow: 'auto',
+ minHeight: 200, minWidth: 450,
+ width: '45vh', height: '45wh'
+};
export function showJobInfo(jobId) {
const ID = 'show-job-info';
@@ -36,7 +41,7 @@ export async function showUwsJob({jobUrl, jobId}) {
const mask = (
-
+
);
diff --git a/src/firefly/js/tables/TableUtil.js b/src/firefly/js/tables/TableUtil.js
index ee84e266b..1ab0d8fe1 100644
--- a/src/firefly/js/tables/TableUtil.js
+++ b/src/firefly/js/tables/TableUtil.js
@@ -1121,38 +1121,39 @@ export function tableDetailsView(tbl_id, highlightedRow, details_tbl_id) {
* @memberof firefly.util.table
* @func calcColumnWidths
*/
-export function getColMaxValues(columns, dataAry,
- {
- maxAryWidth = Number.MAX_SAFE_INTEGER,
- maxColWidth = Number.MAX_SAFE_INTEGER,
- useWidth = true,
- }={}) {
- return columns.map( (cv, idx) => {
-
- const width = useWidth? cv.prefWidth || cv.width : 0;
- if (width) {
- return 'O'.repeat(width); // O is a good reference for average width of a character
- }
+export function getColMaxValues(columns, dataAry, opt) {
+ return columns.map( (cv, idx) => getColMaxVal(cv, idx, dataAry, opt));
+}
+
+export function getColMaxVal(col, columnIndex, dataAry,
+ {
+ maxAryWidth = Number.MAX_SAFE_INTEGER,
+ maxColWidth = Number.MAX_SAFE_INTEGER,
+ useWidth = true,
+ }={}) {
+ const width = useWidth? col.prefWidth || col.width : 0;
+ if (width) {
+ return 'O'.repeat(width); // O is a good reference for average width of a character
+ }
- let maxVal = '';
+ let maxVal = '';
- // the 4 headers
- [cv.label || cv.name, cv.units, getTypeLabel(cv), cv.nullString].forEach( (v) => {
- if (v?.length > maxVal.length) maxVal = v;
- });
+ // the 4 headers
+ [col.label || col.name, col.units, getTypeLabel(col), col.nullString].forEach( (v) => {
+ if (v?.length > maxVal.length) maxVal = v;
+ });
- // the data
- dataAry.forEach((row) => {
- const v = formatValue(columns[idx], row[idx]);
- if (v.length > maxVal.length) maxVal = v;
- });
+ // the data
+ dataAry.forEach((row) => {
+ const v = formatValue(col, row[columnIndex]);
+ if (v.length > maxVal.length) maxVal = v;
+ });
- // limits
- if (cv.arraySize && maxVal.length > maxAryWidth) maxVal = maxVal.substr(0, maxAryWidth);
- if (maxVal.length > maxColWidth) maxVal = maxVal.substr(0, maxColWidth);
+ // limits
+ if (col.arraySize && maxVal.length > maxAryWidth) maxVal = maxVal.substr(0, maxAryWidth);
+ if (maxVal.length > maxColWidth) maxVal = maxVal.substr(0, maxColWidth);
- return maxVal;
- });
+ return maxVal;
}
/**
@@ -1442,10 +1443,12 @@ export function hasAuxData(tbl_id) {
/**
* @param tbl_id ID of the table
+ * @param tableModel or, the tableModel itself.
* @return TBL_STATE of the table.
*/
-export function getTableState(tbl_id) {
- const {error, status, isFetching, totalRows, filters, sqlFilter} = getTblById(tbl_id) || {};
+export function getTableState(tbl_id, tableModel={}) {
+ const {error, status, isFetching, totalRows, request={}} = getTblById(tbl_id) || tableModel;
+ const {filters, sqlFilter} = request;
if (error) return TBL_STATE.ERROR;
if (isFetching) return TBL_STATE.LOADING;
@@ -1488,7 +1491,7 @@ export function parseError(error) {
const [_, type, cause] = error?.cause.match(/(.+?):(.+)/) || [];
return {message, type, cause};
} else {
- const [_, error, cause] = message.match(/(.+?):(.+)/) || []; // formatted error messages; 'error:cause'
+ const [_, error, cause] = message?.match(/(.+?):(.+)/) || []; // formatted error messages; 'error:cause'
return {message: error || message, cause};
}
}
diff --git a/src/firefly/js/tables/ui/AddOrUpdateColumn.jsx b/src/firefly/js/tables/ui/AddOrUpdateColumn.jsx
index e8d6f276e..c92d23368 100644
--- a/src/firefly/js/tables/ui/AddOrUpdateColumn.jsx
+++ b/src/firefly/js/tables/ui/AddOrUpdateColumn.jsx
@@ -4,7 +4,7 @@
import React, {useCallback, useState} from 'react';
import PropTypes from 'prop-types';
-import {Button, Stack, Link, Sheet, Typography, Box} from '@mui/joy';
+import {Button, Stack, Link, Sheet, Typography, Box, Skeleton} from '@mui/joy';
import {delay} from 'lodash';
import {UCDList} from '../../voAnalyzer/VoConst.js';
@@ -12,7 +12,7 @@ import {SqlTableFilter, code} from './FilterEditor.jsx';
import {addOrUpdateColumn, deleteColumn} from '../../rpc/SearchServicesJson.js';
import {getGroupFields, validateFieldGroup, getFieldVal} from '../../fieldGroup/FieldGroupUtils.js';
import {ValidationField} from '../../ui/ValidationField.jsx';
-import {getAllColumns, getColumn, getTblById} from '../TableUtil.js';
+import {getAllColumns, getColumn, getTableUiById, getTblById} from '../TableUtil.js';
import {showPopup, showInfoPopup, showYesNoPopup} from '../../ui/PopupUtil.jsx';
import {HelpIcon} from '../../ui/HelpIcon.jsx';
import {ToolbarButton} from '../../ui/ToolbarButton.jsx';
@@ -68,9 +68,8 @@ export const AddOrUpdateColumn = React.memo(({tbl_ui_id, tbl_id, hidePopup, edit
setIsWorking(true);
addOrUpdateColumn(request, params).then( () => {
hidePopup?.();
- dispatchTableUiUpdate( {tbl_ui_id, columns:[], columnWidths: undefined, scrollLeft:100000}); // reset columns and scroll to the right-most of the table so the added column is visible
+ reloadTable(tbl_ui_id, request, editColName, params.cname);
onChange?.();
- reloadTable(request,editColName, params.cname);
}).catch( (err) => {
showInfoPopup(parseError(err, params), 'Add Column Failed');
}).finally(() => setIsWorking(false));
@@ -83,9 +82,7 @@ export const AddOrUpdateColumn = React.memo(({tbl_ui_id, tbl_id, hidePopup, edit
const {request} = getTblById(tbl_id);
deleteColumn(request, editColName).then( () => {
hidePopup?.();
- dispatchTableUiUpdate( {tbl_ui_id, columns:[], columnWidths: undefined}); // reset columns and scroll to the right-most of the table so the added column is visible
- // dispatchTableUiUpdate()
- reloadTable(request,editColName);
+ reloadTable(tbl_ui_id, request, editColName);
onChange?.();
}).catch( (err) => showInfoPopup(parseError(err), 'Delete Column Failed'));
}
@@ -98,14 +95,14 @@ export const AddOrUpdateColumn = React.memo(({tbl_ui_id, tbl_id, hidePopup, edit
const DelBtn = (
);
return (
-
a':{width:12},
label:{width:80},
input:{width:265}
}}>
- {isWorking && }
+ {isWorking &&
}
c.name === 'ROW_IDX');
+ columns.splice(colIdx, 0, {});
+ columnWidths.splice(colIdx, 0, -1);
+ // for now, we always add to the end; we can keep all previous values intact
+ scrollLeft = 100000; // scroll to the right-most of the table so the added column is visible
+ } else {
+ // updating a column
+ const colIdx = columns.findIndex((c) => c.name === editColName);
+ if (del) {
+ columns.splice(colIdx, 1);
+ columnWidths.splice(colIdx, 1);
+ }
// if editColumn is in sort or filter, clear it.
+ const {sortInfo, filters, inclCols, sqlFilter} = request;
+
if (sortInfo) {
if (sortInfo.match(/[A-Z],(.+)/)?.[1]?.replaceAll('"','').split(',')?.includes(editColName)) {
Reflect.deleteProperty(request,'sortInfo');
@@ -166,6 +183,7 @@ function reloadTable(request, editColName, newColName) {
Reflect.deleteProperty(request,'sqlFilter');
}
}
+
// if editColumn is in the 'select' portion, remove it.
if (inclCols) {
const cols = inclCols.split(',');
@@ -174,7 +192,9 @@ function reloadTable(request, editColName, newColName) {
}
}
}
+
dispatchTableFetch(request);
+ dispatchTableUiUpdate( {tbl_ui_id, columns, columnWidths, scrollLeft}); // update columns and scroll
}
export const AddColumnBtn = ({tbl_ui_id, tbl_id}) => (
diff --git a/src/firefly/js/tables/ui/BasicTableView.jsx b/src/firefly/js/tables/ui/BasicTableView.jsx
index 9887a99a4..d48602360 100644
--- a/src/firefly/js/tables/ui/BasicTableView.jsx
+++ b/src/firefly/js/tables/ui/BasicTableView.jsx
@@ -4,22 +4,25 @@
import React, {useCallback, useEffect} from 'react';
import {Box, Typography} from '@mui/joy';
-import PropTypes, {func} from 'prop-types';
+import {arrayOf, array, bool, func, instanceOf, number, object, objectOf, shape, string} from 'prop-types';
import {Column, Table} from 'fixed-data-table-2';
import {wrapResizer} from '../../ui/SizeMeConfig.js';
import {get, set, isEmpty, isUndefined, omitBy, pick} from 'lodash';
-import {calcColumnWidths, getCellValue, getColMaxValues, getColumns, getProprietaryInfo, getTableState, getTableUiById, getTblById, hasRowAccess, isClientTable, tableTextView, TBL_STATE, uniqueTblUiId} from '../TableUtil.js';
+import {getCellValue, getColMaxVal, getColMaxValues, getColumns, getProprietaryInfo, getTableState, getTableUiById, getTblById, hasRowAccess, isClientTable, tableTextView, TBL_STATE, uniqueTblUiId} from '../TableUtil.js';
import {SelectInfo} from '../SelectInfo.js';
import {FilterInfo} from '../FilterInfo.js';
import {SortInfo} from '../SortInfo.js';
-import {CellWrapper, getPxWidth, HeaderCell, headerLevel, headerStyle, makeDefaultRenderer, SelectableCell, SelectableHeader} from './TableRenderer.js';
+import {CellWrapper, getPxWidth, HeaderCell, headerStyle, makeDefaultRenderer, SelectableCell, SelectableHeader} from './TableRenderer.js';
import {useStoreConnector} from '../../ui/SimpleComponent.jsx';
import {dispatchTableUiUpdate, TBL_UI_UPDATE} from '../TablesCntlr.js';
import {Logger} from '../../util/Logger.js';
import 'fixed-data-table-2/dist/fixed-data-table.css';
import './TablePanel.css';
+import {updateSet} from 'firefly/util/WebUtil.js';
+import {TableMask} from 'firefly/ui/panel/MaskPanel.jsx';
+import {TableErrorMsg} from 'firefly/tables/ui/TablePanel.jsx';
const logger = Logger('Tables').tag('BasicTable');
const noDataMsg = 'No Data Found';
@@ -86,8 +89,11 @@ const BasicTableViewInternal = React.memo((props) => {
if (isSingleColumnTable(columns) && (!columnWidths || columnWidths[0]!==calcWidth)) {
// set 1st (only visible) column's width to table's width minus scrollbar's width (15px)
changes.columnWidths = [calcWidth, ...Array(columns.length - 1).fill(0)];
+ } else if(!columnWidths) {
+ changes.columnWidths = columnWidthsInPixel(columns, data);
+ } else if (columnWidths.some?.((w) => w < 0)) { // at least one column needs width calc
+ changes.columnWidths = columnWidths.map((w, idx) => w >0 ? w : colWidthInPixel( getColMaxVal(columns[idx], idx,data), columns[idx]));
}
- else if(!columnWidths) changes.columnWidths = columnWidthsInPixel(columns, data);
}
if (adjScrollTop !== scrollTop) changes.scrollTop = adjScrollTop;
if (adjScrollLeft !== scrollLeft) changes.scrollLeft = adjScrollLeft;
@@ -104,11 +110,10 @@ const BasicTableViewInternal = React.memo((props) => {
const rowClassNameGetter = highlightedRowHandler || defHighlightedRowHandler(tbl_id, hlRowIdx, startIdx);
- const tstate = getTableState(tbl_id);
+ const tstate = getTableState(tbl_id, {error}); // tableModel is used when tbl_id is not defined.
logger.debug(`render.. state:[${tstate}] -- ${tbl_id}`);
-
- if (tstate === TBL_STATE.ERROR) return {error}
;
- if (tstate === TBL_STATE.LOADING || isEmpty(columnWidths)) return ;
+ if (tstate === TBL_STATE.ERROR) return ;
+ if (tstate === TBL_STATE.LOADING || isEmpty(columnWidths)) return ;
const content = () => {
if (textView) {
@@ -160,41 +165,41 @@ const BasicTableViewInternal = React.memo((props) => {
BasicTableViewInternal.propTypes = {
- tbl_ui_id: PropTypes.string,
- columns: PropTypes.arrayOf(PropTypes.object),
- data: PropTypes.arrayOf(PropTypes.array),
- hlRowIdx: PropTypes.number,
- selectInfoCls: PropTypes.instanceOf(SelectInfo),
- filterInfo: PropTypes.string,
- sortInfo: PropTypes.string,
- selectable: PropTypes.bool,
- showUnits: PropTypes.bool,
- showTypes: PropTypes.bool,
- showFilters: PropTypes.bool,
- showHeader: PropTypes.bool,
- textView: PropTypes.bool,
- rowHeight: PropTypes.number,
- rowHeightGetter: PropTypes.func, // params: rowData and columnWidths, returns height
- showMask: PropTypes.bool,
- currentPage: PropTypes.number,
- startIdx: PropTypes.number,
- error: PropTypes.string,
- size: PropTypes.object.isRequired,
- highlightedRowHandler: PropTypes.func,
- onRowDoubleClick: PropTypes.func,
- renderers: PropTypes.objectOf(
- PropTypes.shape({
- cellRenderer: PropTypes.func,
- headRenderer: PropTypes.func
+ tbl_ui_id: string,
+ columns: arrayOf(object),
+ data: arrayOf(array),
+ hlRowIdx: number,
+ selectInfoCls: instanceOf(SelectInfo),
+ filterInfo: string,
+ sortInfo: string,
+ selectable: bool,
+ showUnits: bool,
+ showTypes: bool,
+ showFilters: bool,
+ showHeader: bool,
+ textView: bool,
+ rowHeight: number,
+ rowHeightGetter: func, // params: rowData and columnWidths, returns height
+ showMask: bool,
+ currentPage: number,
+ startIdx: number,
+ error: string,
+ size: object.isRequired,
+ highlightedRowHandler: func,
+ onRowDoubleClick: func,
+ renderers: objectOf(
+ shape({
+ cellRenderer: func,
+ headRenderer: func
})
),
- callbacks: PropTypes.shape({
- onRowHighlight: PropTypes.func,
- onRowSelect: PropTypes.func,
- onSelectAll: PropTypes.func,
- onSort: PropTypes.func,
- onFilter: PropTypes.func,
- onGotoPage: PropTypes.func
+ callbacks: shape({
+ onRowHighlight: func,
+ onRowSelect: func,
+ onSelectAll: func,
+ onSort: func,
+ onFilter: func,
+ onGotoPage: func
})
};
@@ -226,11 +231,10 @@ function doScrollEnd(scrollLeft, scrollTop) {
}
function doColumnResize(newColumnWidth, columnKey) {
- const {columnWidths={}, tbl_ui_id} = this;
- dispatchTableUiUpdate({
- tbl_ui_id,
- columnWidths: Object.assign({}, columnWidths, {[columnKey]: newColumnWidth})
- });
+ const {columnWidths=[], tbl_ui_id} = this;
+ if(columnKey >= 0 && columnKey < columnWidths.length) {
+ dispatchTableUiUpdate({ tbl_ui_id, columnWidths: updateSet(columnWidths, columnKey, newColumnWidth)});
+ }
}
function doKeyDown(e) {
@@ -328,20 +332,21 @@ function correctScrollLeftIfNeeded(totalColWidths, scrollLeft, width, triggeredB
return scrollLeft;
}
-function columnWidthsInPixel(columns, data, minWidth=45) {
+function columnWidthsInPixel(columns, data, minWidth) {
const maxVals = getColMaxValues(columns, data, {maxColWidth: 100, maxAryWidth: 30});
+ return maxVals.map((text, idx) => colWidthInPixel(text, columns[idx]), minWidth);
+}
- const paddings = 8;
- return maxVals.map((text, idx) => {
- const header = columns[idx].label || columns[idx].name;
- const style = header === text ? headerStyle : {fontSize:12};
- text = text.replace(/[^a-zA-Z0-9]/g, 'O'); // some non-alphanum values can be very narrow. use 'O' in place of them.
- const pxNum = getPxWidth({text, ...style}) + paddings;
- return pxNum < minWidth ? minWidth : pxNum;
- });
+function colWidthInPixel(text, col, minWidth=45, paddings=8) {
+ const header = col.label || col.name;
+ const style = header === text ? headerStyle : {fontSize:12};
+ text = text.replace(/[^a-zA-Z0-9]/g, 'O'); // some non-alphanum values can be very narrow. use 'O' in place of them.
+ const pxNum = getPxWidth({text, ...style}) + paddings;
+ return pxNum < minWidth ? minWidth : pxNum;
}
+
function defHighlightedRowHandler(tbl_id, hlRowIdx, startIdx) {
const tableModel = getTblById(tbl_id);
diff --git a/src/firefly/js/tables/ui/TablePanel.jsx b/src/firefly/js/tables/ui/TablePanel.jsx
index 3dbd51d57..c7e844bc3 100644
--- a/src/firefly/js/tables/ui/TablePanel.jsx
+++ b/src/firefly/js/tables/ui/TablePanel.jsx
@@ -3,7 +3,7 @@
*/
import React, {useEffect} from 'react';
-import {Box, Stack, Typography, Sheet, Divider, ChipDelete, Tooltip, Skeleton, Button} from '@mui/joy';
+import {Box, Stack, Typography, Sheet, ChipDelete, Tooltip, Button} from '@mui/joy';
import PropTypes, {object, shape} from 'prop-types';
import {defer, truncate, get, set} from 'lodash';
import {getAppOptions, getSearchActions} from '../../core/AppDataCntlr.js';
@@ -33,6 +33,7 @@ import {AddColumnBtn} from './AddOrUpdateColumn.jsx';
import WarningIcon from '@mui/icons-material/WarningAmberRounded';
import {PropertySheetAsTable} from 'firefly/tables/ui/PropertySheet';
import {META} from '../TableRequestUtil.js';
+import {TableMask} from 'firefly/ui/panel/MaskPanel.jsx';
const logger = Logger('Tables').tag('TablePanel');
@@ -428,26 +429,28 @@ function NotReady({showTitle, tbl_id, title, removable, backgroundable, error})
dispatchTableFetch(JSON.parse(prevReq));
};
if (error) {
- const {message, type, cause} = parseError(error);
- return (
-
- {message}
- { cause && (
-
-
- Cause:
- {type && [{type}]}
-
- {cause}
-
- )}
- {prevReq && }
-
- );
+ return ;
} else {
- return ;
+ return ;
}
}
}
-
+export function TableErrorMsg({error, prevReq, reloadTable, ...props}) {
+ const {message, type, cause} = parseError(error);
+ return (
+
+ {message}
+ { cause && (
+
+
+ Cause:
+ {type && [{type}]}
+
+ {cause}
+
+ )}
+ {prevReq && }
+
+ );
+}
diff --git a/src/firefly/js/ui/DownloadDialog.jsx b/src/firefly/js/ui/DownloadDialog.jsx
index 3db66bad8..149f47848 100644
--- a/src/firefly/js/ui/DownloadDialog.jsx
+++ b/src/firefly/js/ui/DownloadDialog.jsx
@@ -190,18 +190,8 @@ export function DownloadOptionPanel ({groupKey, cutoutSize, help_id, children, s
// const showWarnings = hasProprietaryData(getTblById(tbl_id)); // it feature is not working correctly
- const maskStyle = {
- position: 'absolute',
- top:-26,
- bottom:-4,
- right:-4,
- left:-4,
- width:undefined,
- height:undefined,
- backgroundColor: 'rgba(0,0,0,0.2)'
- };
- const maskPanel = hideDownloadDialog()}/>;
+ const maskPanel = (hideDownloadDialog()}/>);
const saveAsProps = {
initialState: {
diff --git a/src/firefly/js/ui/FileUploadDropdown.jsx b/src/firefly/js/ui/FileUploadDropdown.jsx
index 7ff50f864..b9961d887 100644
--- a/src/firefly/js/ui/FileUploadDropdown.jsx
+++ b/src/firefly/js/ui/FileUploadDropdown.jsx
@@ -2,10 +2,9 @@
* License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt
*/
-import {Box} from '@mui/joy';
+import {Box, Skeleton} from '@mui/joy';
import React, {useState} from 'react';
import {FormPanel} from './FormPanel.jsx';
-import {dispatchHideDropDown} from '../core/LayoutCntlr.js';
import {FileUploadViewPanel, resultFail} from '../visualize/ui/FileUploadViewPanel.jsx';
import {getAppOptions} from 'firefly/api/ApiUtil.js';
import DialogRootContainer from 'firefly/ui/DialogRootContainer.jsx';
@@ -15,7 +14,6 @@ import {resultSuccess} from 'firefly/ui/FileUploadProcessor';
import {FieldGroup} from 'firefly/ui/FieldGroup';
import {DATA_LINK_TABLES, IMAGES, MOC_TABLES, REGIONS, SPECTRUM_TABLES, TABLES, UWS} from 'firefly/ui/FileUploadUtil';
-const maskWrapper= { position:'absolute', left:0, top:0, width:'100%', height:'100%' };
const panelKey = 'FileUploadAnalysis';
const defaultAcceptList = [
@@ -40,7 +38,7 @@ export const FileUploadDropdown= ({sx, onCancel, onSubmit=resultSuccess, keepSta
const [doMask, changeMasking]= useState(() => false);
const helpId = getAppOptions()?.uploadPanelHelpId ?? 'basics.searching';
return (
-
+
- {doMask && }
+ {doMask && } // zIndex:10 because '.file-drop-zone' raises plane to z-index:10.
);
};
diff --git a/src/firefly/js/ui/ThemeSetup.js b/src/firefly/js/ui/ThemeSetup.js
index 16f47fdfb..b4e871692 100644
--- a/src/firefly/js/ui/ThemeSetup.js
+++ b/src/firefly/js/ui/ThemeSetup.js
@@ -83,6 +83,11 @@ export function defaultTheme() {
defaultProps: {
size:'sm',
}
+ },
+ JoySkeleton: {
+ defaultProps: {
+ animation: 'wave',
+ }
}
}
});
diff --git a/src/firefly/js/ui/WorkspaceDropdown.jsx b/src/firefly/js/ui/WorkspaceDropdown.jsx
index 5a5b18fa1..319f9af8c 100644
--- a/src/firefly/js/ui/WorkspaceDropdown.jsx
+++ b/src/firefly/js/ui/WorkspaceDropdown.jsx
@@ -8,6 +8,7 @@ import PropTypes from 'prop-types';
import {FormPanel} from './FormPanel.jsx';
import {dispatchHideDropDown} from '../core/LayoutCntlr.js';
import {WorkspaceViewPanel, resultSuccess, resultFail} from '../visualize/ui/WorkspaceViewPanel.jsx';
+import {Skeleton, Stack} from '@mui/joy';
const dropdownName = 'WorkspaceDropDownCmd';
@@ -36,7 +37,7 @@ export class WorkspaceDropdown extends PureComponent {
render() {
return (
-
+
- {this.state.doMask && }
-
+ {this.state.doMask && }
+
);
}
}
diff --git a/src/firefly/js/ui/WorkspaceSelectPane.jsx b/src/firefly/js/ui/WorkspaceSelectPane.jsx
index eb82509d5..d0ce616f4 100644
--- a/src/firefly/js/ui/WorkspaceSelectPane.jsx
+++ b/src/firefly/js/ui/WorkspaceSelectPane.jsx
@@ -15,7 +15,7 @@ import {WorkspaceSave} from './WorkspaceViewer.jsx';
import {useStoreConnector} from './SimpleComponent.jsx';
import {dispatchWorkspaceUpdate, getWorkspaceErrorMsg} from '../visualize/WorkspaceCntlr.js';
import {getWorkspaceConfig} from '../visualize/WorkspaceCntlr.js';
-import {Stack, Typography, Box} from '@mui/joy';
+import {Stack, Typography, Box, Skeleton} from '@mui/joy';
export const LOCALFILE = 'isLocal';
export const WORKSPACE = 'isWs';
@@ -85,7 +85,7 @@ function ShowWorkspace({wsSelect}) {
const wsList = useStoreConnector(getWorkspaceList);
const isUpdating = useStoreConnector(isAccessWorkspace);
- const content = isUpdating ?
+ const content = isUpdating ?
: isEmpty(wsList) ? {'Workspace access error: ' + getWorkspaceErrorMsg()}
: ;
diff --git a/src/firefly/js/ui/WorkspaceViewer.jsx b/src/firefly/js/ui/WorkspaceViewer.jsx
index ac46b0849..93557013a 100644
--- a/src/firefly/js/ui/WorkspaceViewer.jsx
+++ b/src/firefly/js/ui/WorkspaceViewer.jsx
@@ -1,4 +1,4 @@
-import {Button, Stack} from '@mui/joy';
+import {Button, Skeleton, Stack} from '@mui/joy';
import React, {memo} from 'react';
import PropTypes from 'prop-types';
import {get, truncate} from 'lodash';
@@ -459,7 +459,7 @@ function showWorkspaceAsPopup({onComplete, value, fieldKey=workspaceUploadDef.fi
files={newList}
keepSelect={true}
initialState={{value, validator: isWsFolder(false)}}/>
- {showMask && }
+ {showMask && }
}>
diff --git a/src/firefly/js/ui/dynamic/DLGeneratedDropDown.js b/src/firefly/js/ui/dynamic/DLGeneratedDropDown.js
index 42afba4f1..adea36206 100644
--- a/src/firefly/js/ui/dynamic/DLGeneratedDropDown.js
+++ b/src/firefly/js/ui/dynamic/DLGeneratedDropDown.js
@@ -1,4 +1,4 @@
-import {Box, Link, Sheet, Stack, Typography} from '@mui/joy';
+import {Box, Link, Sheet, Skeleton, Stack, Typography} from '@mui/joy';
import {isArray, isEmpty} from 'lodash';
import {bool, func, object, shape, string} from 'prop-types';
import React, {useEffect, useState} from 'react';
@@ -451,7 +451,7 @@ function DLGeneratedTableSearch({currentTblId, qAna, groupKey, initArgs, sideBar
const NotLoaded= ({regHasUrl,regLoaded, url}) => (
(regHasUrl || !regLoaded) ?
- ( ) :
+ ( ) :
(
{`No collections to load from: ${url}`}
)
diff --git a/src/firefly/js/ui/panel/MaskPanel.jsx b/src/firefly/js/ui/panel/MaskPanel.jsx
new file mode 100644
index 000000000..984ac9d01
--- /dev/null
+++ b/src/firefly/js/ui/panel/MaskPanel.jsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import {Sheet, Skeleton, Stack} from '@mui/joy';
+
+export function TableMask({cols=5, withToolbar=true, ...props}) {
+ return (
+
+ {withToolbar && }
+
+ {[...Array(cols).keys()].map((value) => (
+
+ ))}
+
+
+ {[...Array(cols).keys()].map((value) => (
+
+ ))}
+
+
+ );
+}
+
+export function GridMask({rows=3, cols=3, ...props}) {
+ return (
+
+ {[...Array(rows).keys()].map((idx) => (
+
+ {[...Array(cols).keys()].map((idx) => (
+
+ ))}
+
+ ))}
+
+ );
+}
+
+export function FormMask({rows=10, sx, ...props}) {
+ return (
+
+
+ {[...Array(rows).keys()].map((value) => (
+
+ ))}
+
+
+ {[...Array(rows).keys()].map((value) => (
+
+ ))}
+
+
+ );
+}
+
diff --git a/src/firefly/js/ui/tap/ObjectIDSearch.jsx b/src/firefly/js/ui/tap/ObjectIDSearch.jsx
index d44328cf7..f8b0fe50f 100644
--- a/src/firefly/js/ui/tap/ObjectIDSearch.jsx
+++ b/src/firefly/js/ui/tap/ObjectIDSearch.jsx
@@ -1,4 +1,4 @@
-import {Box, Chip, Stack, Typography} from '@mui/joy';
+import {Box, Chip, Skeleton, Stack, Typography} from '@mui/joy';
import React, {useContext, useEffect, useState} from 'react';
import {FieldGroupCtx} from 'firefly/ui/FieldGroup';
import {ConstraintContext} from 'firefly/ui/tap/Constraints';
@@ -128,7 +128,9 @@ export function ObjectIDSearch({cols, capabilities, tableName, columnsModel}) {
return (
-
+
+ {working && }
+
Performs an exact match on the ID(s) provided, not a spatial search in the neighborhood of the designated objects.
{!canUpload && This search uses "Select IN" style SQL as this service does not support uploads.}
}
- {working && }
diff --git a/src/firefly/js/ui/tap/TapViewType.jsx b/src/firefly/js/ui/tap/TapViewType.jsx
index 77f57972f..81dbd3f3d 100644
--- a/src/firefly/js/ui/tap/TapViewType.jsx
+++ b/src/firefly/js/ui/tap/TapViewType.jsx
@@ -1,4 +1,4 @@
-import {Box, Button, Divider, Sheet, Stack, Tooltip, Typography} from '@mui/joy';
+import {Box, Button, Divider, Sheet, Skeleton, Stack, Tooltip, Typography} from '@mui/joy';
import {truncate} from 'lodash';
import {bool, string, func, object, shape} from 'prop-types';
import React, {Fragment, useContext, useEffect, useRef, useState} from 'react';
@@ -25,6 +25,7 @@ import {
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded';
import './TableSelectViewPanel.css';
+import {TableMask} from 'firefly/ui/panel/MaskPanel.jsx';
const SCHEMA_TIP= 'Select a table collection (TAP ‘schema’); type to search the schema names and descriptions.';
@@ -111,7 +112,7 @@ function AdqlUI({serviceUrl, serviceLabel, servicesShowing, setServicesShowing,
- :