Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
837541c
initial reproducing error
aduques Jul 23, 2026
bc99aaf
Merge branch 'development' into issue1666
aduques Jul 26, 2026
f46ecad
Add express-async-errors to forward rejected async route handlers to …
CarlyAThomas Jul 22, 2026
b33e5db
Print the original error's stack trace when logging a wrapped Error
CarlyAThomas Jul 22, 2026
987b48a
Rename obvius.js's local success/failure to successObvius/failureObvius
CarlyAThomas Jul 22, 2026
279c70e
Redesign response.js's failure() to separate logged errors from clien…
CarlyAThomas Jul 22, 2026
cf493b5
Migrate groups.js's 11 endpoints onto response.js
CarlyAThomas Jul 22, 2026
cf01bb4
Migrate units.js's 4 endpoints onto response.js
CarlyAThomas Jul 23, 2026
330b745
Migrate conversions.js's 5 endpoints onto response.js
CarlyAThomas Jul 23, 2026
607d0f3
Migrate meters.js's 4 endpoints onto response.js
CarlyAThomas Jul 27, 2026
0f08ada
Migrate users.js's 6 endpoints onto response.js
CarlyAThomas Jul 27, 2026
45f4297
Migrate login.js's 1 endpoint onto response.js
CarlyAThomas Jul 27, 2026
4015e2e
Migrate maps.js's 5 endpoints onto response.js
CarlyAThomas Jul 27, 2026
b2713f6
Migrate verification.js's 1 endpoint onto response.js
CarlyAThomas Jul 28, 2026
6695107
Migrate preferences.js's 2 endpoints onto response.js
CarlyAThomas Jul 28, 2026
2c5034b
Migrate logs.js's 4 endpoints onto response.js
CarlyAThomas Jul 28, 2026
9910f13
Migrate baseline.js's 2 endpoints onto response.js
CarlyAThomas Jul 28, 2026
0023a43
Migrate ciks.js's 1 endpoint onto response.js
CarlyAThomas Jul 28, 2026
b5935fc
Migrate compareReadings.js's 2 endpoints onto response.js
CarlyAThomas Jul 30, 2026
78b6656
Migrate readings.js's 2 endpoints onto response.js
CarlyAThomas Jul 30, 2026
76ccb34
Migrate unitReadings.js's 8 endpoints onto response.js
CarlyAThomas Jul 30, 2026
fbd43d9
Migrate conversionArray.js's 1 endpoint onto response.js
CarlyAThomas Jul 30, 2026
874d390
imported response.js to users.js + added success/failure + added TODO…
aduques Jul 30, 2026
d1e90b8
imported response.js to conversions.js + added success/failure + adde…
aduques Jul 30, 2026
a8602c5
imported response.js to groups.js + added success/failure + added TOD…
aduques Jul 31, 2026
0b954fb
imported response.js to meters.js + added failure + added TODO DEBUGs…
aduques Jul 31, 2026
1356747
imported response.js to units.js + added success/failure + added TODO…
aduques Aug 1, 2026
3e94055
merged 1614 changes + removed TODO DEBUGs
aduques Aug 5, 2026
0392153
made changes to failure() in users.js to send a message string rather…
aduques Aug 5, 2026
e33480a
Revert "made changes to failure() in users.js to send a message strin…
aduques Aug 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ export default function CreateUserModal() {
// introducing omit() in the client files for User could cause unexpected issues. We are acknowledging that the codebase currently has a different
// implementation for handleSubmit() compared to other client files.
const newUser: User = { username: userDetails.username, role: userDetails.role, password: userDetails.password, note: userDetails.note };

//TODO DEBUG
//newUser.username = '';
createUser(newUser)
.unwrap()
.then(() => {
Expand All @@ -130,7 +133,7 @@ export default function CreateUserModal() {
showErrorNotification(
translate('users.failed.to.create.user') +
translate('users.successfully.edit.user.username') + userDetails.username + ') ' +
error.data.message);
error.data);
resetPasswordFields();
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ export default function EditUserModalComponent(props: EditUserModalComponentProp
...(passwordModified && { password: userDetails.password })
};

//TODO DEBUG
//editedUser.username = '';

submitUserEdits(editedUser)
.unwrap()
.then(() => {
Expand All @@ -209,7 +212,7 @@ export default function EditUserModalComponent(props: EditUserModalComponentProp
showErrorNotification(
translate('users.failed.to.edit.user') +
translate('users.successfully.edit.user.username') + userDetails.username + ') ' +
error.data.message
error.data
);
});
resetPasswordFields();
Expand All @@ -228,7 +231,7 @@ export default function EditUserModalComponent(props: EditUserModalComponentProp
showErrorNotification(
translate('users.failed.to.delete.user') +
translate('users.successfully.edit.user.username') + props.user.username + ') ' +
error.data.message
error.data
);
});
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ export default function CreateConversionModalComponent() {
// Close modal first to avoid repeat clicks
setShowModal(false);

// TODO DEBUG: added in to test the showErrorNotification
//conversionState.sourceId = -1;
//conversionState.destinationId = -1;

// Add the new conversion and update the store
// Omit the source options , do not need to send in request so remove here.
// If source is a meter, make bidirectional false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ export default function EditConversionModalComponent(props: EditConversionModalC
translate('conversion.delete.failure') +
' (' + translate('conversion.source') + ' "' + unitDataById[payload.sourceId]?.identifier + '"' +
', ' + translate('conversion.destination') + ' "' + unitDataById[payload.destinationId]?.identifier + '") ' +
error.data.message
error.data
);
});
};
Expand Down Expand Up @@ -482,6 +482,10 @@ export default function EditConversionModalComponent(props: EditConversionModalC
// Only do work if there are changes
if (conversionHasChanges) {

// TODO DEBUG: added in to test the showErrorNotification
//state.sourceId = -1;
//state.destinationId = -1;

// Save our changes
editConversion({
conversionData: {
Expand Down Expand Up @@ -537,6 +541,10 @@ export default function EditConversionModalComponent(props: EditConversionModalC
// Only do work if there are changes
if (conversionHasChanges) {

// TODO DEBUG: added in to test the showErrorNotification
//state.sourceId = -1;
//state.destinationId = -1;

// Save our changes
editConversion({
conversionData: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ export default function CreateGroupModalComponent() {
const { ...stateWithoutId } = state;
const submitState = { ...stateWithoutId, gps: gps };

// TODO DEBUG: added in to test the showErrorNotification
//submitState.name = '';

// groupsApi.ts's createGroup mutation already strips id/deepMeters/deepGroups internally
// before building the request
createGroup(submitState)
Expand Down
9 changes: 7 additions & 2 deletions src/client/app/components/groups/EditGroupModalComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,11 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr
deleteGroup(groupState.id)
.unwrap()
.then(() => {
showSuccessNotification(translate('group.delete.success') + ' ' + groupState.name);
showSuccessNotification(
translate('group.delete.success') + ' (' + translate('name') + ' "' + groupState.name + '")'
);
}).catch(error => {
showErrorNotification(translate('group.delete.failure') + error.data.message);
showErrorNotification(translate('group.delete.failure') + ' ' + error.data);
});
};
/* End Confirm Delete Modal */
Expand Down Expand Up @@ -365,6 +367,9 @@ export default function EditGroupModalComponent(props: EditGroupModalComponentPr
defaultGraphicUnit: thisGroupState.defaultGraphicUnit
};

// TODO DEBUG: added in to test the showErrorNotification
//submitState.name = '';

// This saves group to the DB and then refreshes the window if the last group being updated and
// changes were made to the children. This avoid a reload on name change, etc.
submitGroupEdits(submitState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ export default function CreateMeterModalComponent(props: CreateMeterModalProps):
timeZone: (meterDetails.timeZone == '' ? null : meterDetails.timeZone)
};

// TODO DEBUG: added in to test the showErrorNotification
//submitState.name = '';
//submitState.identifier = '';

// Submit new meter if checks where ok.
// Attempt to add meter to database
submitAddMeter(submitState as unknown as MeterData)
Expand Down
5 changes: 5 additions & 0 deletions src/client/app/components/meters/EditMeterModalComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,11 @@ export default function EditMeterModalComponent(props: EditMeterModalComponentPr
(unitDataById[props.meter.unitId].unitRepresent != UnitRepresentType.quantity
&& unitDataById[localMeterEdits.unitId].unitRepresent == UnitRepresentType.quantity));


// TODO DEBUG: added in to test the showErrorNotification
//submitState.name = '';
//submitState.identifier = '';

// Submit new meter if checks where ok.
editMeter({ meterData: submitState, shouldRefreshViews: shouldRefreshReadingViews })
.unwrap()
Expand Down
3 changes: 3 additions & 0 deletions src/client/app/components/unit/CreateUnitModalComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ export default function CreateUnitModalComponent() {
typeOfUnit: (state.typeOfUnit != UnitType.suffix && state.suffix != '') ? UnitType.suffix : state.typeOfUnit
};

// TODO DEBUG: added in to test the showErrorNotification
//submitState.secInRate = -1;

// Add the new unit and update the store
submitCreateUnit(submitState as unknown as UnitData)
.unwrap()
Expand Down
3 changes: 3 additions & 0 deletions src/client/app/components/unit/EditUnitModalComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ export default function EditUnitModalComponent(props: EditUnitModalComponentProp
|| (props.unit.secInRate !== state.secInRate
&& (props.unit.unitRepresent === UnitRepresentType.flow || props.unit.unitRepresent === UnitRepresentType.raw));

// TODO DEBUG: added in to test the showErrorNotification
//submitState.secInRate = -1;

// Save our changes by dispatching the submitEditedUnit mutation
submitEditedUnit({ editedUnit: submitState, shouldRedoCik, shouldRefreshReadingViews })
.unwrap()
Expand Down
5 changes: 4 additions & 1 deletion src/server/routes/conversions.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ router.post('/addConversion', adminAuthMiddleware('add conversions'), async (req
);
await newConversion.insert(t);
});
res.sendStatus(HTTP_CODES.OK);
//res.sendStatus(HTTP_CODES.OK);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change overlaps a change in PR #1688 that came in at about the same time. My current thinking is their change should stay as all routes were aligned with this new methodology. Thought?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I definitely agree. The changes made in #1688 should take priority as extensive work has been done to have consistent implementations across all the routes. When merging the work from #1688, their change has overwritten this one.

success(res);
} catch (err) {
log.error(`Error while inserting new conversion with error(s): ${err}`);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, `Error while inserting new conversion with errors(s): ${err}`);
Expand All @@ -143,6 +144,8 @@ router.post('/addConversion', adminAuthMiddleware('add conversions'), async (req
* Route for POST, delete conversion.
*/
router.post('/delete', adminAuthMiddleware('delete conversions'), async (req, res) => {
// TODO DEBUG: to force the showErrorNotification to pass in EditConversionsModalComponent.tsx
//req.body.meterIds.push(0);
// Accept sourceId, destinationId, meterIds, groupIds
const validConversion = {
type: 'object',
Expand Down
17 changes: 12 additions & 5 deletions src/server/routes/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,19 +393,24 @@ router.put('/edit', adminAuthMiddleware('edit groups'), async (req, res) => {

return t.batch(flatten([adoptGroupsQueries, disownGroupsQueries, adoptMetersQueries, disownMetersQueries]));
});
res.sendStatus(HTTP_CODES.OK);
//res.sendStatus(HTTP_CODES.OK);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment. The changes here also overlap the other PR. Thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting that the merge has replaced this with the consistent implementation from #1688.

success(res);
} catch (err) {
if (err.message && err.message === 'Cyclic group detected') {
res.status(HTTP_CODES.BAD_REQUEST).send({ message: err.message });
//res.status(HTTP_CODES.BAD_REQUEST).send({ message: err.message });
failure(res, HTTP_CODES.BAD_REQUEST, err.message);
} else {
log.error(`Error while editing existing group ${err}`, err);
res.sendStatus(HTTP_CODES.INTERNAL_SERVER_ERROR);
//res.sendStatus(HTTP_CODES.INTERNAL_SERVER_ERROR);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, "Got request to edit group with invalid data. Error(s): " + validatorResult.errors.toString());
}
}
}
});

router.post('/delete', adminAuthMiddleware('delete groups'), async (req, res) => {
// TODO DEBUG: to force the showErrorNotification to pass in EditGroupsModalComponent.tsx
//req.body.id = -1;
const validParams = {
type: 'object',
additionalProperties: false,
Expand All @@ -423,10 +428,12 @@ router.post('/delete', adminAuthMiddleware('delete groups'), async (req, res) =>
const conn = getConnection();
try {
await Group.delete(req.body.id, conn);
res.sendStatus(HTTP_CODES.OK);
//res.sendStatus(HTTP_CODES.OK);
success(res, 'Successfully deleted group');
} catch (err) {
log.error(`Error while deleting group ${err}`, err);
res.sendStatus(HTTP_CODES.INTERNAL_SERVER_ERROR);
//res.sendStatus(HTTP_CODES.INTERNAL_SERVER_ERROR);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, `'Error while deleting group: ${err}`);
}
}
});
Expand Down
18 changes: 16 additions & 2 deletions src/server/routes/meters.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,14 @@ router.post('/edit', adminAuthMiddleware('edit meters'), async (req, res) => {
res.json(formatMeterForResponse(meter, true));
} catch (err) {
log.error(`Error while editing a meter with detail "${err['detail']}"`, err);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, err.toString() + ' with detail ' + err['detail']);
if (err.toString().includes('duplicate key value violates unique constraint')) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment. The changes here also overlap the other PR but I think bring in other features. Do you think they could be merged? Thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been updated to consider the changes from the other PR.

  } catch (err) {
		      if (err.toString().includes('duplicate key value violates unique constraint')) {
			      failure(res, HTTP_CODES.BAD_REQUEST, err, `Meter name "${req.body.name}" already exists`, LogLevel.SILENT);
		      } else if (err.toString().includes('violates check constraint')) {
			      failure(res, HTTP_CODES.BAD_REQUEST, err, `Invalid meter data: ${err.toString()}`, LogLevel.SILENT);
		      } else {
			      const detail = err['detail'] ? ` with detail "${err['detail']}"` : '';
			      failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, new Error(`Error while editing a meter${detail}: ${err.message}`, { cause: err }));
		      }
	      }

failure(res, HTTP_CODES.BAD_REQUEST, `Meter name "${req.body.name}" already exists`);
} else if (err.toString().includes('violates check constraint')) {
failure(res, HTTP_CODES.BAD_REQUEST, `Invalid meter data: ${err.toString()}`);
} else {
log.error(`Error while editing a meter with detail "${err['detail']}"`, err);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, err.toString() + ' with detail ' + err['detail']);
}
}
}
});
Expand Down Expand Up @@ -411,7 +418,14 @@ router.post('/addMeter', adminAuthMiddleware('add meter'), async (req, res) => {
res.json(formatMeterForResponse(newMeter, true));
} catch (err) {
log.error(`Error while inserting new meter with detail "${err['detail']}"`, err);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, err.toString() + ' with detail ' + err['detail']);
if (err.toString().includes('duplicate key value violates unique constraint')) {
failure(res, HTTP_CODES.BAD_REQUEST, `Meter name "${req.body.name}" already exists`);
} else if (err.toString().includes('violates check constraint')) {
failure(res, HTTP_CODES.BAD_REQUEST, `Invalid meter data: ${err.toString()}`);
} else {
log.error(`Error while inserting new meter with detail "${err['detail']}"`, err);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, err.toString() + ' with detail ' + err['detail']);
}
}
}
});
Expand Down
22 changes: 20 additions & 2 deletions src/server/routes/units.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,15 @@ router.post('/edit', adminAuthMiddleware('edit units'), async (req, res) => {
success(res, 'Successfully edited unit');
} catch (err) {
log.error(`Failed to update unit: ${err}`, err);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, 'Unable to update unit');
//failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, 'Unable to update unit');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment. The changes here also overlap the other PR but with new items. Thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been updated to consider the changes from the other PR.

  } catch (err) {
		      if (err.toString().includes('duplicate key value violates unique constraint')) {
			      failure(res, HTTP_CODES.BAD_REQUEST, err, `Unit name "${req.body.name}" already exists`, LogLevel.SILENT);
		      } else if (err.toString().includes('violates check constraint')) {
			      failure(res, HTTP_CODES.BAD_REQUEST, err, `Invalid unit data: ${err.toString()}`, LogLevel.SILENT);
		      } else {
			      failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, new Error(`Failed to update unit: ${err.message}`, { cause: err }));
		      }
	      }

if (err.toString().includes('duplicate key value violates unique constraint')) {
failure(res, HTTP_CODES.BAD_REQUEST, `Unit name "${req.body.name}" already exists`);
} else if (err.toString().includes('violates check constraint')) {
failure(res, HTTP_CODES.BAD_REQUEST, `Invalid unit data: ${err.toString()}`);
} else {
log.error(`Error while editing a unit with detail "${err['detail']}"`, err);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, err.toString() + ' with detail ' + err['detail']);
}
}
}
});
Expand Down Expand Up @@ -197,7 +205,15 @@ router.post('/addUnit', adminAuthMiddleware('add units'), async (req, res) => {
success(res, 'Unit created successfully');
} catch (err) {
log.error(`Error while inserting new unit: ${err}`, err);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, `Error while inserting new unit: ${err}`);
//failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, `Error while inserting new unit: ${err}`);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above in this file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been updated to consider the changes from the other PR.

	      } catch (err) {
		      if (err.toString().includes('duplicate key value violates unique constraint')) {
			      failure(res, HTTP_CODES.BAD_REQUEST, err, `Unit name "${req.body.name}" already exists`, LogLevel.SILENT);
		      } else if (err.toString().includes('violates check constraint')) {
			      failure(res, HTTP_CODES.BAD_REQUEST, err, `Invalid unit data: ${err.toString()}`, LogLevel.SILENT);
		      } else {
			      failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, new Error(`Error while inserting new unit: ${err.message}`, { cause: err }));
		      }
	      }

if (err.toString().includes('duplicate key value violates unique constraint')) {
failure(res, HTTP_CODES.BAD_REQUEST, `Unit name "${req.body.name}" already exists`);
} else if (err.toString().includes('violates check constraint')) {
failure(res, HTTP_CODES.BAD_REQUEST, `Invalid unit data: ${err.toString()}`);
} else {
log.error(`Error while inserting new unit with detail "${err['detail']}"`, err);
failure(res, HTTP_CODES.INTERNAL_SERVER_ERROR, err.toString() + ' with detail ' + err['detail']);
}
}
}
});
Expand All @@ -206,6 +222,8 @@ router.post('/addUnit', adminAuthMiddleware('add units'), async (req, res) => {
* Route for deleting a unit by ID.
*/
router.post('/delete', adminAuthMiddleware('delete units'), async (req, res) => {
// TODO DEBUG: to force the showErrorNotification to pass in EditUnitsModalComponent.tsx
//req.body.id = -1;
const validParams = {
type: 'object',
additionalProperties: false,
Expand Down
Loading
Loading