From 19d3e00395eb5b3e0354dff5e3835853811a0d0b Mon Sep 17 00:00:00 2001
From: Mike Cousins
Date: Wed, 6 Nov 2019 13:09:21 -0500
Subject: [PATCH] fix(app,api): display session error messages in SessionAlert
(#4378)
Closes #4367
---
api/src/opentrons/api/session.py | 1 +
app/src/components/RunLog/SessionAlert.js | 7 ++++++-
app/src/robot/api-client/client.js | 9 +++++++++
app/src/robot/reducer/session.js | 6 +++++-
app/src/robot/selectors.js | 10 ++++++++++
5 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/api/src/opentrons/api/session.py b/api/src/opentrons/api/session.py
index bc3c6ea9f49..d5f2dcb9f8c 100755
--- a/api/src/opentrons/api/session.py
+++ b/api/src/opentrons/api/session.py
@@ -456,6 +456,7 @@ def _snapshot(self):
payload = {
'state': self.state,
'startTime': self.startTime,
+ 'errors': self.errors,
'lastCommand': last_command
}
return {
diff --git a/app/src/components/RunLog/SessionAlert.js b/app/src/components/RunLog/SessionAlert.js
index b849dd76d1c..3be24ec3fd3 100644
--- a/app/src/components/RunLog/SessionAlert.js
+++ b/app/src/components/RunLog/SessionAlert.js
@@ -1,6 +1,8 @@
// @flow
import * as React from 'react'
+import { useSelector } from 'react-redux'
import { AlertItem } from '@opentrons/components'
+import { getSessionError } from '../../robot/selectors'
import type { SessionStatus } from '../../robot'
type Props = {
@@ -11,6 +13,7 @@ type Props = {
export default function SessionAlert(props: Props) {
const { sessionStatus, className, onResetClick } = props
+ const sessionError = useSelector(getSessionError)
switch (sessionStatus) {
case 'finished':
@@ -63,7 +66,9 @@ export default function SessionAlert(props: Props) {
resolving this issue.
}
- />
+ >
+ {sessionError !== null && {sessionError}
}
+
)
default:
diff --git a/app/src/robot/api-client/client.js b/app/src/robot/api-client/client.js
index a390347249a..fb1219c230d 100755
--- a/app/src/robot/api-client/client.js
+++ b/app/src/robot/api-client/client.js
@@ -409,6 +409,15 @@ export default function client(dispatch) {
clearRunTimerInterval()
}
+ // both light and full updates may have the errors list
+ if (apiSession.errors) {
+ update.errors = apiSession.errors.map(e => ({
+ timestamp: e.timestamp,
+ message: e.error.message,
+ line: e.error.line,
+ }))
+ }
+
// if lastCommand key is present, we're dealing with a light update
if ('lastCommand' in apiSession) {
const lastCommand = apiSession.lastCommand && {
diff --git a/app/src/robot/reducer/session.js b/app/src/robot/reducer/session.js
index 10e17593603..c4fafa67dd7 100644
--- a/app/src/robot/reducer/session.js
+++ b/app/src/robot/reducer/session.js
@@ -24,7 +24,11 @@ type Request = {
export type SessionState = {
sessionRequest: Request,
state: SessionStatus,
- errors: Array<{}>,
+ errors: Array<{|
+ timestamp: number,
+ line: number,
+ message: string,
+ |}>,
// TODO(mc, 2018-01-11): command IDs should be strings
protocolCommands: Array,
protocolCommandsById: {
diff --git a/app/src/robot/selectors.js b/app/src/robot/selectors.js
index cc8d2ca20ba..ae4d16a3c9c 100644
--- a/app/src/robot/selectors.js
+++ b/app/src/robot/selectors.js
@@ -172,6 +172,16 @@ export const getRunProgress = createSelector(
}
)
+export const getSessionError: State => string | null = createSelector(
+ (state: State) => session(state).runRequest.error,
+ (state: State) => session(state).errors,
+ (runError, sessionErrors) => {
+ if (runError) return runError.message
+ if (sessionErrors.length > 0) return sessionErrors[0].message
+ return null
+ }
+)
+
export function getStartTime(state: State): number | null {
const { startTime, remoteTimeCompensation } = session(state)