From 3e52246ecddb06acd46572ab99e3fb3c751608f1 Mon Sep 17 00:00:00 2001 From: Ryan Goetz Date: Wed, 25 Oct 2023 11:19:51 -1000 Subject: [PATCH] Update the UI to parse the ConstraintViolation response differently. This will return an object containing all constraints processed by the server, including whether they have compilation errors or ran successfully. --- src/stores/constraints.ts | 37 ++++++++++++++++++++----------------- src/utilities/effects.ts | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/stores/constraints.ts b/src/stores/constraints.ts index 0cc5dc4353..927b157ed5 100644 --- a/src/stores/constraints.ts +++ b/src/stores/constraints.ts @@ -1,6 +1,6 @@ import { keyBy } from 'lodash-es'; import { derived, get, writable, type Readable, type Writable } from 'svelte/store'; -import type { Constraint, ConstraintResult } from '../types/constraint'; +import type { Constraint, ConstraintResponse, ConstraintResult } from '../types/constraint'; import gql from '../utilities/gql'; import type { Status } from '../utilities/status'; import { modelId, planId, planStartTimeMs } from './plan'; @@ -34,7 +34,7 @@ export const constraintVisibilityMap: Readable export const checkConstraintsStatus: Writable = writable(null); -export const constraintResultsResponse: Writable = writable([]); +export const constraintResponse: Writable = writable([]); export const constraintsColumns: Writable = writable('2fr 3px 1fr'); export const constraintsFormColumns: Writable = writable('1fr 3px 2fr'); @@ -42,22 +42,25 @@ export const constraintsFormColumns: Writable = writable('1fr 3px 2fr'); /* Derived. */ export const constraintResults: Readable = derived( - [constraintResultsResponse, planStartTimeMs], - ([$constraintResultsResponse, $planStartTimeMs]) => - $constraintResultsResponse.reduce((list: ConstraintResult[], constraintResult) => { - list.push({ - ...constraintResult, - violations: constraintResult.violations.map(violation => ({ - ...violation, - windows: violation.windows.map(({ end, start }) => ({ - end: $planStartTimeMs + end / 1000, - start: $planStartTimeMs + start / 1000, + [constraintResponse, planStartTimeMs], + ([$constraintResponse, $planStartTimeMs]) => + $constraintResponse + .filter(response => response.success) + .map(successfulResponse => successfulResponse.results) + .reduce((list: ConstraintResult[], constraintResult) => { + list.push({ + ...constraintResult, + violations: constraintResult.violations.map(violation => ({ + ...violation, + windows: violation.windows.map(({ end, start }) => ({ + end: $planStartTimeMs + end / 1000, + start: $planStartTimeMs + start / 1000, + })), })), - })), - }); + }); - return list; - }, []), + return list; + }, []), ); export const visibleConstraintResults: Readable = derived( @@ -88,5 +91,5 @@ export function setAllConstraintsVisible(visible: boolean) { export function resetConstraintStores(): void { checkConstraintsStatus.set(null); - constraintResultsResponse.set([]); + constraintResponse.set([]); } diff --git a/src/utilities/effects.ts b/src/utilities/effects.ts index c3197ceec2..c6cc7e29b1 100644 --- a/src/utilities/effects.ts +++ b/src/utilities/effects.ts @@ -4,7 +4,7 @@ import type { CommandDictionary as AmpcsCommandDictionary } from '@nasa-jpl/aeri import { get } from 'svelte/store'; import { SearchParameters } from '../enums/searchParameters'; import { activityDirectives, activityDirectivesMap, selectedActivityDirectiveId } from '../stores/activities'; -import { checkConstraintsStatus, constraintResultsResponse } from '../stores/constraints'; +import { checkConstraintsStatus, constraintResponse } from '../stores/constraints'; import { catchError, catchSchedulingError } from '../stores/errors'; import { createExpansionRuleError, @@ -37,7 +37,7 @@ import type { import type { ActivityMetadata } from '../types/activity-metadata'; import type { BaseUser, User, UserId } from '../types/app'; import type { ReqAuthResponse, ReqSessionResponse } from '../types/auth'; -import type { Constraint, ConstraintInsertInput, ConstraintResult } from '../types/constraint'; +import type { Constraint, ConstraintInsertInput, ConstraintResponse, ConstraintResult } from '../types/constraint'; import type { ExpansionRule, ExpansionRuleInsertInput, @@ -285,19 +285,39 @@ const effects = { checkConstraintsStatus.set(Status.Incomplete); if (plan !== null) { const { id: planId } = plan; - const data = await reqHasura( + const data = await reqHasura( gql.CHECK_CONSTRAINTS, { planId, }, user, ); + const { ConstraintResponses } = data; + if (ConstraintResponses) { + constraintResponse.set(ConstraintResponses); - const { constraintResults } = data; - if (constraintResults != null) { - constraintResultsResponse.set(constraintResults); - checkConstraintsStatus.set(Status.Complete); - showSuccessToast('Check Constraints Complete'); + // find only the constraints compiled. + const successfulConstraintResults: ConstraintResult[] = ConstraintResponses.filter( + constraintResponse => constraintResponse.success, + ).map(constraintResponse => constraintResponse.results); + + const failedConstraintResponses = ConstraintResponses.filter( + constraintResponse => !constraintResponse.success, + ); + + if (successfulConstraintResults.length != ConstraintResponses.length) { + showFailureToast('Partial Constraints Completed'); + failedConstraintResponses.forEach(failedConstraint => { + failedConstraint.errors.forEach(error => { + catchError(`${error.message}`, error.stack); + }); + }); + + checkConstraintsStatus.set(successfulConstraintResults.length !== 0 ? Status.Incomplete : Status.Failed); + } else { + showSuccessToast('All Constraints Completed'); + checkConstraintsStatus.set(Status.Complete); + } } else { throw Error(`Unable to check constraints for plan with ID: "${plan.id}"`); }