Skip to content

Commit

Permalink
feature/new-plot-types (#228)
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinJJackson authored Jul 29, 2024
1 parent 4c5d51d commit 4e00633
Show file tree
Hide file tree
Showing 31 changed files with 1,401 additions and 624 deletions.
15 changes: 8 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hhd-ui",
"version": "0.15.7",
"version": "0.16.0",
"private": true,
"dependencies": {
"@ag-grid-community/client-side-row-model": "^30.0.3",
Expand All @@ -24,7 +24,7 @@
"date-fns": "^2.30.0",
"graceful-fs": "^4.2.11",
"internal-nav-helper": "^3.1.0",
"keycloak-js": "^25.0.0",
"keycloak-js": "^25.0.2",
"lodash.debounce": "^4.0.8",
"lodash.isequal": "^4.5.0",
"luxon": "^3.3.0",
Expand Down
41 changes: 38 additions & 3 deletions src/app-bundles/batch-plot-configurations-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ export default createRestBundle({
name: 'batchPlotConfigurations',
uid: 'id',
persist: false,
getTemplate: '/projects/:projectId/plot_configurations',
putTemplate: '/projects/:projectId/plot_configurations/{:item.id}',
getTemplate: '/projects/:projectId/plot_configs',
putTemplate: '/projects/:projectId/plot_configs/{:item.id}',
// @TODO: Remove the `postTemplate`
postTemplate: '/projects/:projectId/plot_configurations',
deleteTemplate: '/projects/:projectId/plot_configurations/{:item.id}',
deleteTemplate: '/projects/:projectId/plot_configs/{:item.id}',
fetchActions: ['URL_UPDATED', 'PROJECTS_FETCH_FINISHED'],
forceFetchActions: ['BATCHPLOTCONFIGURATIONS_SAVE_FINISHED'],
urlParamSelectors: ['selectProjectsIdByRoute'],
Expand All @@ -29,6 +30,40 @@ export default createRestBundle({
store.doBatchPlotMapAddData();
},

/**
* Save plot plot config settings. note: formData payloads differ based on plotType.
*
* @param {string} plotType one of ['scatter-line', 'profile', 'contour', 'bullseye']
* @param {string} id Batch Plot Config Id
* @param {object} formData api-defined trace structure for related plotType
* @returns
*/
doSaveBatchPlotConfiguration: (plotType, id = null, formData = {}) => ({ dispatch, store, apiPost, apiPut }) => {
const uriMap = {
'scatter-line': 'scatter_line_plots',
'profile': 'profile_plots',
'contour': 'contour_plots',
'bullseye': 'bullseye_plots',
};
const method = !id ? apiPost : apiPut;
const projectId = store.selectProjectsIdByRoute()?.projectId;
const uri = `/projects/${projectId}/plot_configs/${uriMap[plotType]}${!id ? '' : `/${id}`}`;

const finalFormData = {
...formData,
date_range: '1 year',
}

method(uri, finalFormData, (err, _body) => {
if (err) {
dispatch({ type: 'BATCH_PLOT_CONFIGURATION_SAVE_ERROR', payload: err });
} else {
dispatch({ type: 'BATCH_PLOT_CONFIGURATION_SAVED' });
store.doBatchPlotConfigurationsFetch();
}
});
},

selectBatchPlotConfigurationsRaw: (state) => state.batchPlotConfigurations,
selectBatchPlotConfigurationsActiveId: (state) =>
state.batchPlotConfigurations._activeBatchPlotConfigurationId,
Expand Down
4 changes: 2 additions & 2 deletions src/app-bundles/time-series-measurements-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ export default createRestBundle({
dispatch({ type: 'TIMESERIES_FETCH_BY_ID_START', payload: {} });
const [after, before] = dateRange;

const isoAfter = after ? after?.toISOString() : afterDate;
const isoBefore = before ? before?.toISOString() : beforeDate;
const isoAfter = after ? new Date(after)?.toISOString() : afterDate;
const isoBefore = before ? new Date(before)?.toISOString() : beforeDate;

const url = `/timeseries/${timeseriesId}/measurements?after=${isoAfter}&before=${isoBefore}&threshold=${threshold}`;
const flags = store['selectTimeseriesMeasurementsFlags']();
Expand Down
2 changes: 1 addition & 1 deletion src/app-bundles/upload-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ const uploadBundle = {
: setAllTo[1];
} else {
// If field not mapped, set to null; if required field, push error
const data = row[sourceKey] || fieldMap[key];
const data = row[sourceKey];
if (!data) {
parsedRow[key] = null;
if (config.required) parsedRow.errors.push(key);
Expand Down
2 changes: 2 additions & 0 deletions src/app-components/chart/minify-plotly.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as Bar from 'plotly.js/lib/bar';
import * as Pie from 'plotly.js/lib/pie';
import * as Surface from 'plotly.js/lib/surface';
import * as Scatter3D from 'plotly.js/lib/scatter3d';
import * as Contour from 'plotly.js/lib/contour';

Plotly.register([
/*
Expand All @@ -11,6 +12,7 @@ Plotly.register([
List of available imports can be found here `node_modules/plotly.js/lib/index.js`
*/
Bar,
Contour,
Pie,
Surface,
Scatter3D,
Expand Down
9 changes: 9 additions & 0 deletions src/app-components/hero/hero.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ const Hero = () => (
>
IPM SubCOP
</a>
<a
className='mt-2 d-block pointer'
title='Contact MIDAS Support'
href='mailto:[email protected]'
target='_blank'
rel='noreferrer'
>
Contact Support
</a>
</div>
</div>
);
Expand Down
120 changes: 67 additions & 53 deletions src/app-pages/project/batch-plotting/batch-plotting.jsx
Original file line number Diff line number Diff line change
@@ -1,70 +1,81 @@
import React from 'react';
import React, { useState } from 'react';
import { connect } from 'redux-bundler-react';
import { Engineering } from '@mui/icons-material';
import { toast } from 'react-toastify';
import { Link } from '@mui/material';

import BatchPlotChart from './tab-content/batch-plot-chart';
import BullseyePlot from './chart-content/bullseye-plot.jsx';
import Card from '../../../app-components/card';
import ContourPlot from './chart-content/contour-plot.jsx';
import DataConfiguration from './components/data-configuration';
import DepthChart from './tab-content/depth-chart';
import Map from '../../../app-components/classMap';
import TabContainer from '../../../app-components/tab/tabContainer';
import ProfilePlot from './chart-content/profile-plot.jsx';
import ScatterLinePlot from './chart-content/scatter-line-plot.jsx';
import { downloadFinalReport, useGetReportStatus, useInitializeReportDownload } from '../../../app-services/collections/report-configuration-download.ts';
import { tUpdateSuccess } from '../../../common/helpers/toast-helpers';
import { titlize } from '../../../common/helpers/utils.js';

import './batch-plotting.scss';

const batchPlotContainsInclinometers = (activeId, items, timeseries, instruments, domains) => {
const ret = {
containsInclinometers: false,
inclinometerTimeseriesIds: [],
};
if (!Object.keys(items).length || !activeId) return ret;
const config = items[activeId];
const { timeseries_id } = config?.display?.traces?.map(el => el.timeseries_id) || {};

if (!timeseries_id) return ret;

const { id: inclinometerTypeId } = domains['instrument_type'].find(el => el.value === 'Inclinometer');

timeseries_id.forEach(id => {
const { instrument_id } = timeseries.find(ts => ts.id === id) || {};
const { type_id } = instruments.find(i => i.id === instrument_id) || {};

if (type_id === inclinometerTypeId) {
ret.containsInclinometers = true;
ret.inclinometerTimeseriesIds = [...ret.inclinometerTimeseriesIds, id];
}
});

return ret;
};

const BatchPlotting = connect(
'doMapsInitialize',
'doMapsShutdown',
'selectMapsObject',
'selectHashQuery',
'selectProjectsByRoute',
'selectBatchPlotConfigurationsActiveId',
'selectBatchPlotConfigurationsItemsObject',
'selectInstrumentTimeseriesItems',
'selectInstrumentsItems',
'selectDomainsItemsByGroup',
'selectProjectReportConfigurations',
({
doMapsInitialize,
doMapsShutdown,
mapsObject,
hashQuery,
projectsByRoute: project,
batchPlotConfigurationsActiveId: batchPlotId,
batchPlotConfigurationsItemsObject: batchPlotItems,
instrumentTimeseriesItems: timeseries,
instrumentsItems: instruments,
domainsItemsByGroup: domains,
projectReportConfigurations: reportConfigs,
}) => {
const crossSectionReady = import.meta.env.VITE_CROSS_SECTION === 'true';
const userConfigId = hashQuery ? hashQuery['c'] : '';
const activeConfig = batchPlotItems[batchPlotId];
const { plot_type } = activeConfig || {};

const [toastId, setToastId] = useState(undefined);

const {
containsInclinometers,
inclinometerTimeseriesIds,
} = batchPlotContainsInclinometers(batchPlotId, batchPlotItems, timeseries, instruments, domains);
const { id: projectId } = project;
const { data: jobDetails, mutate: initReportJobMutator } = useInitializeReportDownload(projectId);
const { report_config_id: reportConfigId, id: jobId } = jobDetails || {};

const { data: currentJob } = useGetReportStatus({ projectId, reportConfigId, jobId }, {
enabled: !!((projectId && reportConfigId && jobId) && (['INIT', 'IN_PROGRESS'].includes(jobDetails?.status))),
refetchInterval: 3000,
});
const { file_key, progress } = currentJob || {};

if (file_key && progress === 100) {
tUpdateSuccess(
toastId,
'Your file is ready, click this message to open!',
{
autoClose: false,
onClose: () => {
downloadFinalReport({ projectId, reportConfigId, jobId });
}
}
);
}

const beginDownloadReportJob = id => {
const tId = toast.loading('Getting your report ready for download. This may take a minute...');
setToastId(tId);
initReportJobMutator(id);
};

const containedInReports = reportConfigs?.filter(cfg => cfg.plot_configs.some(el => el.id === batchPlotId)) || [];

return (
<>
Expand All @@ -79,12 +90,20 @@ const BatchPlotting = connect(
<Card.Body>
This Batch Plot Configuration is a part of the following reports. Click on the report name to download the report or click on the&nbsp;
<b>Remove</b> Button to remove the plot configuration from the correlated Report Configuration.
<hr />
{containedInReports.length ? containedInReports.map(cfg => (
<Link
key={cfg.id}
component='button'
onClick={() => beginDownloadReportJob(cfg.id)}
>
{cfg.name}
</Link>
)) : <i>No Reports</i>}
</Card.Body>
</Card>
<div className='row mt-4'>
<div
className={`${crossSectionReady ? 'col col-sm-5' : 'col-sm-12'}`}
>
<div className={`${crossSectionReady ? 'col col-sm-5' : 'col-sm-12'}`}>
<Card style={{ minHeight: '400px' }}>
<Card.Body>
<Map
Expand All @@ -110,19 +129,14 @@ const BatchPlotting = connect(
</div>
)}
</div>
<Card className='w-100 my-4 p-3'>
<TabContainer
tabs={[
{
title: 'Batch Plot Chart',
content: <BatchPlotChart />,
},
containsInclinometers && {
title: 'Depth Based Plot',
content: <DepthChart inclinometerTimeseriesIds={inclinometerTimeseriesIds} />
},
].filter(e => e)}
/>
<Card className='w-100 my-4'>
<Card.Header text={`${plot_type?.split('-').map(s => titlize(s)).join('-')} Plot`} />
<Card.Body>
{plot_type === 'scatter-line' && <ScatterLinePlot plotConfig={activeConfig} />}
{plot_type === 'profile' && <ProfilePlot plotConfig={activeConfig} />}
{plot_type === 'contour' && <ContourPlot plotConfig={activeConfig} />}
{plot_type === 'bullseye' && <BullseyePlot plotConfig={activeConfig} />}
</Card.Body>
</Card>
</>
)}
Expand Down
Loading

0 comments on commit 4e00633

Please sign in to comment.