From 41d0027745de71b88de26c738d7ff1a368046817 Mon Sep 17 00:00:00 2001 From: Anne Haley Date: Fri, 30 Sep 2022 11:36:27 -0400 Subject: [PATCH] Sentry errors (#606) * Enforce consistent api response destructuring (Sentry error dfc24eeb686f4f2288baec1c541ce36d) * Avoid sending requests with undefined references (Sentry error 873d87beddb0406ba50ffa2a56a27f66) * Avoid accessing properties of undefined objects (various Sentry errors) * No optional chaining in template --- web_client/src/components/ControlPanel.vue | 3 +- web_client/src/components/WindowWidget.vue | 1 + web_client/src/django.ts | 130 ++++++++++++--------- web_client/src/utils/crosshairs.js | 1 + 4 files changed, 79 insertions(+), 56 deletions(-) diff --git a/web_client/src/components/ControlPanel.vue b/web_client/src/components/ControlPanel.vue index 7466806c..17302499 100644 --- a/web_client/src/components/ControlPanel.vue +++ b/web_client/src/components/ControlPanel.vue @@ -411,7 +411,8 @@ export default { :decision="decision" />
This scan has no prior comments. diff --git a/web_client/src/components/WindowWidget.vue b/web_client/src/components/WindowWidget.vue index 205b393a..4a782ed6 100644 --- a/web_client/src/components/WindowWidget.vue +++ b/web_client/src/components/WindowWidget.vue @@ -168,6 +168,7 @@ export default defineComponent({ { - return (await apiClient.post('/global/import')).data; + const response = await apiClient.post('/global/import'); + return response?.data; }, async projectImport(projectId: string): Promise { - return (await apiClient.post(`/projects/${projectId}/import`)).data; + const response = await apiClient.post(`/projects/${projectId}/import`); + return response?.data; }, async globalExport(): Promise { - return (await apiClient.post('/global/export')).data; + const response = await apiClient.post('/global/export'); + return response?.data; }, async projectExport(projectId: string): Promise { - return (await apiClient.post(`/projects/${projectId}/export`)).data; + if (!projectId) return undefined; + const response = await apiClient.post(`/projects/${projectId}/export`); + return response?.data; }, async createProject(projectName: string): Promise { - const { data } = await apiClient.post('/projects', { name: projectName }); - return data; + if (!projectName) return undefined; + const response = await apiClient.post('/projects', { name: projectName }); + return response?.data; }, async deleteProject(projectId: string): Promise { - const { data } = await apiClient.delete(`/projects/${projectId}`); - return data; + if (!projectId) return undefined; + const response = await apiClient.delete(`/projects/${projectId}`); + return response?.data; }, async projects(): Promise { - const { data } = await apiClient.get('/projects'); - const { results } = data; - return results; + const response = await apiClient.get('/projects'); + return response?.data?.results; }, async project(projectId: string): Promise { - const { data } = await apiClient.get(`/projects/${projectId}`); - return data; + if (!projectId) return undefined; + const response = await apiClient.get(`/projects/${projectId}`); + return response?.data; }, async projectTaskOverview(projectId: string): Promise { - const { data } = await apiClient.get(`/projects/${projectId}/task_overview`); - return data; + if (!projectId) return undefined; + const response = await apiClient.get(`/projects/${projectId}/task_overview`); + return response?.data; }, async settings(projectId: string): Promise { - const { data } = await apiClient.get(`/projects/${projectId}/settings`); - return data; + if (!projectId) return undefined; + const response = await apiClient.get(`/projects/${projectId}/settings`); + return response?.data; }, async setGlobalSettings(settings: ProjectSettings): Promise { - const resp = await apiClient.put('/global/settings', settings); - return resp.status === 200 ? resp.data : null; + if (!settings) return undefined; + const response = await apiClient.put('/global/settings', settings); + return response?.data; }, async setProjectSettings(projectId: string, settings: ProjectSettings): Promise { - const resp = await apiClient.put(`/projects/${projectId}/settings`, settings); - return resp.status === 200 ? resp.data : null; + if (!projectId || !settings) return undefined; + const response = await apiClient.put(`/projects/${projectId}/settings`, settings); + return response?.data; }, async experiments(projectId: string): Promise { - const { data } = await apiClient.get('/experiments', { + if (!projectId) return undefined; + const response = await apiClient.get('/experiments', { params: { project: projectId }, }); - const { results } = data; - return results; + return response?.data?.results; }, async experiment(experimentId: string): Promise { - const { data } = await apiClient.get(`/experiments/${experimentId}`); - return data; + if (!experimentId) return undefined; + const response = await apiClient.get(`/experiments/${experimentId}`); + return response?.data; }, async createExperiment(projectId:string, experimentName: string): Promise { + if (!projectId || !experimentName) return undefined; const response = await apiClient.post('/experiments', { project: projectId, name: experimentName, }); - const { data } = response; - if (response.status === 500 && data.detail) { - throw new ErrorResponseDetail(data.detail); + if (response.status === 500 && response?.data?.detail) { + throw new ErrorResponseDetail(response.data.detail); } - return data; + return response?.data; }, async uploadToExperiment(experimentId: string, files: File[]) { + if (!experimentId || !files) return undefined; // Promise.all maintains order so we can reference filenames by index const uploadResponses = await Promise.all(files.map( (file) => s3ffClient.uploadFile(file, 'core.Frame.content'), @@ -155,27 +169,31 @@ const djangoClient = { )); }, async setExperimentNote(experimentId: string, note: string): Promise { - const { data } = await apiClient.post(`/experiments/${experimentId}/note`, { note }); - return data; + if (!experimentId) return undefined; + const response = await apiClient.post(`/experiments/${experimentId}/note`, { note }); + return response?.data; }, async lockExperiment(experimentId: string, force: boolean): Promise { - const { data } = await apiClient.post(`/experiments/${experimentId}/lock`, { force }); - return data; + if (!experimentId) return undefined; + const response = await apiClient.post(`/experiments/${experimentId}/lock`, { force }); + return response?.data; }, async unlockExperiment(experimentId: string): Promise { - const { data } = await apiClient.delete(`/experiments/${experimentId}/lock`); - return data; + if (!experimentId) return undefined; + const response = await apiClient.delete(`/experiments/${experimentId}/lock`); + return response?.data; }, async scans(experimentId: string): Promise { - const { data } = await apiClient.get('/scans', { + if (!experimentId) return undefined; + const response = await apiClient.get('/scans', { params: { experiment: experimentId }, }); - const { results } = data; - return results; + return response?.data?.results; }, async scan(scanId: string): Promise { - const { data } = await apiClient.get(`/scans/${scanId}`); - return data; + if (!scanId) return undefined; + const response = await apiClient.get(`/scans/${scanId}`); + return response?.data; }, async setDecision( scanId: string, @@ -184,29 +202,31 @@ const djangoClient = { userIdentifiedArtifacts: Object, location: Object, ): Promise { - const { data } = await apiClient.post('/scan-decisions', { + if (!scanId) return undefined; + const response = await apiClient.post('/scan-decisions', { scan: scanId, decision, note: comment, artifacts: userIdentifiedArtifacts, location, }); - return data; + return response?.data; }, async frames(scanId: string): Promise { - const { data } = await apiClient.get('/frames', { + if (!scanId) return undefined; + const response = await apiClient.get('/frames', { params: { scan: scanId }, }); - const { results } = data; - return results; + return response?.data?.results; }, async frame(frameId: string): Promise { - const { data } = await apiClient.get(`/frames/${frameId}`); - return data; + if (!frameId) return undefined; + const response = await apiClient.get(`/frames/${frameId}`); + return response?.data; }, async me(): Promise { - const resp = await apiClient.get('/users/me'); - return resp && resp.status === 200 ? resp.data : null; + const response = await apiClient.get('/users/me'); + return response?.data; }, async allUsers(): Promise> { - const resp = await apiClient.get('/users'); - return resp.status === 200 ? resp.data : null; + const response = await apiClient.get('/users'); + return response?.data; }, async sendEmail(email: Email) { await apiClient.post('/email', email); diff --git a/web_client/src/utils/crosshairs.js b/web_client/src/utils/crosshairs.js index eb09d043..afb261a7 100644 --- a/web_client/src/utils/crosshairs.js +++ b/web_client/src/utils/crosshairs.js @@ -30,6 +30,7 @@ class CrosshairSet { } getSliceLines() { + if (!this.imageData) return undefined; const [iMax, jMax, kMax] = this.imageData.getDimensions(); const iRepresentation = [