Skip to content

Commit

Permalink
feature/multiple-equivalency-tables (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinJJackson authored Dec 13, 2023
1 parent 39f8360 commit 3c6d593
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 75 deletions.
4 changes: 2 additions & 2 deletions src/app-bundles/data-logger-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ export default {
});
},

doFetchDataLoggerPreview: ({ dataLoggerId }) => ({ dispatch, apiGet }) => {
const uri = `/datalogger/${dataLoggerId}/preview`;
doFetchDataLoggerPreview: ({ dataLoggerId, tableId }) => ({ dispatch, apiGet }) => {
const uri = `/datalogger/${dataLoggerId}/tables/${tableId}/preview`;

apiGet(uri, (err, body) => {
if (err) {
Expand Down
44 changes: 34 additions & 10 deletions src/app-bundles/data-logger-equivalency-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export default {
selectDataLoggerEquivalencyRaw: state => state.dataLoggerEquivalency,
selectDataLoggerEquivalencyTable: state => state.dataLoggerEquivalency.table,

doFetchDataLoggerEquivalency: ({ dataLoggerId }) => ({ dispatch, apiGet }) => {
const uri = `/datalogger/${dataLoggerId}/equivalency_table`;
doFetchDataLoggerEquivalency: ({ dataLoggerId, tableId }) => ({ dispatch, apiGet }) => {
const uri = `/datalogger/${dataLoggerId}/tables/${tableId}/equivalency_table`;

apiGet(uri, (err, body) => {
if (err) {
Expand All @@ -39,9 +39,31 @@ export default {
});
},

doCreateDataLoggerEquivalency: ({ dataLoggerId, newRows = [], unusedRows = [], isDeleteChecked = false }) => ({ store, apiPost }) => {
doCreateEquivalencyByTableName: ({ dataLoggerId, tableName, newRows }) => ({ store, apiPost }) => {
const uri = `/datalogger/${dataLoggerId}/equivalency_table`;

const payload = {
datalogger_id: dataLoggerId,
datalogger_table_name: tableName,
rows: newRows.map(row => ({
field_name: row,
display_name: row,
})),
};

apiPost(uri, payload, (err, _body) => {
if (err) {
// eslint-disable-next-line no-console
console.log('todo', err);
} else {
store.doFetchDataLoggersByProjectId();
}
});
},

doCreateDataLoggerEquivalency: ({ dataLoggerId, tableId, newRows = [], unusedRows = [], isDeleteChecked = false }) => ({ store, apiPost }) => {
const uri = `/datalogger/${dataLoggerId}/tables/${tableId}/equivalency_table`;

if (isDeleteChecked) {
unusedRows.forEach(el => {
const { id } = el;
Expand All @@ -68,12 +90,13 @@ export default {
},

doUpdateSingleDataLoggerEquivalency: (data) => ({ store, apiPut }) => {
const { dataLoggerId, id, fieldName, displayName, instrumentId, timeseriesId } = data;
const uri = `/datalogger/${dataLoggerId}/equivalency_table`;
const { dataLoggerId, tableId, id, fieldName, displayName, instrumentId, timeseriesId } = data;
const uri = `/datalogger/${dataLoggerId}/tables/${tableId}/equivalency_table`;
// const toastId = toast.loading('Updating Field Mapping...');

const payload = {
datalogger_id: dataLoggerId,
datalogger_table_id: tableId,
rows: [
{
id,
Expand All @@ -98,11 +121,12 @@ export default {
},

// For use in auto-assigning only.
doUpdateMultipleDataLoggerEquivalency: (dataLoggerId, rows, toastId) => ({ store, apiPut }) => {
const uri = `/datalogger/${dataLoggerId}/equivalency_table`;
doUpdateMultipleDataLoggerEquivalency: (dataLoggerId, tableId, rows, toastId) => ({ store, apiPut }) => {
const uri = `/datalogger/${dataLoggerId}/tables/${tableId}/equivalency_table`;

const payload = {
datalogger_id: dataLoggerId,
datalogger_table_id: tableId,
rows,
};

Expand All @@ -113,13 +137,13 @@ export default {
tUpdateError(toastId, 'Failed to assign timeseries to field names. Please try again later.');
} else {
tUpdateSuccess(toastId, 'Successfully assigned timeseries to field names!');
store.doFetchDataLoggerEquivalency({ dataLoggerId });
store.doFetchDataLoggerEquivalency({ dataLoggerId, tableId });
}
});
},

doDeleteDataLoggerEquivalencyRow: ({ dataLoggerId, id, refreshData = true }) => ({ store, apiDelete }) => {
const uri = `/datalogger/${dataLoggerId}/equivalency_table/row?id=${id}`;
doDeleteDataLoggerEquivalencyRow: ({ dataLoggerId, tableId, id, refreshData = true }) => ({ store, apiDelete }) => {
const uri = `/datalogger/${dataLoggerId}/tables/${tableId}/equivalency_table/row?id=${id}`;

apiDelete(uri, (err, _body) => {
if (err) {
Expand Down
4 changes: 2 additions & 2 deletions src/app-bundles/time-series-bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default createRestBundle({
}
},
addons: {
doSaveFieldNamesToTimeseries: (newObject, instrumentId, dataLoggerId) => ({ dispatch, store, apiPost }) => {
doSaveFieldNamesToTimeseries: (newObject, instrumentId, dataLoggerId, tableId) => ({ dispatch, store, apiPost }) => {
dispatch({ type: 'ASSIGN_FIELD_NAMES_TO_TIMESERIES_START' });
const toastId = tLoading('Creating new timeseries...');
const { projectId } = store.selectProjectsIdByRoute();
Expand Down Expand Up @@ -71,7 +71,7 @@ export default createRestBundle({
};
}));

store.doUpdateMultipleDataLoggerEquivalency(dataLoggerId, rows, toastId);
store.doUpdateMultipleDataLoggerEquivalency(dataLoggerId, tableId, rows, toastId);
}
});

Expand Down
47 changes: 26 additions & 21 deletions src/app-pages/profile/userProfile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import TabContainer from '../../app-components/tab';

import './userProfile.css';

const urlify = str => str.toLowerCase().split(' ').join('-');
const urlify = str => str?.toLowerCase().split(' ').join('-');

const buildProjectContent = (projects = []) => {
if (!projects.length) return <p>No Projects!</p>;
Expand All @@ -24,27 +24,32 @@ const buildAlertContent = (alerts = [], onClick = () => {}) => {

return (
<>
{alerts.map((alert, i) => {
const { project_name, instrument_name, name, body, read, create_date } = alert;
const url = `/${urlify(project_name)}/instruments/${urlify(instrument_name)}`;
const timeAgo = formatDistance(new Date(create_date), Date.now());
{alerts.map(alert => {
const { project_name, instruments, name, body, read, create_date } = alert;

return (
<div
key={i}
onClick={() => onClick(url)}
className={`alert-container${read ? '' : ' unread'} pointer`}
title={`Go To ${instrument_name}`}
>
<span className={`list-group-item flex-column align-items-start${read && ' list-group-item-action'}`}>
<div className='d-flex w-100 justify-content-between'>
<h5 className='mb-3'>{name} - {instrument_name}</h5>
<small>{timeAgo}</small>
</div>
<p className='mb-1'>{body}</p>
</span>
</div>
);
return instruments.map(instrument => {
const { instrument_name, instrument_id } = instrument;

const url = `/${urlify(project_name)}/instruments/${urlify(instrument_name)}`;
const timeAgo = formatDistance(new Date(create_date), Date.now());

return (
<div
key={instrument_id}
onClick={() => onClick(url)}
className={`alert-container${read ? '' : ' unread'} pointer`}
title={`Go To ${instrument_name}`}
>
<span className={`list-group-item flex-column align-items-start${read && ' list-group-item-action'}`}>
<div className='d-flex w-100 justify-content-between'>
<h5 className='mb-3'>{name} - {instrument_name}</h5>
<small>{timeAgo}</small>
</div>
<p className='mb-1'>{body}</p>
</span>
</div>
);
});
})}
</>
);
Expand Down
14 changes: 13 additions & 1 deletion src/app-pages/project/data-loggers/dataLoggerDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@ const dateDisplay = date => {
return isoDate.toLocaleString(DateTime.DATETIME_MED);
};

const checkTableLength = (tables = []) => {
if (!Array.isArray(tables) || !tables?.length) return 0;

const validTableArray = tables.map(t => Object.keys(t).length).filter(el => el);

return validTableArray.length;
};

const DataLoggerDetails = ({ dataLogger }) => {
const { name, sn, model, creator_username, create_date, updater_username, update_date, errors } = dataLogger;
const { name, sn, model, creator_username, create_date, updater_username, update_date, errors, tables } = dataLogger;

return (
<Card className='mt-3'>
Expand All @@ -27,6 +35,10 @@ const DataLoggerDetails = ({ dataLogger }) => {
<b>Model: </b>
{model}
</div>
<div className='col-3'>
<b># of Tables: </b>
{checkTableLength(tables)}
</div>
</div>
<div className='row mt-2'>
<i className='col-12'>
Expand Down
51 changes: 43 additions & 8 deletions src/app-pages/project/data-loggers/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import DataLoggerModal from './modals/dataLoggerModal';
import DeleteDataLoggerModal from './modals/deleteDataLoggerModal';
import IncomingRawDataTable from './tables/incomingRawDataTable';
import Toa5Modal from './modals/toa5Modal';
import HelperTooltip from '../../../app-components/helper-tooltip';

const generateDataLoggerOptions = (dataLoggers = []) => (
dataLoggers.map(logger => ({
Expand All @@ -21,6 +22,13 @@ const generateDataLoggerOptions = (dataLoggers = []) => (
}))
);

const generateEquivalencyOptions = (tables = []) => (
tables.map(t => ({
label: t?.table_name || <i>unnamed table</i>,
value: t?.id,
}))
);

const DataLoggers = connect(
'doModalOpen',
'doFetchDataLoggersByProjectId',
Expand All @@ -37,18 +45,20 @@ const DataLoggers = connect(
const queryParamId = hashQuery?.id;

const [selectedDataLogger, setSelectedDataLogger] = useState('');
const [selectedEquivalencyTable, setSelectedEquivalencyTable] = useState('');
const [dataLoggerOptions, setDataLoggerOptions] = useState(generateDataLoggerOptions(dataLoggers));
const dataLoggerInfo = dataLoggers?.find(el => el?.id === selectedDataLogger?.value);
const { tables = [] } = dataLoggerInfo || {};

useEffect(() => {
doFetchDataLoggersByProjectId();
}, [doFetchDataLoggersByProjectId]);

useEffect(() => {
if (selectedDataLogger) {
doFetchDataLoggerEquivalency({ dataLoggerId: selectedDataLogger?.value });
if (selectedDataLogger && selectedEquivalencyTable) {
doFetchDataLoggerEquivalency({ dataLoggerId: selectedDataLogger?.value, tableId: selectedEquivalencyTable?.value });
}
}, [selectedDataLogger, doFetchDataLoggerEquivalency]);
}, [selectedDataLogger, selectedEquivalencyTable, doFetchDataLoggerEquivalency]);

useDeepCompareEffect(() => {
setDataLoggerOptions(generateDataLoggerOptions(dataLoggers));
Expand All @@ -67,7 +77,10 @@ const DataLoggers = connect(
className='d-inline-block w-50'
placeholder='Select a Data Logger...'
options={dataLoggerOptions}
onChange={val => setSelectedDataLogger(val)}
onChange={val => {
setSelectedDataLogger(val);
setSelectedEquivalencyTable('');
}}
value={selectedDataLogger}
/>
) : <span>No Data Loggers for this project. Add one using the <i>Add New Data Logger</i> button to the right.</span>}
Expand All @@ -81,7 +94,7 @@ const DataLoggers = connect(
className='mr-2'
title='Upload TOA5 File'
icon={<UploadOutlined fontSize='inherit' />}
handleClick={() => doModalOpen(Toa5Modal, { dataLoggerInfo }, 'lg')}
handleClick={() => doModalOpen(Toa5Modal, { dataLoggerInfo, tableId: selectedEquivalencyTable?.value }, 'lg')}
/>
<Button
isOutline
Expand Down Expand Up @@ -118,7 +131,7 @@ const DataLoggers = connect(
className='mr-2'
icon={<Delete fontSize='inherit' />}
title='Delete Data Logger'
handleClick={() => doModalOpen(DeleteDataLoggerModal, { dataLoggerInfo, callback: () => setSelectedDataLogger(null) })}
handleClick={() => doModalOpen(DeleteDataLoggerModal, { dataLoggerInfo, tableId: selectedEquivalencyTable?.value, callback: () => setSelectedDataLogger(null) })}
/>
</>
) : null}
Expand All @@ -135,8 +148,30 @@ const DataLoggers = connect(
{selectedDataLogger ? (
<>
<DataLoggerDetails dataLogger={dataLoggerInfo} />
<IncomingRawDataTable dataLogger={dataLoggerInfo} />
<DataLoggerMappingTable dataLogger={dataLoggerInfo} />
<Card className='mt-3'>
<Card.Body>
<Select
className='d-inline-block w-50'
placeholder='Select an Equivalency Table...'
options={generateEquivalencyOptions(tables)}
onChange={val => setSelectedEquivalencyTable(val)}
value={selectedEquivalencyTable}
/>
<HelperTooltip
id='unnamed-table-helper'
content={<span>
A table with no name, labeled "unnamed table" in the select box, will be automatically named <br/>
upon the next data upload through the telemetry API.
</span>}
/>
{selectedEquivalencyTable ? (
<>
<IncomingRawDataTable dataLogger={dataLoggerInfo} tableId={selectedEquivalencyTable?.value} />
<DataLoggerMappingTable dataLogger={dataLoggerInfo} tableId={selectedEquivalencyTable?.value} />
</>
) : null}
</Card.Body>
</Card>
</>
) : null}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const AddMappingRowsModal = connect(
dataLoggerEquivalencyTable: equivalencyTable,
fieldNames = [],
dataLoggerId,
tableId,
}) => {
const { rows = [] } = equivalencyTable;
const newFieldNames = fieldNames.map(field => field.fieldName);
Expand Down Expand Up @@ -92,7 +93,7 @@ const AddMappingRowsModal = connect(
showCancelButton
saveText='Update Table'
showSaveButton={!noChanges}
onSave={() => doCreateDataLoggerEquivalency({ dataLoggerId, newRows, unusedRows, isDeleteChecked })}
onSave={() => doCreateDataLoggerEquivalency({ dataLoggerId, tableId, newRows, unusedRows, isDeleteChecked })}
/>
</Modal.ModalContent>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,21 @@ const AssignTimeseriesModal = connect(
instrumentTimeseriesByInstrumentId: timeseries,
instrumentsItems,
equivalencyTable,
tableId,
}) => {
const [selectedInstrument, setSelectedInstrument] = useState(null);
const [overwriteExisting, setOverwriteExisting] = useState(false);
const [updatingObject, setUpdatingObject] = useState({ newTs: [], existingTs: [] });
const { datalogger_id, rows } = equivalencyTable;

const saveTimeseriesToInstrument = () => doSaveFieldNamesToTimeseries(updatingObject, selectedInstrument, datalogger_id);
const saveTimeseriesToInstrument = () => doSaveFieldNamesToTimeseries(updatingObject, selectedInstrument, datalogger_id, tableId);

useEffect(() => {
if (selectedInstrument) {
const newTs = [];
const existingTs = [];

rows.forEach(row => {
rows?.forEach(row => {
if (overwriteExisting || !row.timeseries_id) {
const found = timeseries[selectedInstrument]?.find(el => el.name === row.field_name);
if (found) existingTs.push({
Expand Down
17 changes: 1 addition & 16 deletions src/app-pages/project/data-loggers/modals/dataLoggerModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const DataLoggerModal = connect(
const [sn, setSN] = useState(initSn);
const [name, setName] = useState(initName);
const [modelId, setModelId] = useState(initModelId);
const [isSaaIpi, setIsSaaIpi] = useState(false);

const saveDataLoggerDetails = () => {
if (isEdit) {
Expand All @@ -43,9 +42,7 @@ const DataLoggerModal = connect(

const isSaveDisabled = () => {
if (!sn || !name || !modelId) return true;

if (!isSaaIpi) return false;
else return true;
else return false;
};

return (
Expand Down Expand Up @@ -82,18 +79,6 @@ const DataLoggerModal = connect(
domain='datalogger_model'
/>
</div>
{modelId ? (
<>
<div className='form-group'>
<input
type='checkbox'
checked={isSaaIpi}
onChange={() => setIsSaaIpi(prev => !prev)}
/>
&nbsp;- Data Logger is Used for Inclinometer Data (SAA or IPI)
</div>
</>
) : null}
</>
) : (
<small>
Expand Down
Loading

0 comments on commit 3c6d593

Please sign in to comment.