From 0daa9f0f2ab25611e9175cb45d0cb6136790f170 Mon Sep 17 00:00:00 2001 From: AaronPlave Date: Wed, 20 May 2026 08:48:13 -0700 Subject: [PATCH 1/6] refactor: unify error/log pipeline into consoleEntries store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single writable + two helpers (catchError, logMessage) that take a category first arg. Per-tab readables (schedulingErrors, simulationDatasetErrors, constraintRunErrors, allLogs, errorLogs, allProblems) are derived filters and keep their original public names. Deletes SchedulingError, SimulationDatasetError, ConstraintRunError in favor of LogMessage with an optional category. Routes thrown exceptions during schedule/simulate/checkConstraints to the matching tab rather than the generic Logs tab — UI half of NASA-AMMOS/plandev#1777. --- .../console/views/ConsoleLog.svelte | 11 +- src/components/timeline/Row.svelte | 6 +- .../workspaces/[workspaceId]/+page.svelte | 8 +- src/stores/errors.test.ts | 164 +++ src/stores/errors.ts | 203 ++-- src/types/errors.ts | 39 +- src/types/scheduling.ts | 6 +- src/types/simulation.ts | 6 +- src/utilities/effects.test.ts | 20 +- src/utilities/effects.ts | 958 ++++++++++-------- src/utilities/errors.test.ts | 4 +- src/utilities/errors.ts | 49 +- src/utilities/requests.test.ts | 176 ++++ src/utilities/requests.ts | 11 +- src/utilities/simulation.ts | 3 +- 15 files changed, 1050 insertions(+), 614 deletions(-) create mode 100644 src/stores/errors.test.ts create mode 100644 src/utilities/requests.test.ts diff --git a/src/components/console/views/ConsoleLog.svelte b/src/components/console/views/ConsoleLog.svelte index cb53da27de..f7d28475d4 100644 --- a/src/components/console/views/ConsoleLog.svelte +++ b/src/components/console/views/ConsoleLog.svelte @@ -5,7 +5,6 @@ import { ChevronDown, ChevronRight } from 'lucide-svelte'; import { onMount } from 'svelte'; import type { BaseError, LogMessage } from '../../../types/errors'; - import { isLogMessage } from '../../../utilities/errors'; import { safeStringify } from '../../../utilities/text'; import { formatMS } from '../../../utilities/time'; @@ -17,15 +16,17 @@ export let showLongTimestamp: boolean = true; export let showType: boolean = true; + let duration: number | undefined; let expandable: boolean = false; - let leftContents: HTMLDivElement; - let open: boolean = defaultExpanded; let expansionPadding: number = 0; + let leftContents: HTMLDivElement; let level: string = ''; + let open: boolean = defaultExpanded; let renderedMessage: string = ''; $: expandable = log.data || log.trace || log.cause || log.service ? true : false; $: level = (log as LogMessage).level || ''; + $: duration = (log as LogMessage).duration; // if we have no message but we *do* have data, and row is not expanded, render data as message so row isn't empty $: renderedMessage = !log.message.trim() && log.data && !(expandable && open) ? safeStringify(log.data) : (log.message ?? ''); @@ -137,8 +138,8 @@ {renderedMessage} - {#if isLogMessage(log) && typeof log.duration === 'number'} -
({formatMS(log.duration)})
+ {#if typeof duration === 'number'} +
({formatMS(duration)})
{/if} diff --git a/src/components/timeline/Row.svelte b/src/components/timeline/Row.svelte index 4c8ab3eac7..cd435a5c03 100644 --- a/src/components/timeline/Row.svelte +++ b/src/components/timeline/Row.svelte @@ -308,9 +308,9 @@ if (profile && profile.length === 1) { resource = sampleProfiles([profile[0]], startTimeYmd)[0]; logMessage( + 'log', `Retrieved profile ${name} (${profile[0].profile_segments.length} segment${pluralize(profile[0].profile_segments.length)}) for simulation ${simulationDatasetId}.`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); } else { throw new Error('Profile not Found'); @@ -320,7 +320,7 @@ if (err.name === 'AbortError') { aborted = true; } else { - catchError(`Profile Download Failed for ${name}`, e as Error); + catchError('log', `Profile Download Failed for ${name}`, e as Error); error = err.message; } } finally { diff --git a/src/routes/workspaces/[workspaceId]/+page.svelte b/src/routes/workspaces/[workspaceId]/+page.svelte index 7d78bbe878..1fe604ec28 100644 --- a/src/routes/workspaces/[workspaceId]/+page.svelte +++ b/src/routes/workspaces/[workspaceId]/+page.svelte @@ -565,7 +565,9 @@ addWorkspaceAdaptationLog(log.level as LogLevel, log.args); }); setSequenceLanguages(adaptation); - logMessage(`Loaded adaptation "${metadata.name}" (ID=${id}).`, '', performance.now() - startTime); + logMessage('log', `Loaded adaptation "${metadata.name}" (ID=${id}).`, { + duration: performance.now() - startTime, + }); } catch (e) { console.error(e); showFailureToast('Invalid sequence adaptation'); @@ -910,7 +912,7 @@ } showSuccessToast(`File marked as ${readOnly ? 'read only' : 'editable'}`); } catch (e) { - catchError('Failed to update read-only status', e as Error); + catchError('log', 'Failed to update read-only status', e as Error); showFailureToast('Failed to update read-only status'); } } @@ -929,7 +931,7 @@ } showSuccessToast('User metadata updated'); } catch (e) { - catchError('Failed to update user metadata', e as Error); + catchError('log', 'Failed to update user metadata', e as Error); showFailureToast('Failed to update user metadata'); } } diff --git a/src/stores/errors.test.ts b/src/stores/errors.test.ts new file mode 100644 index 0000000000..5026088a3b --- /dev/null +++ b/src/stores/errors.test.ts @@ -0,0 +1,164 @@ +import { get } from 'svelte/store'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; +import type { BaseError } from '../types/errors'; +import { ErrorTypes } from '../utilities/errors'; +import { CompoundError } from '../utilities/requests'; +import { + allLogs, + catchError, + clearConsoleEntries, + errorLogs, + logMessage, + consoleEntries, + schedulingErrors, +} from './errors'; + +vi.mock('$env/dynamic/public', () => ({ env: {} })); +vi.mock('$app/environment', () => ({ browser: true })); + +function backendError(type: ErrorTypes, service: string, msg = 'something failed'): BaseError { + return { + data: { specification_id: 659 }, + message: msg, + service, + timestamp: '2026-05-18T16:10:49Z', + trace: 'stack', + type, + }; +} + +function compoundFrom(...errors: BaseError[]): CompoundError { + return new CompoundError( + errors[0]?.message ?? 'multi', + errors.map(e => ({ ...e, level: 'error' })), + ); +} + +describe('catchError routes by call-site category', () => { + beforeEach(() => { + clearConsoleEntries(); + vi.spyOn(console, 'log').mockImplementation(() => {}); + }); + + afterEach(() => { + clearConsoleEntries(); + vi.restoreAllMocks(); + }); + + test('thrown Error wraps message prefix and routes to scheduling tab', () => { + catchError('scheduling', 'Unable to schedule', new Error('boom')); + expect(get(schedulingErrors)).toHaveLength(1); + expect(get(schedulingErrors)[0].category).toBe('scheduling'); + expect(get(schedulingErrors)[0].type).toBe(ErrorTypes.CAUGHT_ERROR); + expect(get(schedulingErrors)[0].message).toContain('Unable to schedule'); + expect(get(schedulingErrors)[0].message).toContain('boom'); + expect(get(allLogs)).toHaveLength(0); + }); + + test('CompoundError fans out to multiple entries with original types preserved', () => { + const ce = compoundFrom( + backendError(ErrorTypes.NO_SUCH_PLAN, 'aerie_merlin', 'plan gone'), + backendError(ErrorTypes.FORBIDDEN, 'aerie_permissions', 'nope'), + ); + catchError('simulation', 'Simulation failed', ce); + const errs = get(consoleEntries).filter(e => e.category === 'simulation'); + expect(errs).toHaveLength(2); + expect(errs[0].type).toBe(ErrorTypes.NO_SUCH_PLAN); + expect(errs[1].type).toBe(ErrorTypes.FORBIDDEN); + expect(errs[0].message).toContain('Simulation failed'); + }); + + test('BaseError payload spreads directly (graceful failure path)', () => { + const reason = backendError(ErrorTypes.NO_SUCH_SCHEDULING_SPECIFICATION, 'aerie_permissions'); + catchError('scheduling', '', reason); + const errs = get(schedulingErrors); + expect(errs).toHaveLength(1); + expect(errs[0].type).toBe(ErrorTypes.NO_SUCH_SCHEDULING_SPECIFICATION); + expect(errs[0].service).toBe('aerie_permissions'); + expect(errs[0].data).toEqual({ specification_id: 659 }); + }); + + test('PR #1777 key case — service=aerie_permissions during scheduling lands in Scheduling tab, not Logs', () => { + const reason = backendError( + ErrorTypes.NO_SUCH_SCHEDULING_SPECIFICATION, + 'aerie_permissions', + 'Could not check permissions on scheduling specification 659: specification does not exist.', + ); + catchError('scheduling', '', reason); + expect(get(schedulingErrors)).toHaveLength(1); + expect(get(errorLogs)).toHaveLength(0); + expect(get(allLogs)).toHaveLength(0); + }); + + test('ignores AbortError without pushing', () => { + const ae = new Error('aborted'); + ae.name = 'AbortError'; + catchError('scheduling', 'Unable to schedule', ae); + expect(get(consoleEntries)).toHaveLength(0); + }); + + test('default category="log" lands in allLogs and errorLogs', () => { + catchError('log', 'Create Failed', new Error('boom')); + expect(get(allLogs)).toHaveLength(1); + expect(get(errorLogs)).toHaveLength(1); + expect(get(schedulingErrors)).toHaveLength(0); + }); + + test('shouldLog=false suppresses console output', () => { + catchError('log', 'x', new Error('y'), { shouldLog: false }); + expect(console.log).not.toHaveBeenCalled(); + }); + + test('options.level=warn applies', () => { + catchError('log', 'warn me', new Error('w'), { level: 'warn' }); + expect(get(allLogs)[0].level).toBe('warn'); + // errorLogs filters level=error, so warn shouldn't show up there + expect(get(errorLogs)).toHaveLength(0); + }); +}); + +describe('logMessage', () => { + beforeEach(() => clearConsoleEntries()); + afterEach(() => clearConsoleEntries()); + + test('pushes an info-level LOG entry under the given category', () => { + logMessage('scheduling', 'Completed scheduling.', { duration: 1234 }); + const entries = get(consoleEntries); + expect(entries).toHaveLength(1); + expect(entries[0].category).toBe('scheduling'); + expect(entries[0].level).toBe('info'); + expect(entries[0].type).toBe(ErrorTypes.LOG); + expect(entries[0].duration).toBe(1234); + }); + + test('strips redundant prefix via cleanLogMessage', () => { + logMessage('log', 'Error: boom'); + expect(get(allLogs)[0].message).toBe('boom'); + }); + + test('details become cause', () => { + logMessage('log', 'msg', { details: 'why' }); + expect(get(allLogs)[0].cause).toBe('why'); + }); +}); + +describe('clearConsoleEntries', () => { + beforeEach(() => clearConsoleEntries()); + + test('no arg clears all categories', () => { + catchError('scheduling', 'a', new Error('x')); + catchError('simulation', 'b', new Error('y')); + catchError('log', 'c', new Error('z')); + expect(get(consoleEntries)).toHaveLength(3); + clearConsoleEntries(); + expect(get(consoleEntries)).toHaveLength(0); + }); + + test('category arg clears only that category', () => { + catchError('scheduling', 'a', new Error('x')); + catchError('simulation', 'b', new Error('y')); + clearConsoleEntries('scheduling'); + expect(get(schedulingErrors)).toHaveLength(0); + expect(get(consoleEntries).filter(e => e.category === 'simulation')).toHaveLength(1); + }); +}); diff --git a/src/stores/errors.ts b/src/stores/errors.ts index bc9e432a04..c958a26a0d 100644 --- a/src/stores/errors.ts +++ b/src/stores/errors.ts @@ -7,11 +7,9 @@ import type { ActivityValidationErrors, AnchorValidationError, BaseError, - ConstraintRunError, + ErrorCategory, LogLevel, LogMessage, - SchedulingError, - SimulationDatasetError, } from '../types/errors'; import type { ModelLog, ModelStatus } from '../types/model'; import { ErrorTypes, generateActivityValidationErrorRollups } from '../utilities/errors'; @@ -105,39 +103,48 @@ export const activityErrorRollupsMap: Readable keyBy($activityErrorRollups, 'id'), ); -export const constraintRunErrors: Readable = derived( - [relevantConstraintRuns], - ([$relevantConstraintRuns]) => { - return $relevantConstraintRuns +export const consoleEntries: Writable = writable([]); + +export const constraintRunErrors: Readable = derived( + [relevantConstraintRuns, consoleEntries], + ([$relevantConstraintRuns, $consoleEntries]) => { + const fromRuns: LogMessage[] = $relevantConstraintRuns .filter(run => run.results.violations?.length || run.errors?.length) - .map(run => { - return { - data: { - constraintId: run.constraint_id, - errors: run.errors, - violations: run.results.violations || undefined, - }, - message: run.errors?.length - ? run.errors[0].message - : `Constraint "${run.results.constraintName}" has ${run.results.violations?.length ?? 0} violation${pluralize(run.results.violations?.length ?? 0)}`, - timestamp: run.requested_at, - type: ErrorTypes.CONSTRAINT_RUN_ERROR, - } as ConstraintRunError; - }); + .map(run => ({ + category: 'constraint', + data: { + constraintId: run.constraint_id, + errors: run.errors, + violations: run.results.violations || undefined, + }, + level: 'error', + message: run.errors?.length + ? run.errors[0].message + : `Constraint "${run.results.constraintName}" has ${run.results.violations?.length ?? 0} violation${pluralize(run.results.violations?.length ?? 0)}`, + timestamp: run.requested_at, + type: ErrorTypes.CONSTRAINT_RUN_ERROR, + })); + const fromExceptions = $consoleEntries.filter(e => e.category === 'constraint'); + return [...fromRuns, ...fromExceptions]; }, ); -export const simulationDatasetErrors: Readable = derived( - [simulationDataset], - ([$simulationDataset]) => { - return $simulationDataset && $simulationDataset.reason - ? [ - { - ...$simulationDataset.reason, - message: parseErrorReason($simulationDataset.reason.message), - }, - ] - : []; +export const simulationDatasetErrors: Readable = derived( + [simulationDataset, consoleEntries], + ([$simulationDataset, $consoleEntries]) => { + const fromDataset: LogMessage[] = + $simulationDataset && $simulationDataset.reason + ? [ + { + ...$simulationDataset.reason, + category: 'simulation', + level: 'error', + message: parseErrorReason($simulationDataset.reason.message), + }, + ] + : []; + const fromExceptions = $consoleEntries.filter(e => e.category === 'simulation'); + return [...fromDataset, ...fromExceptions]; }, [], ); @@ -167,12 +174,14 @@ export const modelErrors: Readable = derived( [], ); -export const schedulingErrors: Writable = writable([]); +export const schedulingErrors: Readable = derived(consoleEntries, $pe => + $pe.filter(e => e.category === 'scheduling'), +); -export const allLogs: Writable = writable([]); +export const allLogs: Readable = derived(consoleEntries, $pe => $pe.filter(e => e.category === 'log')); -export const errorLogs: Readable = derived([allLogs], ([$allLogs]) => - $allLogs.filter(log => log.type === ErrorTypes.CAUGHT_ERROR), +export const errorLogs: Readable = derived(consoleEntries, $pe => + $pe.filter(e => e.category === 'log' && e.level === 'error'), ); export const allProblems: Readable = derived( @@ -259,81 +268,93 @@ function generateLogMessageForModelLog(modelLog: ModelLog | null, status: ModelS } } -export function logMessage( - message: string, - details?: string, - duration?: number, - level: LogLevel = 'info', - shouldLog: boolean = false, -): void { - allLogs.update(l => { - l.push({ - level, - message: cleanLogMessage(message), - timestamp: `${new Date()}`, - ...(details ? { cause: details } : {}), - ...(typeof duration === 'number' ? { duration } : {}), - type: ErrorTypes.LOG, - }); - return [...l]; - }); - - if (shouldLog) { - console.log(details ?? message); +function compoundErrorToLogMessages(message: string, error: Error | CompoundError): LogMessage[] { + // Returns [] for AbortError so the caller can bail without pushing. + if ((error as Error).name === 'AbortError') { + return []; } + if ((error as CompoundError).name === 'CompoundError') { + return (error as CompoundError).errors.map(e => ({ ...e, message: `${message}: ${e.message}` })); + } + return [ + { + cause: error.cause ? (typeof error.cause === 'object' ? JSON.stringify(error.cause) : String(error.cause)) : '', + level: 'error', + message: `${message}: ${cleanLogMessage(`${error}`)}`, + timestamp: `${new Date()}`, + trace: error.stack, + type: ErrorTypes.CAUGHT_ERROR, + }, + ]; } -export function catchError(message: string, error: Error | CompoundError, shouldLog: boolean = true): void { - let errors: LogMessage[] = []; - - // ignore the error if it is an AbortError - if ((error as Error).name && (error as Error).name === 'AbortError') { - return; - } +// Dispatches on `error instanceof Error`: thrown Errors / CompoundErrors get the `message` prefix; +// plain BaseError objects (backend graceful-failure responses) are spread directly. +export function catchError( + category: ErrorCategory, + message: string, + error: Error | CompoundError | BaseError, + options?: { level?: LogLevel; shouldLog?: boolean }, +): void { + const shouldLog = options?.shouldLog ?? true; + const level: LogLevel = options?.level ?? 'error'; + let entries: LogMessage[]; - if ((error as CompoundError).name === 'CompoundError') { - errors = (error as CompoundError).errors.map(e => ({ ...e, message: `${message}: ${e.message}` })); + if (error instanceof Error) { + const logs = compoundErrorToLogMessages(message, error); + if (!logs.length) { + return; + } + entries = logs.map(l => ({ ...l, category, level })); } else { - errors = [ - { - cause: `${typeof error.cause === 'object' ? JSON.stringify(error.cause) : error.cause}` || '', - level: 'error', - message: `${message}: ${cleanLogMessage(`${error}`)}`, - timestamp: `${new Date()}`, - trace: error.stack, - type: ErrorTypes.CAUGHT_ERROR, - }, - ]; + entries = [{ ...error, category, level, message: message ? `${message}: ${error.message}` : error.message }]; } - allLogs.update(l => { - return l.concat(errors); - }); + consoleEntries.update(arr => arr.concat(entries)); if (shouldLog) { console.log(error); } } -export function catchSchedulingError(error: SchedulingError) { - schedulingErrors.update(errors => { - errors.push({ - ...error, - message: parseErrorReason(error.message), - }); - return [...errors]; - }); +export function logMessage( + category: ErrorCategory, + message: string, + options?: { details?: string; duration?: number; level?: LogLevel; shouldLog?: boolean }, +): void { + const level: LogLevel = options?.level ?? 'info'; + const entry: LogMessage = { + category, + level, + message: cleanLogMessage(message), + timestamp: `${new Date()}`, + type: ErrorTypes.LOG, + ...(options?.details ? { cause: options.details } : {}), + ...(typeof options?.duration === 'number' ? { duration: options.duration } : {}), + }; + consoleEntries.update(arr => arr.concat([entry])); + + if (options?.shouldLog) { + console.log(options?.details ?? message); + } +} + +export function clearConsoleEntries(category?: ErrorCategory): void { + if (category === undefined) { + consoleEntries.set([]); + } else { + consoleEntries.update(arr => arr.filter(e => e.category !== category)); + } } export function clearSchedulingErrors(): void { - schedulingErrors.set([]); + clearConsoleEntries('scheduling'); } export function clearLogs(): void { - allLogs.set([]); + clearConsoleEntries('log'); } export function resetErrorStores(): void { - clearLogs(); - clearSchedulingErrors(); + clearConsoleEntries(); } diff --git a/src/types/errors.ts b/src/types/errors.ts index 6414fcdea5..97af0b4b70 100644 --- a/src/types/errors.ts +++ b/src/types/errors.ts @@ -1,5 +1,4 @@ import type { ErrorTypes } from '../utilities/errors'; -import type { ConstraintResult, UserCodeError } from './constraint'; export type LogLevel = 'error' | 'warn' | 'info'; @@ -13,10 +12,13 @@ export interface BaseError { type: ErrorTypes; // very short, semi-human-readable string representing the category/class/type of error, in all caps and underscores, eg. “INVALID_SIMULATION_ID” } +export type ErrorCategory = 'activity' | 'anchor' | 'constraint' | 'log' | 'model' | 'scheduling' | 'simulation'; + export interface LogMessage extends BaseError { - duration?: number; // optional ms + category?: ErrorCategory; // set when the entry enters consoleEntries; unset for pre-categorization shapes + duration?: number; level: LogLevel; - type: ErrorTypes.CAUGHT_ERROR | ErrorTypes.LOG; + type: ErrorTypes; } export interface AnchorValidationError extends BaseError { @@ -35,37 +37,6 @@ export interface ActivityValidationErrors { type: string; } -export interface ConstraintRunError extends BaseError { - data: { - constraintId: number; - errors?: UserCodeError[]; - violations?: Pick; - }; -} - -export interface SchedulingError extends BaseError { - data: { - errors: { - [activityId: string]: unknown; - }; - success: boolean; - }; -} - -export interface SimulationDatasetError extends BaseError { - data: { - activityStackStrace?: string; - elapsedTime?: string; - errors?: { - [activityId: string]: unknown; - }; - executingActivityType?: string; - executingDirectiveId?: number; - success?: boolean; - utcTimeDoy?: string; - }; -} - export interface ActivityDirectiveInstantiationError { extraneousArguments: string[]; missingArguments: string[]; diff --git a/src/types/scheduling.ts b/src/types/scheduling.ts index 33a6682688..e6a9999d49 100644 --- a/src/types/scheduling.ts +++ b/src/types/scheduling.ts @@ -1,6 +1,6 @@ import type { SchedulingDefinitionType } from '../enums/scheduling'; import type { PartialWith } from './app'; -import type { SchedulingError } from './errors'; +import type { BaseError } from './errors'; import type { BaseDefinition, BaseMetadata } from './metadata'; import type { ArgumentsMap } from './parameter'; import type { SchedulingTagsInsertInput } from './tags'; @@ -141,7 +141,7 @@ export type SchedulingGoalAnalysis = { export type SchedulingResponse = { analysisId: number | null; - reason: SchedulingError; + reason: BaseError; }; export type SchedulingGoalModelSpecification = { @@ -211,7 +211,7 @@ export type SchedulingRequest = { analysis_id: number; canceled: boolean; dataset_id: number | null; - reason: SchedulingError | null; + reason: BaseError | null; requested_at: string; requested_by: string; specification_id: number; diff --git a/src/types/simulation.ts b/src/types/simulation.ts index d559032bff..0db2fb6910 100644 --- a/src/types/simulation.ts +++ b/src/types/simulation.ts @@ -1,6 +1,6 @@ import type { ActivityDirectiveId } from './activity'; import type { UserId } from './app'; -import type { BaseError, SimulationDatasetError } from './errors'; +import type { BaseError } from './errors'; import type { ArgumentsMap } from './parameter'; import type { ValueSchema } from './schema'; import type { Subscription } from './subscribable'; @@ -83,7 +83,7 @@ export type SimulationEvent = { }; export type SimulateResponse = { - reason: SimulationDatasetError; + reason: BaseError; simulationDatasetId: number; status: 'complete' | 'failed' | 'incomplete' | 'pending'; }; @@ -106,7 +106,7 @@ export type SimulationDataset = { model_id: number; model_revision: number; plan_revision: number; - reason: SimulationDatasetError | null; + reason: BaseError | null; requested_at: string; requested_by: string; simulation_end_time: string | null; diff --git a/src/utilities/effects.test.ts b/src/utilities/effects.test.ts index 4b9b69100a..acaa91ff5b 100644 --- a/src/utilities/effects.test.ts +++ b/src/utilities/effects.test.ts @@ -77,6 +77,7 @@ describe('Handle modal and requests in effects', () => { ); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Preset Unable To Be Applied To Activity', Error('Unable to apply preset with ID: "1" to directive with ID: "2"'), ); @@ -116,6 +117,7 @@ describe('Handle modal and requests in effects', () => { ); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Simulation Update Failed', Error('Unable to update simulation with ID: "1"'), ); @@ -141,6 +143,7 @@ describe('Handle modal and requests in effects', () => { ); expect(catchErrorSpy).toHaveBeenCalledWith( + 'constraint', 'Check Constraints Failed', Error('Unable to check constraints for plan with ID: "1"'), ); @@ -203,6 +206,7 @@ describe('Handle modal and requests in effects', () => { ); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Derivation Group Create Failed', Error('Unable to create derivation group'), ); @@ -219,6 +223,7 @@ describe('Handle modal and requests in effects', () => { await effects.getExternalEvents('test', 'test', mockUser); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Failed to retrieve external events.', Error("Unable to get external events for external source 'test' (derivation group: 'test')."), ); @@ -235,6 +240,7 @@ describe('Handle modal and requests in effects', () => { await effects.getExternalEventTypesBySource('test', 'test', mockUser); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Failed to retrieve external event types for source', Error('Unable to retrieve external event types for source'), ); @@ -251,6 +257,7 @@ describe('Handle modal and requests in effects', () => { await effects.getExternalEventTypes(1, mockUser); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Failed to retrieve external event types', Error('Unable to gather all external event types for the source'), ); @@ -297,6 +304,7 @@ describe('Handle modal and requests in effects', () => { ); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Activity Directive Create Failed', Error('Unable to create activity directive "foo" on plan with ID 1'), ); @@ -314,6 +322,7 @@ describe('Handle modal and requests in effects', () => { await effects.createActivityDirectiveTags([], mockUser); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Create Activity Directive Tags Failed', Error('Unable to create activity directive tags'), ); @@ -341,6 +350,7 @@ describe('Handle modal and requests in effects', () => { expect(catchErrorSpy).toHaveBeenCalledOnce(); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Create Activity Directive Tags Failed', Error('Some activity directive tags were not successfully created'), ); @@ -358,6 +368,7 @@ describe('Handle modal and requests in effects', () => { await effects.createSequenceTemplate('', '', 0, '', 0, '', mockUser); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Create Sequence Template Failed', Error('Create Sequence Template Failed'), ); @@ -388,6 +399,7 @@ describe('Handle modal and requests in effects', () => { ); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Sequence Template Deletion Failed', Error('Unable to delete sequence template with ID: "0"'), ); @@ -405,6 +417,7 @@ describe('Handle modal and requests in effects', () => { await effects.createSequenceFilter({} as ActivityLayerFilter, '', 0, mockUser); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Create Sequence Filter Failed', Error('Create Sequence Filter Failed'), ); @@ -423,6 +436,7 @@ describe('Handle modal and requests in effects', () => { await effects.deleteSequenceFilters([1, 2, 3], mockUser); expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', 'Sequence Filter Delete Failed', Error('Unable to delete sequence filters with IDs: "1,2,3"'), ); @@ -451,7 +465,11 @@ describe('Handle modal and requests in effects', () => { mockUser, ); - expect(catchErrorSpy).toHaveBeenCalledWith('Sequence Templating Failed', Error('Sequence Templating Failed')); + expect(catchErrorSpy).toHaveBeenCalledWith( + 'log', + 'Sequence Templating Failed', + Error('Sequence Templating Failed'), + ); }); }); diff --git a/src/utilities/effects.ts b/src/utilities/effects.ts index 879bb63059..18799d8dad 100644 --- a/src/utilities/effects.ts +++ b/src/utilities/effects.ts @@ -31,7 +31,7 @@ import { checkConstraintsQueryStatus as checkConstraintsQueryStatusStore, resetConstraintStoresForSimulation, } from '../stores/constraints'; -import { catchError, catchSchedulingError, logMessage } from '../stores/errors'; +import { catchError, clearConsoleEntries, logMessage } from '../stores/errors'; import { createExpansionRuleError as createExpansionRuleErrorStore, creatingExpansionSequence as creatingExpansionSequenceStore, @@ -296,7 +296,7 @@ import { showWorkspaceBulkOperationConflictModal, } from './modal'; import { featurePermissions, gatewayPermissions, queryPermissions } from './permissions'; -import { CompoundError, reqActionServer, reqExtension, reqGateway, reqHasura } from './requests'; +import { reqActionServer, reqExtension, reqGateway, reqHasura } from './requests'; import { sampleProfiles } from './resources'; import { convertResponseToMetadata } from './scheduling'; import { compareEvents } from './simulation'; @@ -563,6 +563,7 @@ const effects = { if (data !== null) { logMessage( + 'log', `Applied sequence filter "${filter.name}" (ID=${filter.id}) to simulation dataset ID=${simulationDatasetId}.`, ); showSuccessToast('Filter Applied Successfully'); @@ -572,7 +573,7 @@ const effects = { } } } catch (e) { - catchError('Filter Application Failed', e as Error); + catchError('log', 'Filter Application Failed', e as Error); showFailureToast('Filter Application Failed'); } }, @@ -614,14 +615,17 @@ const effects = { user, ); if (data.apply_preset_to_activity != null) { - logMessage(`Applied preset "${preset.name}" (ID=${preset.id}) to activity directive ID=${activityId}.`); + logMessage( + 'log', + `Applied preset "${preset.name}" (ID=${preset.id}) to activity directive ID=${activityId}.`, + ); showSuccessToast('Preset Successfully Applied to Activity'); } else { throw Error(`Unable to apply preset with ID: "${preset.id}" to directive with ID: "${activityId}"`); } } } catch (e) { - catchError('Preset Unable To Be Applied To Activity', e as Error); + catchError('log', 'Preset Unable To Be Applied To Activity', e as Error); showFailureToast('Preset Application Failed'); } }, @@ -655,11 +659,11 @@ const effects = { const newSimulation: Simulation = { ...simulation, arguments: template.arguments, template }; await effects.updateSimulation(plan, newSimulation, user); - logMessage(`Applied template ID=${template.id} to simulation ID=${simulation.id}.`); + logMessage('log', `Applied template ID=${template.id} to simulation ID=${simulation.id}.`); showSuccessToast('Template Successfully Applied to Simulation'); } } catch (e) { - catchError('Template Unable To Be Applied To Simulation', e as Error); + catchError('log', 'Template Unable To Be Applied To Simulation', e as Error); showFailureToast('Template Application Failed'); } }, @@ -674,7 +678,7 @@ const effects = { if (response.success) { showSuccessToast(response.message); - logMessage(`Executed extension "${extension.label}" (ID=${extension.id}).`); + logMessage('log', `Executed extension "${extension.label}" (ID=${extension.id}).`); window.open(response.url, '_blank'); } else { throw new Error(response.message); @@ -682,7 +686,7 @@ const effects = { } catch (error: any) { const failureMessage = `Extension: ${extension.label} was not executed successfully`; - catchError(failureMessage, error as Error); + catchError('log', failureMessage, error as Error); showFailureToast(failureMessage); } }, @@ -711,7 +715,7 @@ const effects = { } } } catch (e) { - catchError('Action Cancellation Failed', e as Error); + catchError('log', 'Action Cancellation Failed', e as Error); showFailureToast('Action Cancellation Failed'); } }, @@ -731,11 +735,11 @@ const effects = { if (confirm) { await reqHasura(gql.CANCEL_SCHEDULING_REQUEST, { id: analysisId }, user); - logMessage(`Canceled scheduling request ID=${analysisId}.`); + logMessage('log', `Canceled scheduling request ID=${analysisId}.`); showSuccessToast('Scheduling Request Successfully Canceled'); } } catch (e) { - catchError('Scheduling Request Unable To Be Canceled', e as Error); + catchError('log', 'Scheduling Request Unable To Be Canceled', e as Error); showFailureToast('Scheduling Request Cancel Failed'); } }, @@ -755,16 +759,17 @@ const effects = { if (confirm) { await reqHasura(gql.CANCEL_SIMULATION, { id: simulationDatasetId }, user); - logMessage(`Canceled simulation ID=${simulationDatasetId}.`); + logMessage('log', `Canceled simulation ID=${simulationDatasetId}.`); showSuccessToast('Simulation Successfully Canceled'); } } catch (e) { - catchError('Simulation Unable To Be Canceled', e as Error); + catchError('log', 'Simulation Unable To Be Canceled', e as Error); showFailureToast('Simulation Cancel Failed'); } }, async checkConstraints(plan: Plan, user: User | null, force: boolean = false): Promise { + clearConsoleEntries('constraint'); try { checkConstraintsQueryStatusStore.set(Status.Incomplete); if (plan !== null) { @@ -798,7 +803,7 @@ const effects = { showSuccessToast('All Constraints Checked'); checkConstraintsQueryStatusStore.set(Status.Complete); } - logMessage(`Ran constraint checking.`, '', performance.now() - startTime); + logMessage('log', `Ran constraint checking.`, { duration: performance.now() - startTime }); } else { throw Error(`Unable to check constraints for plan with ID: "${plan.id}"`); } @@ -807,7 +812,7 @@ const effects = { } } catch (e) { checkConstraintsQueryStatusStore.set(Status.Failed); - catchError('Check Constraints Failed', e as Error); + catchError('constraint', 'Check Constraints Failed', e as Error); showFailureToast('Check Constraints Failed'); } }, @@ -824,10 +829,10 @@ const effects = { user, ); const modelCompatabilityForPlan: ModelCompatabilityForPlan = data.check_model_compatibility_for_plan?.result; - logMessage(`Checked plan model migration compatibility for model ID=${newModelId}.`); + logMessage('log', `Checked plan model migration compatibility for model ID=${newModelId}.`); return modelCompatabilityForPlan; } catch (e) { - catchError('Check Plan Model Migration Compatibility Failed', e as Error); + catchError('log', 'Check Plan Model Migration Compatibility Failed', e as Error); } }, @@ -884,15 +889,14 @@ const effects = { })); await reqHasura(gql.UPDATE_ACTIVITY_DIRECTIVES, { updates: anchorUpdates }, user); - logMessage( - `Pasted ${activities.length} activity directive${pluralize(activities.length)}.`, - `ID${pluralize(activities.length)}: ${activities.map(a => a.id).join(', ')}`, - ); + logMessage('log', `Pasted ${activities.length} activity directive${pluralize(activities.length)}.`, { + details: `ID${pluralize(activities.length)}: ${activities.map(a => a.id).join(', ')}`, + }); showSuccessToast(`Pasted ${activities.length} Activity Directive${pluralize(activities.length)}`); return clonedActivitiesReferences; } } catch (e) { - catchError('Activity Directive Paste Failed', e as Error); + catchError('log', 'Activity Directive Paste Failed', e as Error); showFailureToast('Activity Directive Paste Failed'); } }, @@ -925,7 +929,7 @@ const effects = { ); const { insert_action_definition_one } = data; if (insert_action_definition_one) { - logMessage(`Created action "${name}" in workspace ID=${workspaceId}.`); + logMessage('log', `Created action "${name}" in workspace ID=${workspaceId}.`); showSuccessToast('Action Created Successfully'); return true; } else { @@ -935,7 +939,7 @@ const effects = { throw new Error('Action Creation Failed'); } } catch (e) { - catchError('Action Creation Failed', e as Error); + catchError('log', 'Action Creation Failed', e as Error); showFailureToast('Action Creation Failed'); return false; } @@ -958,6 +962,7 @@ const effects = { const { insert_action_definition_version_one } = data; if (insert_action_definition_version_one) { logMessage( + 'log', `Created version v${insert_action_definition_version_one.revision} for action ID=${actionDefinitionId}.`, ); showSuccessToast('New Version Uploaded'); @@ -969,7 +974,7 @@ const effects = { throw new Error('Version Upload Failed'); } } catch (e) { - catchError('Version Upload Failed', e as Error); + catchError('log', 'Version Upload Failed', e as Error); showFailureToast('Version Upload Failed'); return false; } @@ -1018,16 +1023,16 @@ const effects = { if (actionRunResult !== null) { const actionRunId = actionRunResult.id; - logMessage(`Created action run ID=${actionRunId}.`); + logMessage('log', `Created action run ID=${actionRunId}.`); // send follow-up secrets request directly to action server, containing transient secrets + JWT (in header) await effects.sendActionSecretParameters(workspace, secretParameters, actionRunId, user); - logMessage(`Sent secrets for action run ID=${actionRunId}.`); + logMessage('log', `Sent secrets for action run ID=${actionRunId}.`); return actionRunResult.id; } else { throw Error(`Unable to run action`); } } catch (e) { - catchError('Action Run Creation Failed', e as Error); + catchError('log', 'Action Run Creation Failed', e as Error); showFailureToast('Action Run Creation Failed'); return null; } @@ -1082,7 +1087,7 @@ const effects = { selectedSpanIdStore.set(null); showSuccessToast('Activity Directive Created Successfully'); - logMessage(`Created activity directive "${name}" (ID=${id}).`); + logMessage('log', `Created activity directive "${name}" (ID=${id}).`); } else { throw Error(`Unable to create activity directive "${name}" on plan with ID ${plan.id}`); } @@ -1090,7 +1095,7 @@ const effects = { throw Error('Plan is not defined.'); } } catch (e) { - catchError('Activity Directive Create Failed', e as Error); + catchError('log', 'Activity Directive Create Failed', e as Error); showFailureToast('Activity Directive Create Failed'); } }, @@ -1114,7 +1119,10 @@ const effects = { } tags.forEach(tag => { - logMessage(`Created activity directive tag ID=${tag.tag_id} for activity directive ID=${tag.directive_id}.`); + logMessage( + 'log', + `Created activity directive tag ID=${tag.tag_id} for activity directive ID=${tag.directive_id}.`, + ); }); showSuccessToast('Created Activity Directive Tags'); return affectedRows; @@ -1122,7 +1130,7 @@ const effects = { throw Error('Unable to create activity directive tags'); } } catch (e) { - catchError('Create Activity Directive Tags Failed', e as Error); + catchError('log', 'Create Activity Directive Tags Failed', e as Error); showFailureToast('Create Activity Directive Tags Failed'); return null; } @@ -1152,13 +1160,16 @@ const effects = { if (data.insert_activity_presets_one != null) { const { insert_activity_presets_one: activityPreset } = data; showSuccessToast(`Activity Preset ${activityPreset.name} Created Successfully`); - logMessage(`Created activity preset "${activityPreset.name}" for activity type "${associatedActivityType}".`); + logMessage( + 'log', + `Created activity preset "${activityPreset.name}" for activity type "${associatedActivityType}".`, + ); return activityPreset; } else { throw Error(`Unable to create activity preset "${name}"`); } } catch (e) { - catchError('Activity Preset Create Failed', e as Error); + catchError('log', 'Activity Preset Create Failed', e as Error); showFailureToast('Activity Preset Create Failed'); return null; } @@ -1213,6 +1224,7 @@ const effects = { showSuccessToast('Constraint Created Successfully'); logMessage( + 'log', `Created ${constraintInsertInput.public ? 'public' : 'private'} ${definitionType} constraint "${constraint.name}".`, ); return id; @@ -1220,7 +1232,7 @@ const effects = { throw Error(`Unable to create constraint "${constraintToCreate.name}"`); } } catch (e) { - catchError('Constraint Creation Failed', e as Error); + catchError('log', 'Constraint Creation Failed', e as Error); showFailureToast('Constraint Creation Failed'); return null; } @@ -1266,6 +1278,7 @@ const effects = { if (constraintDefinition != null) { showSuccessToast('New Constraint Revision Created Successfully'); logMessage( + 'log', `Created new constraint revision ${constraintDefinition.revision} for constraint ID=${constraintId}.`, ); return constraintDefinition; @@ -1273,7 +1286,7 @@ const effects = { throw Error(`Unable to create constraint definition for constraint "${constraintId}"`); } } catch (e) { - catchError('Constraint Creation Failed', e as Error); + catchError('log', 'Constraint Creation Failed', e as Error); showFailureToast('Constraint Creation Failed'); return null; } @@ -1297,6 +1310,7 @@ const effects = { const { invocation_id: invocationId } = createConstraintSpec; showSuccessToast('New Constraint Invocation Created Successfully'); logMessage( + 'log', `Created constraint invocation for constraint "${createConstraintSpec.constraint_metadata?.name}" (ID=${createConstraintSpec.constraint_id}).`, ); return invocationId ?? null; @@ -1304,7 +1318,7 @@ const effects = { throw Error('Unable to create a constraint spec invocation'); } } catch (e) { - catchError('Constraint invocation creation failed', e as Error); + catchError('log', 'Constraint invocation creation failed', e as Error); showFailureToast('Constraint Invocation Creation Failed'); return null; } @@ -1324,14 +1338,14 @@ const effects = { const { createSequenceAdaptation: newSequenceAdaptation } = data; if (newSequenceAdaptation != null) { - logMessage(`Created custom adaptation "${adaptation.name}".`); + logMessage('log', `Created custom adaptation "${adaptation.name}".`); return { ...newSequenceAdaptation, type: DictionaryTypes.ADAPTATION }; } else { throw Error('Unable to upload sequence adaptation'); } } } catch (e) { - catchError('Sequence Adaptation Upload Failed', e as Error); + catchError('log', 'Sequence Adaptation Upload Failed', e as Error); } return null; @@ -1351,6 +1365,7 @@ const effects = { if (created !== null) { showSuccessToast('Derivation Group Created Successfully'); logMessage( + 'log', `Created derivation group "${derivationGroup.name}" for source type "${derivationGroup.source_type_name}".`, ); return created as DerivationGroup; @@ -1358,7 +1373,7 @@ const effects = { throw Error(`Unable to create derivation group`); } } catch (e) { - catchError('Derivation Group Create Failed', e as Error); + catchError('log', 'Derivation Group Create Failed', e as Error); showFailureToast('Derivation Group Create Failed'); createDerivationGroupErrorStore.set((e as Error).message); return undefined; @@ -1380,6 +1395,7 @@ const effects = { const { id } = createExpansionRule; showSuccessToast('Expansion Rule Created Successfully'); logMessage( + 'log', `Created expansion rule "${rule.name}" (ID=${createExpansionRule.id}) for parcel ID=${rule.parcel_id}.`, ); savingExpansionRuleStore.set(false); @@ -1388,7 +1404,7 @@ const effects = { throw Error(`Unable to create expansion rule "${rule.name}"`); } } catch (e) { - catchError('Expansion Rule Create Failed', e as Error); + catchError('log', 'Expansion Rule Create Failed', e as Error); showFailureToast('Expansion Rule Create Failed'); savingExpansionRuleStore.set(false); createExpansionRuleErrorStore.set((e as Error).message); @@ -1411,14 +1427,14 @@ const effects = { throw Error('Some expansion rule tags were not successfully created'); } tags.forEach(tag => { - logMessage(`Created expansion rule tag ID=${tag.tag_id} for rule ID=${tag.rule_id}.`); + logMessage('log', `Created expansion rule tag ID=${tag.tag_id} for rule ID=${tag.rule_id}.`); }); return affectedRows; } else { throw Error(`Unable to create expansion rule tags`); } } catch (e) { - catchError('Create Expansion Rule Tags Failed', e as Error); + catchError('log', 'Create Expansion Rule Tags Failed', e as Error); showFailureToast('Create Expansion Rule Tags Failed'); return null; } @@ -1439,14 +1455,14 @@ const effects = { const data = await reqHasura(gql.CREATE_EXPANSION_SEQUENCE, { sequence }, user); if (data.createExpansionSequence != null) { showSuccessToast('Expansion Sequence Created Successfully'); - logMessage(`Created expansion rule sequence "${seqId}" for simulation ID=${simulationDatasetId}.`); + logMessage('log', `Created expansion rule sequence "${seqId}" for simulation ID=${simulationDatasetId}.`); creatingExpansionSequenceStore.set(false); return data.createExpansionSequence.seq_id; } else { throw Error(`Unable to create expansion sequence with ID: "${seqId}"`); } } catch (e) { - catchError('Expansion Sequence Create Failed', e as Error); + catchError('log', 'Expansion Sequence Create Failed', e as Error); showFailureToast('Expansion Sequence Create Failed'); creatingExpansionSequenceStore.set(false); return null; @@ -1484,6 +1500,7 @@ const effects = { const { id } = createExpansionSet; showSuccessToast('Expansion Set Created Successfully'); logMessage( + 'log', `Created expansion set "${createExpansionSet.name ?? 'unnamed'}" (ID=${createExpansionSet.id}) for parcel ID=${parcelId}.`, ); savingExpansionSetStore.set(false); @@ -1492,7 +1509,7 @@ const effects = { throw Error('Unable to create expansion set'); } } catch (e) { - catchError('Expansion Set Create Failed', e as Error); + catchError('log', 'Expansion Set Create Failed', e as Error); showFailureToast('Expansion Set Create Failed'); savingExpansionSetStore.set(false); return null; @@ -1522,6 +1539,7 @@ const effects = { const { createExternalSource: newExternalSource } = reqResponse; showSuccessToast('External Source Created Successfully'); logMessage( + 'log', `Created external source "${newExternalSource.source_type_name}" for derivation group "${derivationGroupName}".`, ); creatingExternalSourceStore.set(false); @@ -1532,7 +1550,7 @@ const effects = { throw new Error(respErrors); } } catch (e) { - catchError('External Source Create Failed', e as Error); + catchError('log', 'External Source Create Failed', e as Error); showFailureToast('External Source Create Failed'); if ((e as Error).message.includes('external_source_type_matches_derivation_group')) { createExternalSourceErrorStore.set('Cannot duplicate derivation groups!'); @@ -1565,7 +1583,7 @@ const effects = { const response = await reqGateway(`/uploadExternalSourceEventTypes`, 'POST', JSON.stringify(body), user, false); if (response?.errors === undefined) { - logMessage(`Created external source and event type.`); + logMessage('log', `Created external source and event type.`); showSuccessToast('External Source & Event Type Created Successfully'); return true; } else { @@ -1575,7 +1593,7 @@ const effects = { } catch (e) { showFailureToast('External Source & Event Type Create Failed'); createExternalSourceEventTypeErrorStore.set((e as Error).message); - catchError('External Source & Event Type Create Failed', e as Error); + catchError('log', 'External Source & Event Type Create Failed', e as Error); return false; } }, @@ -1599,7 +1617,7 @@ const effects = { const file: File = files[0]; const jarId = await effects.uploadFile(file, user); showSuccessToast('Model Uploaded Successfully. Processing model...'); - logMessage(`Uploaded model file "${name}" (v${version}).`); + logMessage('log', `Uploaded model file "${name}" (v${version}).`); if (jarId !== null) { const modelInsertInput: ModelInsertInput = { @@ -1615,7 +1633,7 @@ const effects = { const { id } = createModel; showSuccessToast('Model Created Successfully'); - logMessage(`Created model "${name}" (v${version}).`); + logMessage('log', `Created model "${name}" (v${version}).`); createModelErrorStore.set(null); creatingModelStore.set(false); @@ -1625,7 +1643,7 @@ const effects = { } } } catch (e) { - catchError('Model Create Failed', e as Error); + catchError('log', 'Model Create Failed', e as Error); showFailureToast('Model Create Failed'); createModelErrorStore.set((e as Error).message); creatingModelStore.set(false); @@ -1648,11 +1666,11 @@ const effects = { } const { id } = createParcel; - logMessage(`Created parcel "${parcel.name}" (ID=${id}).`); + logMessage('log', `Created parcel "${parcel.name}" (ID=${id}).`); showSuccessToast('Parcel Created Successfully'); return id; } catch (e) { - catchError('Parcel Create Failed', e as Error); + catchError('log', 'Parcel Create Failed', e as Error); showFailureToast('Parcel Create Failed'); return null; } @@ -1676,6 +1694,7 @@ const effects = { if (insertParcelToParameterDictionary) { insertParcelToParameterDictionary.returning.forEach(entry => { logMessage( + 'log', `Created parcel to parameter dictionary ID=${entry.parameter_dictionary_id} for parcel ID=${entry.parcel_id}.`, ); }); @@ -1686,7 +1705,7 @@ const effects = { return insertParcelToParameterDictionary.returning; } catch (e) { - catchError('Create parcel to parameter dictionaries failed', e as Error); + catchError('log', 'Create parcel to parameter dictionaries failed', e as Error); showFailureToast('Create parcel to parameter dictionaries failed'); } @@ -1750,7 +1769,7 @@ const effects = { }; showSuccessToast('Plan Created Successfully'); - logMessage(`Created plan "${name}" (ID=${id}) with model ID=${modelId}.`); + logMessage('log', `Created plan "${name}" (ID=${id}) with model ID=${modelId}.`); createPlanErrorStore.set(null); creatingPlanStore.set(false); @@ -1759,7 +1778,7 @@ const effects = { throw Error(`Unable to create plan "${name}"`); } } catch (e) { - catchError('Plan Create Failed', e as Error); + catchError('log', 'Plan Create Failed', e as Error); showFailureToast('Plan Create Failed'); createPlanErrorStore.set((e as Error).message); creatingPlanStore.set(false); @@ -1783,6 +1802,7 @@ const effects = { if (duplicatePlan != null) { goto(`${base}/plans/${duplicatePlan.new_plan_id}`); logMessage( + 'log', `Created plan branch "${name}" (ID=${planToBranch.id}) from parent plan "${plan.name}" (ID=${plan.id}).`, ); showSuccessToast('Branch Created Successfully'); @@ -1791,7 +1811,7 @@ const effects = { } } } catch (e) { - catchError('Branch Creation Failed', e as Error); + catchError('log', 'Branch Creation Failed', e as Error); showFailureToast('Branch Creation Failed'); } }, @@ -1818,12 +1838,13 @@ const effects = { user, ); logMessage( + 'log', `Created plan branch request from source plan "${sourcePlan.name}" (ID=${sourcePlan.id}) into target plan "${targetPlan.name}" (ID=${targetPlan.id}).`, ); } } } catch (e) { - catchError('Create plan branch request failed', e as Error); + catchError('log', 'Create plan branch request failed', e as Error); showFailureToast('Plan Branch Create Failed'); } }, @@ -1844,6 +1865,7 @@ const effects = { throw Error('Some plan collaborators were not successfully added'); } logMessage( + 'log', `Added plan collaborator${pluralize(collaborators.length)} "${collaborators.map(c => c.collaborator).join(', ')}" to plan ID=${plan.id}.`, ); showSuccessToast('Plan Collaborators Updated'); @@ -1852,7 +1874,7 @@ const effects = { throw Error('Unable to create plan collaborators'); } } catch (e) { - catchError('Plan Collaborator Create Failed', e as Error); + catchError('log', 'Plan Collaborator Create Failed', e as Error); showFailureToast('Plan Collaborator Create Failed'); return; } @@ -1881,6 +1903,7 @@ const effects = { if (createMergeRequest != null) { const { merge_request_id: mergeRequestId } = createMergeRequest; logMessage( + 'log', `Created plan merge request from source plan "${sourcePlan.name}" (ID=${sourcePlan.id}) into target plan "${targetPlan.name}" (ID=${targetPlan.id}).`, ); showSuccessToast('Merge Request Created Successfully'); @@ -1889,7 +1912,7 @@ const effects = { throw Error('Unable to create a branch merge request'); } } catch (e) { - catchError('Merge Request Create Failed', e as Error); + catchError('log', 'Merge Request Create Failed', e as Error); showFailureToast('Merge Request Create Failed'); return null; } @@ -1906,11 +1929,11 @@ const effects = { if (confirm && value) { const { description, name, plan: planToSnapshot, tags } = value; await effects.createPlanSnapshotHelper(planToSnapshot.id, name, description, tags, user); - logMessage(`Created plan snapshot "${name}".`); + logMessage('log', `Created plan snapshot "${name}".`); showSuccessToast('Snapshot Created Successfully'); } } catch (e) { - catchError('Snapshot Creation Failed', e as Error); + catchError('log', 'Snapshot Creation Failed', e as Error); showFailureToast('Snapshot Creation Failed'); } }, @@ -1971,14 +1994,14 @@ const effects = { showSuccessToast('Plan Snapshot Updated Successfully'); } tags.forEach(tag => { - logMessage(`Created plan snapshot tag ID=${tag.tag_id} for snapshot ID=${tag.snapshot_id}.`); + logMessage('log', `Created plan snapshot tag ID=${tag.tag_id} for snapshot ID=${tag.snapshot_id}.`); }); return affectedRows; } else { throw Error('Unable to create plan snapshot tags'); } } catch (e) { - catchError('Create Plan Snapshot Tags Failed', e as Error); + catchError('log', 'Create Plan Snapshot Tags Failed', e as Error); showFailureToast('Create Plan Snapshot Tags Failed'); return null; } @@ -2007,14 +2030,14 @@ const effects = { showSuccessToast('Plan Updated Successfully'); } tags.forEach(tag => { - logMessage(`Created plan tag ID=${tag.tag_id}.`); + logMessage('log', `Created plan tag ID=${tag.tag_id}.`); }); return affectedRows; } else { throw Error('Unable to create plan tags'); } } catch (e) { - catchError('Create Plan Tags Failed', e as Error); + catchError('log', 'Create Plan Tags Failed', e as Error); showFailureToast('Create Plan Tags Failed'); return null; } @@ -2063,6 +2086,7 @@ const effects = { showSuccessToast('Scheduling Condition Created Successfully'); logMessage( + 'log', `Created ${isPublic ? 'public' : 'private'} scheduling condition "${createSchedulingCondition.name}" (ID=${id}).`, ); return id; @@ -2070,7 +2094,7 @@ const effects = { throw Error(`Unable to create scheduling condition "${name}"`); } } catch (e) { - catchError('Scheduling Condition Creation Failed', e as Error); + catchError('log', 'Scheduling Condition Creation Failed', e as Error); showFailureToast('Scheduling Condition Creation Failed'); return null; } @@ -2102,13 +2126,13 @@ const effects = { const { conditionDefinition } = data; if (conditionDefinition != null) { showSuccessToast('New Scheduling Condition Revision Created Successfully'); - logMessage(`Created scheduling condition definition for condition ID=${conditionId}.`); + logMessage('log', `Created scheduling condition definition for condition ID=${conditionId}.`); return conditionDefinition; } else { throw Error(`Unable to create condition definition for scheduling condition "${conditionId}"`); } } catch (e) { - catchError('Scheduling Condition Creation Failed', e as Error); + catchError('log', 'Scheduling Condition Creation Failed', e as Error); showFailureToast('Scheduling Condition Creation Failed'); return null; } @@ -2167,6 +2191,7 @@ const effects = { showSuccessToast('Scheduling Goal Created Successfully'); logMessage( + 'log', `Created ${isPublic ? 'public' : 'private'} scheduling goal "${createSchedulingGoal.name}" (ID=${createSchedulingGoal.id}).`, ); return id; @@ -2174,7 +2199,7 @@ const effects = { throw Error(`Unable to create scheduling goal "${name}"`); } } catch (e) { - catchError('Scheduling Goal Creation Failed', e as Error); + catchError('log', 'Scheduling Goal Creation Failed', e as Error); showFailureToast('Scheduling Goal Creation Failed'); return null; } @@ -2218,14 +2243,14 @@ const effects = { ); const { goalDefinition } = data; if (goalDefinition != null) { - logMessage(`Created ${definitionType} scheduling goal definition for goal ID=${goalId}.`); + logMessage('log', `Created ${definitionType} scheduling goal definition for goal ID=${goalId}.`); showSuccessToast('New Scheduling Goal Revision Created Successfully'); return goalDefinition; } else { throw Error(`Unable to create goal definition for scheduling goal "${goalId}"`); } } catch (e) { - catchError('Scheduling Goal Creation Failed', e as Error); + catchError('log', 'Scheduling Goal Creation Failed', e as Error); showFailureToast('Scheduling Goal Creation Failed'); return null; } @@ -2249,13 +2274,16 @@ const effects = { if (createSchedulingSpecGoal != null) { const { specification_id: specificationId } = createSchedulingSpecGoal; showSuccessToast('New Scheduling Goal Invocation Created Successfully'); - logMessage(`Created scheduling goal plan specification ID=${specificationId} for goal ID=${specGoal.goal_id}.`); + logMessage( + 'log', + `Created scheduling goal plan specification ID=${specificationId} for goal ID=${specGoal.goal_id}.`, + ); return specificationId; } else { throw Error('Unable to create a scheduling spec goal invocation'); } } catch (e) { - catchError('Scheduling Goal Invocation Creation Failed', e as Error); + catchError('log', 'Scheduling Goal Invocation Creation Failed', e as Error); showFailureToast('Scheduling Goal Invocation Creation Failed'); return null; } @@ -2276,10 +2304,10 @@ const effects = { user, ); const { createSchedulingSpec: newSchedulingSpec } = data; - logMessage(`Created scheduling plan specification ID=${newSchedulingSpec?.id}.`); + logMessage('log', `Created scheduling plan specification ID=${newSchedulingSpec?.id}.`); return newSchedulingSpec; } catch (e) { - catchError('Create scheduling plan specification failed', e as Error); + catchError('log', 'Create scheduling plan specification failed', e as Error); return null; } }, @@ -2311,13 +2339,13 @@ const effects = { if (createSequenceFilter != null) { showSuccessToast('Sequence Filter Created Successfully'); - logMessage(`Created sequence filter for sequence "${seqName}".`); + logMessage('log', `Created sequence filter for sequence "${seqName}".`); return result.createSequenceFilter?.id; } else { throw Error('Create Sequence Filter Failed'); } } catch (e) { - catchError('Create Sequence Filter Failed', e as Error); + catchError('log', 'Create Sequence Filter Failed', e as Error); showFailureToast('Create Sequence Filter Failed'); } return undefined; @@ -2353,6 +2381,7 @@ const effects = { if (insertSequenceTemplateOne !== null) { logMessage( + 'log', `Created ${language} sequence template "${name}" for activity type "${activityType}" for parcel ID=${parcelId}.`, ); showSuccessToast('Sequence Template Created Successfully'); @@ -2360,7 +2389,7 @@ const effects = { throw Error('Create Sequence Template Failed'); } } catch (e) { - catchError('Create Sequence Template Failed', e as Error); + catchError('log', 'Create Sequence Template Failed', e as Error); showFailureToast('Create Sequence Template Failed'); } }, @@ -2388,14 +2417,14 @@ const effects = { ); if (newTemplate != null) { - logMessage(`Created simulation template "${name}" (ID=${newTemplate.id}).`); + logMessage('log', `Created simulation template "${name}" (ID=${newTemplate.id}).`); showSuccessToast(`Simulation Template ${name} Created Successfully`); return newTemplate; } else { throw Error(`Unable to create simulation template "${name}"`); } } catch (e) { - catchError('Simulation Template Create Failed', e as Error); + catchError('log', 'Simulation Template Create Failed', e as Error); showFailureToast('Simulation Template Create Failed'); return null; } @@ -2414,7 +2443,7 @@ const effects = { if (notify) { showSuccessToast('Tag Created Successfully'); } - logMessage(`Created tag "${insertTagsOne.name}" (ID=${insertTagsOne.id}).`); + logMessage('log', `Created tag "${insertTagsOne.name}" (ID=${insertTagsOne.id}).`); createTagErrorStore.set(null); return insertTagsOne; } else { @@ -2422,7 +2451,7 @@ const effects = { } } catch (e) { createTagErrorStore.set((e as Error).message); - catchError('Create Tags Failed', e as Error); + catchError('log', 'Create Tags Failed', e as Error); showFailureToast('Create Tags Failed'); return null; } @@ -2450,14 +2479,14 @@ const effects = { showSuccessToast('Tags Created Successfully'); } returning.forEach(tag => { - logMessage(`Created tag "${tag.name}" (ID=${tag.id}).`); + logMessage('log', `Created tag "${tag.name}" (ID=${tag.id}).`); }); return returning; } else { throw Error('Unable to create tags'); } } catch (e) { - catchError('Create Tags Failed', e as Error); + catchError('log', 'Create Tags Failed', e as Error); showFailureToast('Create Tags Failed'); return null; } @@ -2481,14 +2510,14 @@ const effects = { viewStore.update(() => newView); setQueryParam(SearchParameters.VIEW_ID, `${newView.id}`); showSuccessToast('View Created Successfully'); - logMessage(`Created view "${name}" (ID=${newView.id}).`); + logMessage('log', `Created view "${name}" (ID=${newView.id}).`); return true; } else { throw Error(`Unable to create view "${viewInsertInput.name}"`); } } } catch (e) { - catchError('View Create Failed', e as Error); + catchError('log', 'View Create Failed', e as Error); showFailureToast('View Create Failed'); } @@ -2515,6 +2544,7 @@ const effects = { if (newWorkspaceId != null) { showSuccessToast('Workspace Created Successfully'); logMessage( + 'log', `Created ${name ? `workspace "${name}"` : 'unnamed workspace'} (ID=${newWorkspaceId}) in ${location} for parcel ID=${parcelId}.`, ); return newWorkspaceId; @@ -2522,7 +2552,7 @@ const effects = { throw Error(`Unable to create workspace at "${location}"`); } } catch (e) { - catchError('Workspace Create Failed', e as Error); + catchError('log', 'Workspace Create Failed', e as Error); showFailureToast('Workspace Create Failed'); } @@ -2549,6 +2579,7 @@ const effects = { throw Error('Some workspace collaborators were not successfully added'); } logMessage( + 'log', `Added workspace collaborator${pluralize(collaborators.length)} "${collaborators.map(c => c.collaborator).join(', ')}" to workspace ID=${workspace.id}.`, ); showSuccessToast('Workspace Collaborators Updated'); @@ -2557,7 +2588,7 @@ const effects = { throw Error('Unable to create workspace collaborators'); } } catch (e) { - catchError('Workspace Collaborator Create Failed', e as Error); + catchError('log', 'Workspace Collaborator Create Failed', e as Error); showFailureToast('Workspace Collaborator Create Failed'); return; } @@ -2578,7 +2609,7 @@ const effects = { return effects.deleteActivityDirectives([id], plan, user); } catch (e) { - catchError('Activity Directive Delete Failed', e as Error); + catchError('log', 'Activity Directive Delete Failed', e as Error); } return false; @@ -2602,13 +2633,13 @@ const effects = { ); if (data.delete_activity_directive_tags_by_pk != null) { showSuccessToast('Activity Directive Updated Successfully'); - logMessage(`Removed tag ID=${tagId} from activity directive ID=${directiveId}.`); + logMessage('log', `Removed tag ID=${tagId} from activity directive ID=${directiveId}.`); return data.delete_activity_directive_tags_by_pk.tag_id; } else { throw Error('Unable to delete activity directive tag'); } } catch (e) { - catchError('Delete Activity Directive Tag Failed', e as Error); + catchError('log', 'Delete Activity Directive Tag Failed', e as Error); showFailureToast('Delete Activity Directive Tag Failed'); return null; } @@ -2800,14 +2831,13 @@ const effects = { } showSuccessToast('Activity Directives Deleted Successfully'); - logMessage( - `Deleted ${ids.length} activity directive${pluralize(ids.length)}.`, - `ID${pluralize(ids.length)}: ${ids.join(', ')}`, - ); + logMessage('log', `Deleted ${ids.length} activity directive${pluralize(ids.length)}.`, { + details: `ID${pluralize(ids.length)}: ${ids.join(', ')}`, + }); return true; } } catch (e) { - catchError('Activity Directives Delete Failed', e as Error); + catchError('log', 'Activity Directives Delete Failed', e as Error); showFailureToast('Activity Directives Delete Failed'); } @@ -2829,7 +2859,7 @@ const effects = { if (confirm) { const data = await reqHasura<{ id: number }>(gql.DELETE_ACTIVITY_PRESET, { id: activityPreset.id }, user); if (data.deleteActivityPreset != null) { - logMessage(`Deleted activity preset "${activityPreset.name}" (ID=${activityPreset.id}).`); + logMessage('log', `Deleted activity preset "${activityPreset.name}" (ID=${activityPreset.id}).`); showSuccessToast('Activity Preset Deleted Successfully'); return true; } else { @@ -2837,7 +2867,7 @@ const effects = { } } } catch (e) { - catchError('Activity Preset Delete Failed', e as Error); + catchError('log', 'Activity Preset Delete Failed', e as Error); showFailureToast('Activity Preset Delete Failed'); } @@ -2859,7 +2889,7 @@ const effects = { if (confirm) { const data = await reqHasura<{ id: number }>(gql.DELETE_CHANNEL_DICTIONARY, { id }, user); if (data.deleteChannelDictionary != null) { - logMessage(`Deleted channel dictionary ID=${id}.`); + logMessage('log', `Deleted channel dictionary ID=${id}.`); showSuccessToast('Channel Dictionary Deleted Successfully'); channelDictionariesStore.filterValueById(id); } else { @@ -2867,7 +2897,7 @@ const effects = { } } } catch (e) { - catchError('Channel Dictionary Delete Failed', e as Error); + catchError('log', 'Channel Dictionary Delete Failed', e as Error); showFailureToast('Channel Dictionary Delete Failed'); } }, @@ -2887,7 +2917,7 @@ const effects = { if (confirm) { const data = await reqHasura<{ id: number }>(gql.DELETE_COMMAND_DICTIONARY, { id }, user); if (data.deleteCommandDictionary != null) { - logMessage(`Deleted command dictionary ID=${id}.`); + logMessage('log', `Deleted command dictionary ID=${id}.`); showSuccessToast('Command Dictionary Deleted Successfully'); commandDictionariesStore.filterValueById(id); } else { @@ -2895,7 +2925,7 @@ const effects = { } } } catch (e) { - catchError('Command Dictionary Delete Failed', e as Error); + catchError('log', 'Command Dictionary Delete Failed', e as Error); showFailureToast('Command Dictionary Delete Failed'); } }, @@ -2915,7 +2945,7 @@ const effects = { if (confirm) { const data = await reqHasura<{ id: number }>(gql.DELETE_CONSTRAINT_METADATA, { id: constraint.id }, user); if (data.deleteConstraintMetadata != null) { - logMessage(`Deleted constraint "${constraint.name}" (ID=${constraint.id}).`); + logMessage('log', `Deleted constraint "${constraint.name}" (ID=${constraint.id}).`); showSuccessToast('Constraint Deleted Successfully'); return true; } else { @@ -2923,7 +2953,7 @@ const effects = { } } } catch (e) { - catchError('Constraint Delete Failed', e as Error); + catchError('log', 'Constraint Delete Failed', e as Error); showFailureToast('Constraint Delete Failed'); } @@ -2948,13 +2978,13 @@ const effects = { ); if (deleteConstraintPlanSpecifications !== null) { - logMessage(`Deleted constraint invocations IDs=${constraintInvocationIdsToDelete.join(', ')}.`); + logMessage('log', `Deleted constraint invocations IDs=${constraintInvocationIdsToDelete.join(', ')}.`); showSuccessToast(`Constraints Updated Successfully`); } else { throw Error('Unable to update the constraint specifications for the plan'); } } catch (e) { - catchError('Constraint Plan Specifications Update Failed', e as Error); + catchError('log', 'Constraint Plan Specifications Update Failed', e as Error); showFailureToast('Constraint Plan Specifications Update Failed'); } }, @@ -2980,13 +3010,13 @@ const effects = { if (data.deleteDerivationGroup === null) { throw Error('Unable to delete derivation group'); } else { - logMessage(`Deleted derivation groups "${derivationGroupNames.join(', ')}".`); + logMessage('log', `Deleted derivation groups "${derivationGroupNames.join(', ')}".`); showSuccessToast('Derivation Group Deleted Successfully'); } } } } catch (e) { - catchError('Derivation Group Deletion Failed', e as Error); + catchError('log', 'Derivation Group Deletion Failed', e as Error); showFailureToast('Derivation Group Deletion Failed'); } }, @@ -3024,14 +3054,14 @@ const effects = { const sourceDissociation = data.planDerivationGroupLink?.returning[0]; // If the return was null, do nothing - only act on success or non-null if (sourceDissociation) { - logMessage(`Deleted derivation group "${derivation_group_name}" for plan ID=${plan.id}.`); + logMessage('log', `Deleted derivation group "${derivation_group_name}" for plan ID=${plan.id}.`); showSuccessToast('Derivation Group Disassociated Successfully'); } } else { throw Error('Plan is not defined.'); } } catch (e) { - catchError('Derivation Group De-linking Failed', e as Error); + catchError('log', 'Derivation Group De-linking Failed', e as Error); showFailureToast('Derivation Group De-linking Failed'); derivationGroupPlanLinkErrorStore.set((e as Error).message); } @@ -3053,7 +3083,7 @@ const effects = { const data = await reqHasura(gql.DELETE_EXPANSION_RULE, { id: rule.id }, user); if (data.deleteExpansionRule != null) { - logMessage(`Deleted expansion rule "${rule.name}" (ID=${rule.id}).`); + logMessage('log', `Deleted expansion rule "${rule.name}" (ID=${rule.id}).`); showSuccessToast('Expansion Rule Deleted Successfully'); return true; } else { @@ -3061,7 +3091,7 @@ const effects = { } } } catch (e) { - catchError('Expansion Rule Delete Failed', e as Error); + catchError('log', 'Expansion Rule Delete Failed', e as Error); showFailureToast('Expansion Rule Delete Failed'); } @@ -3083,14 +3113,14 @@ const effects = { if (deleteExpansionRuleTags != null) { const { affected_rows: affectedRows } = deleteExpansionRuleTags; tagIds.forEach(tagId => { - logMessage(`Removed tag ID=${tagId} from expansion rule ID=${ruleId}.`); + logMessage('log', `Removed tag ID=${tagId} from expansion rule ID=${ruleId}.`); }); return affectedRows; } else { throw Error('Unable to delete expansion rule tags'); } } catch (e) { - catchError('Delete Expansion Rule Tags Failed', e as Error); + catchError('log', 'Delete Expansion Rule Tags Failed', e as Error); showFailureToast('Delete Expansion Rule Tags Failed'); return null; } @@ -3112,14 +3142,17 @@ const effects = { const { seq_id: seqId, simulation_dataset_id: simulationDatasetId } = sequence; const data = await reqHasura(gql.DELETE_EXPANSION_SEQUENCE, { seqId, simulationDatasetId }, user); if (data.deleteExpansionSequence != null) { - logMessage(`Deleted expansion sequence ID=${seqId} from simulation dataset ID=${simulationDatasetId}.`); + logMessage( + 'log', + `Deleted expansion sequence ID=${seqId} from simulation dataset ID=${simulationDatasetId}.`, + ); showSuccessToast('Expansion Sequence Deleted Successfully'); } else { throw Error(`Unable to delete expansion sequence with ID: "${seqId}"`); } } } catch (e) { - catchError('Expansion Sequence Delete Failed', e as Error); + catchError('log', 'Expansion Sequence Delete Failed', e as Error); showFailureToast('Expansion Sequence Delete Failed'); } }, @@ -3144,6 +3177,7 @@ const effects = { ); if (data.expansionSequence != null) { logMessage( + 'log', `Removed expansion sequence in simulation dataset ID=${simulationDatasetId} from activity directive ID=${simulatedActivityId}.`, ); showSuccessToast('Expansion Sequence Deleted From Activity Successfully'); @@ -3154,7 +3188,7 @@ const effects = { ); } } catch (e) { - catchError('Delete Expansion Sequence From Activity Failed', e as Error); + catchError('log', 'Delete Expansion Sequence From Activity Failed', e as Error); showFailureToast('Delete Expansion Sequence From Activity Failed'); return false; } @@ -3175,7 +3209,7 @@ const effects = { if (confirm) { const data = await reqHasura<{ id: number }>(gql.DELETE_EXPANSION_SET, { id: set.id }, user); if (data.deleteExpansionSet != null) { - logMessage(`Deleted expansion set "${set.name}" (ID=${set.id}).`); + logMessage('log', `Deleted expansion set "${set.name}" (ID=${set.id}).`); showSuccessToast('Expansion Set Deleted Successfully'); return true; } else { @@ -3185,7 +3219,7 @@ const effects = { return false; } catch (e) { - catchError('Expansion Set Delete Failed', e as Error); + catchError('log', 'Expansion Set Delete Failed', e as Error); showFailureToast('Expansion Set Delete Failed'); return false; } @@ -3219,13 +3253,14 @@ const effects = { throw Error('Unable to delete external event type'); } logMessage( + 'log', `Deleted external event type${pluralize(externalEventTypes.length)} "${externalEventTypes.join(', ')}".`, ); showSuccessToast('External Event Type Deleted Successfully'); } } } catch (e) { - catchError('External Event Type Deletion Failed', e as Error); + catchError('log', 'External Event Type Deletion Failed', e as Error); showFailureToast('External Event Type Deletion Failed'); } }, @@ -3293,13 +3328,14 @@ const effects = { } showSuccessToast('External Source Deleted Successfully'); logMessage( + 'log', `Deleted external source${pluralize(externalSources.length)} "${externalSources.map(s => s.source_type_name).join(', ')}".`, ); return true; } } } catch (e) { - catchError('External Source Deletion Failed', e as Error); + catchError('log', 'External Source Deletion Failed', e as Error); showFailureToast('External Source Deletion Failed'); return false; } @@ -3336,6 +3372,7 @@ const effects = { throw Error('Unable to delete external source type'); } else { logMessage( + 'log', `Deleted external source type${pluralize(externalSourceTypes.length)} "${externalSourceTypes.join(', ')}".`, ); showSuccessToast('External Source Type Deletion Successful'); @@ -3343,7 +3380,7 @@ const effects = { } } } catch (e) { - catchError('External Source Type Deletion Failed', e as Error); + catchError('log', 'External Source Type Deletion Failed', e as Error); showFailureToast('External Source Type Deletion Failed'); } }, @@ -3351,10 +3388,10 @@ const effects = { async deleteFile(id: number, user: User | null): Promise { try { await reqGateway(`/file/${id}`, 'DELETE', null, user, false); - logMessage(`Deleted file ID=${id}.`); + logMessage('log', `Deleted file ID=${id}.`); return true; } catch (e) { - catchError(`Delete file ID=${id} failed.`, e as Error); + catchError('log', `Delete file ID=${id} failed.`, e as Error); return false; } }, @@ -3377,14 +3414,14 @@ const effects = { const data = await reqHasura<{ id: number }>(gql.DELETE_MODEL, { id }, user); if (data.deleteModel != null) { showSuccessToast('Model Deleted Successfully'); - logMessage(`Deleted model "${model.name}" (ID=${model.id}).`); + logMessage('log', `Deleted model "${model.name}" (ID=${model.id}).`); modelsStore.filterValueById(id); } else { throw Error(`Unable to delete model "${model.name}"`); } } } catch (e) { - catchError('Model Delete Failed', e as Error); + catchError('log', 'Model Delete Failed', e as Error); showFailureToast('Model Delete Failed'); } }, @@ -3404,7 +3441,7 @@ const effects = { if (confirm) { const data = await reqHasura<{ id: number }>(gql.DELETE_PARAMETER_DICTIONARY, { id }, user); if (data.deleteParameterDictionary != null) { - logMessage(`Deleted parameter dictionary ID=${id}.`); + logMessage('log', `Deleted parameter dictionary ID=${id}.`); showSuccessToast('Parameter Dictionary Deleted Successfully'); parameterDictionariesStore.filterValueById(id); } else { @@ -3412,7 +3449,7 @@ const effects = { } } } catch (e) { - catchError('Parameter Dictionary Delete Failed', e as Error); + catchError('log', 'Parameter Dictionary Delete Failed', e as Error); showFailureToast('Parameter Dictionary Delete Failed'); } }, @@ -3436,14 +3473,14 @@ const effects = { throw Error(`Unable to delete parcel "${parcel.name}"`); } - logMessage(`Deleted parcel "${parcel.name}" (ID=${parcel.id}).`); + logMessage('log', `Deleted parcel "${parcel.name}" (ID=${parcel.id}).`); showSuccessToast('Parcel Deleted Successfully'); return true; } return false; } catch (e) { - catchError('Parcel Delete Failed', e as Error); + catchError('log', 'Parcel Delete Failed', e as Error); showFailureToast('Parcel Delete Failed'); return false; } @@ -3478,6 +3515,7 @@ const effects = { parcelToParameterDictionariesToDelete.forEach(association => { logMessage( + 'log', `Deleted association between parcel ID=${association.parcel_id} and parameter dictionary ID=${association.parameter_dictionary_id}.`, ); }); @@ -3488,7 +3526,7 @@ const effects = { throw Error('Unable to delete parcel to dictionary associations'); } } catch (e) { - catchError('Delete parcel to dictionary associations failed', e as Error); + catchError('log', 'Delete parcel to dictionary associations failed', e as Error); showFailureToast('Delete parcel to dictionary associations failed'); return null; } @@ -3510,7 +3548,7 @@ const effects = { const data = await reqHasura(gql.DELETE_PLAN, { id: plan.id }, user); if (data.deletePlan != null) { showSuccessToast('Plan Deleted Successfully'); - logMessage(`Deleted plan "${plan.name}" (ID=${plan.id}).`); + logMessage('log', `Deleted plan "${plan.name}" (ID=${plan.id}).`); return true; } else { throw Error(`Unable to delete the plan with "${plan.name}"`); @@ -3519,7 +3557,7 @@ const effects = { return false; } catch (e) { - catchError('Plan Delete Failed', e as Error); + catchError('log', 'Plan Delete Failed', e as Error); showFailureToast('Plan Delete Failed'); return false; } @@ -3533,14 +3571,14 @@ const effects = { const data = await reqHasura(gql.DELETE_PLAN_COLLABORATOR, { collaborator, planId: plan.id }, user); if (data.deletePlanCollaborator != null) { - logMessage(`Removed collaborator "${collaborator}" from plan ID=${plan.id}.`); + logMessage('log', `Removed collaborator "${collaborator}" from plan ID=${plan.id}.`); showSuccessToast('Plan Collaborator Removed Successfully'); return true; } else { throw Error('Unable to remove plan collaborator'); } } catch (e) { - catchError('Remove Plan Collaborator Failed', e as Error); + catchError('log', 'Remove Plan Collaborator Failed', e as Error); showFailureToast('Remove Plan Collaborator Failed'); return false; } @@ -3561,7 +3599,7 @@ const effects = { if (confirm) { const data = await reqHasura(gql.DELETE_PLAN_SNAPSHOT, { snapshot_id: snapshot.snapshot_id }, user); if (data.deletePlanSnapshot != null) { - logMessage(`Deleted plan snapshot "${snapshot.snapshot_name}" (ID=${snapshot.snapshot_id}).`); + logMessage('log', `Deleted plan snapshot "${snapshot.snapshot_name}" (ID=${snapshot.snapshot_id}).`); showSuccessToast('Plan Snapshot Deleted Successfully'); return true; } else { @@ -3571,7 +3609,7 @@ const effects = { return false; } catch (e) { - catchError('Delete Plan Snapshot Failed', e as Error); + catchError('log', 'Delete Plan Snapshot Failed', e as Error); showFailureToast('Delete Plan Snapshot Failed'); return false; } @@ -3585,14 +3623,14 @@ const effects = { const data = await reqHasura<{ tag_id: number }>(gql.DELETE_PLAN_TAG, { plan_id: planId, tag_id: tagId }, user); if (data.delete_plan_tags_by_pk != null) { - logMessage(`Removed tag ID=${tagId} from plan ID=${planId}.`); + logMessage('log', `Removed tag ID=${tagId} from plan ID=${planId}.`); showSuccessToast('Plan Updated Successfully'); return data.delete_plan_tags_by_pk.tag_id; } else { throw Error('Unable to delete plan tag'); } } catch (e) { - catchError('Delete Plan Tag Failed', e as Error); + catchError('log', 'Delete Plan Tag Failed', e as Error); showFailureToast('Delete Plan Tag Failed'); return null; } @@ -3617,7 +3655,7 @@ const effects = { user, ); if (data.deleteSchedulingConditionMetadata != null) { - logMessage(`Deleted scheduling condition "${condition.name}" (ID=${condition.id}).`); + logMessage('log', `Deleted scheduling condition "${condition.name}" (ID=${condition.id}).`); showSuccessToast('Scheduling Condition Deleted Successfully'); return true; } else { @@ -3627,7 +3665,7 @@ const effects = { return false; } } catch (e) { - catchError('Scheduling Condition Delete Failed', e as Error); + catchError('log', 'Scheduling Condition Delete Failed', e as Error); showFailureToast('Scheduling Condition Delete Failed'); return false; } @@ -3649,7 +3687,7 @@ const effects = { const data = await reqHasura<{ id: number }>(gql.DELETE_SCHEDULING_GOAL_METADATA, { id: goal.id }, user); if (data.deleteSchedulingGoalMetadata) { - logMessage(`Deleted scheduling goal "${goal.name}" (ID=${goal.id}).`); + logMessage('log', `Deleted scheduling goal "${goal.name}" (ID=${goal.id}).`); showSuccessToast('Scheduling Goal Deleted Successfully'); return true; } else { @@ -3659,7 +3697,7 @@ const effects = { return false; } } catch (e) { - catchError('Scheduling Goal Delete Failed', e as Error); + catchError('log', 'Scheduling Goal Delete Failed', e as Error); showFailureToast('Scheduling Goal Delete Failed'); return false; } @@ -3686,6 +3724,7 @@ const effects = { if (deleteConstraintPlanSpecifications !== null) { logMessage( + 'log', `Deleted ${goalInvocationIdsToDelete.length} scheduling goal invocation${pluralize(goalInvocationIdsToDelete.length)} from scheduling specification ID=${schedulingSpecificationId}.`, ); showSuccessToast(`Scheduling Goals Updated Successfully`); @@ -3693,7 +3732,7 @@ const effects = { throw Error('Unable to update the scheduling goal specifications for the plan'); } } catch (e) { - catchError('Scheduling Goal Plan Specifications Update Failed', e as Error); + catchError('log', 'Scheduling Goal Plan Specifications Update Failed', e as Error); showFailureToast('Scheduling Goal Plan Specifications Update Failed'); } }, @@ -3716,12 +3755,12 @@ const effects = { throw Error(`Unable to delete sequence adaptation with ID: "${id}"`); } - logMessage(`Deleted sequence adaptation ID=${id}.`); + logMessage('log', `Deleted sequence adaptation ID=${id}.`); showSuccessToast('Sequence Adaptation Deleted Successfully'); sequenceAdaptationsStore.filterValueById(id); } } catch (e) { - catchError('Sequence Adaptation Delete Failed', e as Error); + catchError('log', 'Sequence Adaptation Delete Failed', e as Error); showFailureToast('Sequence Adaptation Delete Failed'); } }, @@ -3745,14 +3784,14 @@ const effects = { user, ); if (data.deleteSequenceFilters != null) { - logMessage(`Deleted sequence filters IDs=${sequenceFilterIds.join(', ')}.`); + logMessage('log', `Deleted sequence filters IDs=${sequenceFilterIds.join(', ')}.`); showSuccessToast('Sequence Filters Deleted Successfully'); } else { throw Error(`Unable to delete sequence filters with IDs: "${sequenceFilterIds}"`); } } } catch (e) { - catchError('Sequence Filter Delete Failed', e as Error); + catchError('log', 'Sequence Filter Delete Failed', e as Error); showFailureToast('Sequence Filter Delete Failed'); } }, @@ -3779,14 +3818,14 @@ const effects = { const { delete_sequence_template_by_pk: deleteSequenceTemplate } = data; if (deleteSequenceTemplate !== null) { - logMessage(`Deleted sequence template "${sequenceTemplate.name}" (ID=${sequenceTemplate.id}).`); + logMessage('log', `Deleted sequence template "${sequenceTemplate.name}" (ID=${sequenceTemplate.id}).`); showSuccessToast('Sequence Template Deleted Successfully'); } else { throw Error(`Unable to delete sequence template with ID: "${sequenceTemplate.id}"`); } } } catch (e) { - catchError('Sequence Template Deletion Failed', e as Error); + catchError('log', 'Sequence Template Deletion Failed', e as Error); showFailureToast('Sequence Template Deletion Failed'); } }, @@ -3814,7 +3853,7 @@ const effects = { user, ); if (data.deleteSimulationTemplate != null) { - logMessage(`Deleted simulation template ID=${simulationTemplate.id}.`); + logMessage('log', `Deleted simulation template ID=${simulationTemplate.id}.`); showSuccessToast('Simulation Template Deleted Successfully'); return true; } else { @@ -3822,7 +3861,7 @@ const effects = { } } } catch (e) { - catchError('Simulation Template Delete Failed', e as Error); + catchError('log', 'Simulation Template Delete Failed', e as Error); showFailureToast('Simulation Template Delete Failed'); } @@ -3836,11 +3875,11 @@ const effects = { } await reqHasura<{ id: number }>(gql.DELETE_TAG, { id: tag.id }, user); - logMessage(`Deleted tag "${tag.name}" (ID=${tag.id}).`); + logMessage('log', `Deleted tag "${tag.name}" (ID=${tag.id}).`); showSuccessToast('Tag Deleted Successfully'); return true; } catch (e) { - catchError('Delete Tag Failed', e as Error); + catchError('log', 'Delete Tag Failed', e as Error); showFailureToast('Delete Tag Failed'); return false; } @@ -3949,7 +3988,7 @@ const effects = { if (confirm) { const data = await reqHasura<{ id: number }>(gql.DELETE_VIEW, { id: view.id }, user); if (data.deletedView != null) { - logMessage(`Deleted view "${view.name}" (ID=${view.id}).`); + logMessage('log', `Deleted view "${view.name}" (ID=${view.id}).`); showSuccessToast('View Deleted Successfully'); return true; } else { @@ -3958,7 +3997,7 @@ const effects = { } } catch (e) { showFailureToast('View Delete Failed'); - catchError('View delete failed', e as Error); + catchError('log', 'View delete failed', e as Error); } return false; @@ -3992,7 +4031,7 @@ const effects = { throw new Error(`Some views were not successfully deleted: ${leftoverViewIds.join(', ')}`); } views.forEach(view => { - logMessage(`Deleted view "${view.name}" (ID=${view.id}).`); + logMessage('log', `Deleted view "${view.name}" (ID=${view.id}).`); }); showSuccessToast('Views Deleted Successfully'); return true; @@ -4002,7 +4041,7 @@ const effects = { } } catch (e) { showFailureToast('View Deletes Failed'); - catchError('View deletes failed', e as Error); + catchError('log', 'View deletes failed', e as Error); } return false; @@ -4022,13 +4061,13 @@ const effects = { if (confirm) { await WorkspaceApi.deleteWorkspace(workspace.id, user); - logMessage(`Deleted workspace "${workspace.name}" (ID=${workspace.id}).`); + logMessage('log', `Deleted workspace "${workspace.name}" (ID=${workspace.id}).`); showSuccessToast('Workspace Deleted Successfully'); return true; } } catch (e) { showFailureToast('Workspace Delete Failed'); - catchError('Workspace delete failed', e as Error); + catchError('log', 'Workspace delete failed', e as Error); } return false; @@ -4046,14 +4085,14 @@ const effects = { user, ); if (data.deleteWorkspaceCollaborator != null) { - logMessage(`Removed collaborator "${collaborator}" from workspace ID=${workspace.id}.`); + logMessage('log', `Removed collaborator "${collaborator}" from workspace ID=${workspace.id}.`); showSuccessToast('Workspace Collaborator Removed Successfully'); return true; } else { throw Error('Unable to remove workspace collaborator'); } } catch (e) { - catchError('Remove Workspace Collaborator Failed', e as Error); + catchError('log', 'Remove Workspace Collaborator Failed', e as Error); showFailureToast('Remove Workspace Collaborator Failed'); return false; } @@ -4099,13 +4138,14 @@ const effects = { } logMessage( + 'log', `Deleted ${originalNodes.length} ${typeDisplayString.toLowerCase()} in "${workspace.name}" (ID=${workspace.id}).`, ); showSuccessToast(`Workspace ${typeDisplayString} Deleted Successfully`); } return confirm; } catch (e) { - catchError(`Workspace ${typeDisplayString} was unable to be deleted`, e as Error); + catchError('log', `Workspace ${typeDisplayString} was unable to be deleted`, e as Error); showFailureToast(`Workspace ${typeDisplayString} Deletion Failed`); } @@ -4143,7 +4183,7 @@ const effects = { if (updatedView != null) { const { name: updatedName, updated_at } = updatedView; applyViewUpdate({ name: updatedName, updated_at }); - logMessage(`Updated view "${view.name}" (ID=${view.id}).`); + logMessage('log', `Updated view "${view.name}" (ID=${view.id}).`); showSuccessToast('View Edited Successfully'); return true; } else { @@ -4151,7 +4191,7 @@ const effects = { } } } catch (e) { - catchError('View Edit Failed', e as Error); + catchError('log', 'View Edit Failed', e as Error); showFailureToast('View Edit Failed'); } @@ -4172,15 +4212,15 @@ const effects = { planExpansionStatusStore.set(Status.Complete); showSuccessToast('Plan Expanded Successfully'); logMessage( + 'log', `Expanded plan with expansion set ID=${expansionSetId} for simulation ID=${simulationDatasetId}.`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); } else { throw Error('Unable to expand plan'); } } catch (e) { - catchError('Plan Expansion Failed', e as Error); + catchError('log', 'Plan Expansion Failed', e as Error); planExpansionStatusStore.set(Status.Failed); showFailureToast('Plan Expansion Failed'); } @@ -4214,15 +4254,15 @@ const effects = { sequenceTemplateExpansionStatus.set(Status.Complete); showSuccessToast('Sequence Templating Succeeded'); logMessage( + 'log', `Expanded sequence templates for sequences IDs=${seqIds.join(', ')} for simulation ID=${simulationDatasetId}.`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); } else { throw Error('Sequence Templating Failed'); } } catch (e) { - catchError('Sequence Templating Failed', e as Error); + catchError('log', 'Sequence Templating Failed', e as Error); sequenceTemplateExpansionStatus.set(Status.Failed); sequenceTemplateExpansionError.set(e as string); showFailureToast('Sequence Templating Failed'); @@ -4235,13 +4275,13 @@ const effects = { const data = await reqHasura(query, { actionRunId }, user); const { actionRun } = data; if (actionRun != null) { - logMessage(`Retrieved action run ID=${actionRunId}`); + logMessage('log', `Retrieved action run ID=${actionRunId}`); return actionRun; } else { throw Error('Unable to retrieve activity run'); } } catch (e) { - catchError('Failed to get action run', e as Error); + catchError('log', 'Failed to get action run', e as Error); return null; } }, @@ -4255,16 +4295,16 @@ const effects = { const { activity_directives: activityDirectives } = data; if (activityDirectives != null) { logMessage( + 'log', `Retrieved ${activityDirectives.length} activity directive${pluralize(activityDirectives.length)} for plan ID=${planId}`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); return activityDirectives; } else { throw Error('No activities returned'); } } catch (e) { - catchError('Failed to retrieve activities for plan', e as Error); + catchError('log', 'Failed to retrieve activities for plan', e as Error); return []; } }, @@ -4302,13 +4342,13 @@ const effects = { } return revision; // fallback if sourcePlan is undefined }); - logMessage(`Retrieved activity directive changelog for activity ID=${activityId}.`); + logMessage('log', `Retrieved activity directive changelog for activity ID=${activityId}.`); return updatedRevisions; } else { throw Error('Activity directive changelog not found'); } } catch (e) { - catchError('Failed to retrieve activity directive changelog', e as Error); + catchError('log', 'Failed to retrieve activity directive changelog', e as Error); return []; } }, @@ -4321,16 +4361,16 @@ const effects = { const { activity_type: activityTypes } = data; if (activityTypes != null) { logMessage( + 'log', `Retrieved ${activityTypes.length} activity type${pluralize(activityTypes.length)} for model ID=${modelId}.`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); return activityTypes; } else { throw Error('No activity types found'); } } catch (e) { - catchError('Failed to retrieve activity types', e as Error); + catchError('log', 'Failed to retrieve activity types', e as Error); return []; } }, @@ -4348,13 +4388,13 @@ const effects = { ); const { activity_types: activityTypes } = data; if (activityTypes != null) { - logMessage(`Retrieved expansion rule activity types for model ID=${modelId}.`); + logMessage('log', `Retrieved expansion rule activity types for model ID=${modelId}.`); return activityTypes; } else { throw Error('No activity types found'); } } catch (e) { - catchError('Failed to retrieve expansion rule activity types', e as Error); + catchError('log', 'Failed to retrieve expansion rule activity types', e as Error); return []; } } else { @@ -4367,11 +4407,11 @@ const effects = { const data = await reqHasura(convertToQuery(gql.SUB_CONSTRAINT), { id }, user); const { constraint } = data; if (constraint) { - logMessage(`Retrieved constraint "${constraint.name}" (ID=${id}).`); + logMessage('log', `Retrieved constraint "${constraint.name}" (ID=${id}).`); } return constraint; } catch (e) { - catchError('Failed to retrieve constraint', e as Error); + catchError('log', 'Failed to retrieve constraint', e as Error); return null; } }, @@ -4397,12 +4437,12 @@ const effects = { ); const { constraintProcedureEffectiveArgumentsBulk } = data; if (constraintProcedureEffectiveArgumentsBulk !== null) { - logMessage(`Retrieved effective arguments for ${constraints.length} procedural constraints.`); + logMessage('log', `Retrieved effective arguments for ${constraints.length} procedural constraints.`); return constraintProcedureEffectiveArgumentsBulk; } return []; } catch (e) { - catchError('Failed to retrieve procedural constraint effective arguments', e as Error); + catchError('log', 'Failed to retrieve procedural constraint effective arguments', e as Error); return []; } }, @@ -4424,12 +4464,12 @@ const effects = { ); const { effectiveActivityArgumentsBulk } = data; if (effectiveActivityArgumentsBulk !== null) { - logMessage(`Retrieved default activity arguments for model ID=${modelId}.`); + logMessage('log', `Retrieved default activity arguments for model ID=${modelId}.`); return effectiveActivityArgumentsBulk; } return []; } catch (e) { - catchError('Failed to retrieve default activity arguments', e as Error); + catchError('log', 'Failed to retrieve default activity arguments', e as Error); return []; } }, @@ -4449,10 +4489,10 @@ const effects = { user, ); const { effectiveModelArguments } = data; - logMessage(`Retrieved effective model arguments for model ID=${modelId}.`); + logMessage('log', `Retrieved effective model arguments for model ID=${modelId}.`); return effectiveModelArguments; } catch (e) { - catchError('Failed to retrieve effective model arguments', e as Error); + catchError('log', 'Failed to retrieve effective model arguments', e as Error); return null; } }, @@ -4489,13 +4529,13 @@ const effects = { }); } logMessage( + 'log', `Retrieved ${simulationEvents.length} simulation event${pluralize(simulationEvents.length)} for simulation ID=${datasetId}.`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); return simulationEvents; } catch (e) { - catchError('Failed to retrieve simulation events', e as Error); + catchError('log', 'Failed to retrieve simulation events', e as Error); return []; } }, @@ -4505,11 +4545,11 @@ const effects = { const data = await reqHasura(gql.GET_EXPANSION_RULE, { id }, user); const { expansionRule } = data; if (expansionRule) { - logMessage(`Retrieved expansion rule "${expansionRule.name}" (ID=${id}).`); + logMessage('log', `Retrieved expansion rule "${expansionRule.name}" (ID=${id}).`); } return expansionRule; } catch (e) { - catchError('Failed to get expansion rule', e as Error); + catchError('log', 'Failed to get expansion rule', e as Error); return null; } }, @@ -4523,7 +4563,7 @@ const effects = { const data = await reqHasura(gql.GET_EXPANSION_RUN, { id }, user, signal); const { expansionRun } = data; if (expansionRun) { - logMessage(`Retrieved expansion run (ID=${id}).`); + logMessage('log', `Retrieved expansion run (ID=${id}).`); return { aborted: false, expansionRun }; } else { return { aborted: false, expansionRun: null }; @@ -4532,7 +4572,7 @@ const effects = { if ((e as Error).name === 'AbortError') { return { aborted: true, expansionRun: null }; } - catchError('Failed to get expansion run', e as Error); + catchError('log', 'Failed to get expansion run', e as Error); showFailureToast('Expansion Run Details Retrieval Failed'); return { aborted: false, expansionRun: null }; } @@ -4543,13 +4583,13 @@ const effects = { const data = await reqHasura(gql.GET_EXPANSION_RUNS, {}, user); const { expansionRuns } = data; if (expansionRuns) { - logMessage(`Retrieved ${expansionRuns.length} expansion run${pluralize(expansionRuns.length)}.`); + logMessage('log', `Retrieved ${expansionRuns.length} expansion run${pluralize(expansionRuns.length)}.`); return expansionRuns; } else { return []; } } catch (e) { - catchError('Failed to get expansion runs', e as Error); + catchError('log', 'Failed to get expansion runs', e as Error); showFailureToast('Expansion Runs Retrieval Failed'); return []; } @@ -4574,6 +4614,7 @@ const effects = { if (expansionSequence) { const { seq_id: seqId } = expansionSequence; logMessage( + 'log', `Retrieved expansion sequence "${seqId}" for simulated activity ID=${simulatedActivityId} in simulation ID=${simulationDatasetId}.`, ); return seqId; @@ -4581,7 +4622,7 @@ const effects = { return null; } } catch (e) { - catchError('Failed to retrieve expansion sequence ID', e as Error); + catchError('log', 'Failed to retrieve expansion sequence ID', e as Error); return null; } }, @@ -4604,13 +4645,13 @@ const effects = { const { expanded_sequences } = data; if (expanded_sequences != null && expanded_sequences.length === 1) { const { expanded_sequence } = expanded_sequences[0]; - logMessage(`Retrieved expansion sequence SeqJson for sequence "${seqId}".`); + logMessage('log', `Retrieved expansion sequence SeqJson for sequence "${seqId}".`); return JSON.stringify(expanded_sequence, null, 2); } else { throw Error(`Unable to get expansion sequence seq json for seq ID "${seqId}"`); } } catch (e) { - catchError('Failed to get expansion sequence seq json', e as Error); + catchError('log', 'Failed to get expansion sequence seq json', e as Error); return null; } }, @@ -4646,10 +4687,10 @@ const effects = { throw Error('Unable to gather all external event types for the source'); } - logMessage(`Retrieved ${types.length} external event type${pluralize(types.length)}.`); + logMessage('log', `Retrieved ${types.length} external event type${pluralize(types.length)}.`); return types; } catch (e) { - catchError('Failed to retrieve external event types', e as Error); + catchError('log', 'Failed to retrieve external event types', e as Error); return []; } }, @@ -4687,6 +4728,7 @@ const effects = { } } logMessage( + 'log', `Retrieved ${eventTypes.length} external event type${pluralize(eventTypes.length)} from external source "${externalSourceKey}" in derivation group "${externalSourceDerivationGroup}".`, ); return eventTypes; @@ -4694,7 +4736,7 @@ const effects = { throw Error('Unable to retrieve external event types for source'); } } catch (e) { - catchError('Failed to retrieve external event types for source', e as Error); + catchError('log', 'Failed to retrieve external event types for source', e as Error); showFailureToast('External Event Type Retrieval Failed'); return []; } @@ -4738,11 +4780,12 @@ const effects = { }); } logMessage( + 'log', `Retrieved ${externalEvents.length} external event${pluralize(externalEvents.length)} from external source "${externalSourceKey}" in derivation group "${externalSourceDerivationGroup}".`, ); return externalEvents; } catch (e) { - catchError('Failed to retrieve external events.', e as Error); + catchError('log', 'Failed to retrieve external events.', e as Error); showFailureToast('External Events Retrieval Failed'); return []; } @@ -4755,13 +4798,13 @@ const effects = { ): Promise<{ aborted: boolean; file: string | null }> { try { const file = await reqGateway(`/file/${fileId}`, 'GET', null, user, true, signal, false); - logMessage(`Retrieved file "${fileId}".`); + logMessage('log', `Retrieved file "${fileId}".`); return { aborted: false, file }; } catch (e) { if ((e as Error).name === 'AbortError') { return { aborted: true, file: null }; } else { - catchError(`Failed to get file with id: ${fileId}`, e as Error); + catchError('log', `Failed to get file with id: ${fileId}`, e as Error); showFailureToast(`Failed to get file with id: ${fileId}`); return { aborted: false, file: null }; } @@ -4778,12 +4821,12 @@ const effects = { if (data) { const { name } = data[0]; const cleanedName = name.replace(/(?:-[a-zA-Z0-9]+){2}(\.[a-z]+)?$/, '$1'); - logMessage(`Retrieved filename "${cleanedName}" for file "${fileId}".`); + logMessage('log', `Retrieved filename "${cleanedName}" for file "${fileId}".`); return cleanedName; } return null; } catch (e) { - catchError(`Failed to get filename for file id: ${fileId}`, e as Error); + catchError('log', `Failed to get filename for file id: ${fileId}`, e as Error); showFailureToast(`Failed to get filename for file id: ${fileId}`); return null; } @@ -4795,13 +4838,13 @@ const effects = { const data = await reqHasura(query, { id: modelId }, user); const { model } = data; if (model != null) { - logMessage(`Retrieved model "${model.name}" v${model.version} (ID=${modelId})`); + logMessage('log', `Retrieved model "${model.name}" v${model.version} (ID=${modelId})`); return model; } else { throw Error('No model found'); } } catch (e) { - catchError('Failed to retrieve model', e as Error); + catchError('log', 'Failed to retrieve model', e as Error); return null; } }, @@ -4812,13 +4855,13 @@ const effects = { const data = await reqHasura(query, {}, user); const { models = [] } = data; if (models != null) { - logMessage(`Retrieved ${models.length} model${pluralize(models.length)}`); + logMessage('log', `Retrieved ${models.length} model${pluralize(models.length)}`); return models; } else { throw Error('Models not found'); } } catch (e) { - catchError('Failed to retrieve models', e as Error); + catchError('log', 'Failed to retrieve models', e as Error); return []; } }, @@ -4828,11 +4871,11 @@ const effects = { const data = await reqHasura(gql.GET_PARCEL, { id }, user); const { parcel } = data; if (parcel) { - logMessage(`Retrieved parcel "${parcel.name}" (ID=${parcel.id}).`); + logMessage('log', `Retrieved parcel "${parcel.name}" (ID=${parcel.id}).`); } return parcel; } catch (e) { - catchError('Failed to retrieve parcel', e as Error); + catchError('log', 'Failed to retrieve parcel', e as Error); return null; } }, @@ -4857,11 +4900,11 @@ const effects = { throw new Error(`Unable to find channel dictionary with id ${channelDictionaryId}`); } else { const [{ parsed_json: parsedJson }] = channelDictionary; - logMessage(`Retrieved channel dictionary ID=${channelDictionaryId}.`); + logMessage('log', `Retrieved channel dictionary ID=${channelDictionaryId}.`); return parsedJson; } } catch (e) { - catchError('Failed to retrieve channel dictionary', e as Error); + catchError('log', 'Failed to retrieve channel dictionary', e as Error); return null; } }, @@ -4886,11 +4929,11 @@ const effects = { throw new Error(`Unable to find command dictionary with id ${commandDictionaryId}`); } else { const [{ parsed_json: parsedJson }] = commandDictionary; - logMessage(`Retrieved command dictionary ID=${commandDictionaryId}.`); + logMessage('log', `Retrieved command dictionary ID=${commandDictionaryId}.`); return parsedJson; } } catch (e) { - catchError('Failed to retrieve command dictionary', e as Error); + catchError('log', 'Failed to retrieve command dictionary', e as Error); return null; } }, @@ -4915,11 +4958,11 @@ const effects = { throw new Error(`Unable to find parameter dictionary with id ${parameterDictionaryId}`); } else { const [{ parsed_json: parsedJson }] = parameterDictionary; - logMessage(`Retrieved parameter dictionary ID=${parameterDictionaryId}.`); + logMessage('log', `Retrieved parameter dictionary ID=${parameterDictionaryId}.`); return parsedJson; } } catch (e) { - catchError('Failed to retrieve parameter dictionary', e as Error); + catchError('log', 'Failed to retrieve parameter dictionary', e as Error); return null; } }, @@ -4937,13 +4980,13 @@ const effects = { end_time_doy: getDoyTimeFromInterval(start_time, duration), start_time_doy: getDoyTime(new Date(start_time)), }; - logMessage(`Retrieved plan "${plan.name}" (ID=${id}).`, '', performance.now() - startTime); + logMessage('log', `Retrieved plan "${plan.name}" (ID=${id}).`, { duration: performance.now() - startTime }); return plan; } else { return null; } } catch (e) { - catchError('Failed to retrieve plan', e as Error); + catchError('log', 'Failed to retrieve plan', e as Error); return null; } }, @@ -4955,7 +4998,7 @@ const effects = { const { simulation } = data; if (simulation) { - logMessage(`Retrieved latest simulation for plan ID=${planId}`); + logMessage('log', `Retrieved latest simulation for plan ID=${planId}`); return simulation[0]; } @@ -4972,6 +5015,7 @@ const effects = { const { conflictingActivities } = data; if (conflictingActivities != null) { logMessage( + 'log', `Retrieved ${conflictingActivities.length} conflicting activit${conflictingActivities.length === 1 ? 'y' : 'ies'} for plan merge request ID=${mergeRequestId}.`, ); return conflictingActivities; @@ -4979,7 +5023,7 @@ const effects = { throw Error('Unable to retrieve conflicting activities'); } } catch (e) { - catchError('Failed to retrieve conflicting activities', e as Error); + catchError('log', 'Failed to retrieve conflicting activities', e as Error); return []; } }, @@ -4999,6 +5043,7 @@ const effects = { const { nonConflictingActivities } = data; if (nonConflictingActivities != null) { logMessage( + 'log', `Retrieved ${nonConflictingActivities.length} non-conflicting activit${nonConflictingActivities.length === 1 ? 'y' : 'ies'} for plan merge request ID=${mergeRequestId}.`, ); return nonConflictingActivities; @@ -5006,7 +5051,7 @@ const effects = { throw Error('Unable to retrieve non-conflicting activities'); } } catch (e) { - catchError('Failed to retrieve non-conflicting activities', e as Error); + catchError('log', 'Failed to retrieve non-conflicting activities', e as Error); return []; } }, @@ -5018,13 +5063,13 @@ const effects = { const { merge_requests: mergeRequests } = data; if (mergeRequests != null) { const [mergeRequest] = mergeRequests; // Query uses 'limit: 1' so merge_requests.length === 1. - logMessage(`Retrieved in-progress plan merge request ID=${mergeRequest.id}.`); + logMessage('log', `Retrieved in-progress plan merge request ID=${mergeRequest.id}.`); return mergeRequest; } else { throw Error('Unable to get merge requests in progress'); } } catch (e) { - catchError('Failed to retrieve in-progress plan merge request', e as Error); + catchError('log', 'Failed to retrieve in-progress plan merge request', e as Error); return null; } }, @@ -5036,13 +5081,13 @@ const effects = { const { plan } = data; if (plan != null) { const { revision } = plan; - logMessage(`Retrieved latest plan revision ID ${revision}.`); + logMessage('log', `Retrieved latest plan revision ID ${revision}.`); return revision; } else { throw Error('Plan revision not found'); } } catch (e) { - catchError('Failed to get plan revision', e as Error); + catchError('log', 'Failed to get plan revision', e as Error); return null; } }, @@ -5061,6 +5106,7 @@ const effects = { if (planSnapshotActivityDirectives) { logMessage( + 'log', `Retrieved ${planSnapshotActivityDirectives.length} plan snapshot activity directive${pluralize(planSnapshotActivityDirectives.length)}.`, ); return planSnapshotActivityDirectives.map(({ snapshot_id: _snapshotId, ...planSnapshotActivityDirective }) => { @@ -5073,7 +5119,7 @@ const effects = { return null; } } catch (e) { - catchError('Unable to retrieve plan snapshot activity directives', e as Error); + catchError('log', 'Unable to retrieve plan snapshot activity directives', e as Error); return null; } }, @@ -5086,11 +5132,11 @@ const effects = { return []; } if (plan.tags.length) { - logMessage(`Retrieved ${plan.tags.length} plan tag${pluralize(plan.tags.length)}.`); + logMessage('log', `Retrieved ${plan.tags.length} plan tag${pluralize(plan.tags.length)}.`); } return plan.tags.map(({ tag }) => tag); } catch (e) { - catchError('Unable to retrieve plan tags', e as Error); + catchError('log', 'Unable to retrieve plan tags', e as Error); return []; } }, @@ -5104,9 +5150,9 @@ const effects = { }; const { models, plans } = data; logMessage( + 'log', `Retrieved ${models.length} model${pluralize(models.length)} and ${plans.length} plan${pluralize(plans.length)}.`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); return { @@ -5120,7 +5166,7 @@ const effects = { }), }; } catch (e) { - catchError('Unable to retrieve plans and models', e as Error); + catchError('log', 'Unable to retrieve plans and models', e as Error); return { models: [], plans: [] }; } }, @@ -5142,16 +5188,16 @@ const effects = { const { resource_types: resourceTypes } = data; if (resourceTypes != null) { logMessage( + 'log', `Retrieved ${typeof limit === 'number' ? 'initial set of ' : 'all'} ${resourceTypes.length} resource type${pluralize(resourceTypes.length)} for model ID=${modelId}.`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); return resourceTypes; } else { throw Error('No resource types found'); } } catch (e) { - catchError('Unable to retrieve resource types', e as Error); + catchError('log', 'Unable to retrieve resource types', e as Error); return []; } }, @@ -5205,6 +5251,7 @@ const effects = { uniqueProfiles.forEach(profile => { logMessage( + 'log', `Retrieved external profile ${profile.name} (${profile.profile_segments} segment${profile.profile_segments.length}) for simulation ID=${simulationDatasetId}.`, ); }); @@ -5220,7 +5267,7 @@ const effects = { let aborted = false; const error = e as Error; if (error.name !== 'AbortError') { - catchError('Unable to retrieve external profiles ', error); + catchError('log', 'Unable to retrieve external profiles ', error); showFailureToast('Failed to retrieve external profiles'); aborted = true; } @@ -5241,7 +5288,7 @@ const effects = { const actionPermissions = permissions.action_permissions ?? []; const functionPermissions = permissions.function_permissions ?? []; const workspacePermissions = permissions.workspace_permissions ?? []; - logMessage(`Retrieved role permissions for user ID=${user?.id}.`); + logMessage('log', `Retrieved role permissions for user ID=${user?.id}.`); return { ...actionPermissions, ...functionPermissions, @@ -5255,7 +5302,7 @@ const effects = { return {}; } catch (e) { - catchError('Unable to retrieve role permissions', e as Error); + catchError('log', 'Unable to retrieve role permissions', e as Error); return null; } }, @@ -5271,12 +5318,12 @@ const effects = { const { condition } = data; if (condition) { - logMessage(`Retrieved scheduling condition "${condition.name}" (ID=${condition.id}).`); + logMessage('log', `Retrieved scheduling condition "${condition.name}" (ID=${condition.id}).`); return convertResponseToMetadata(condition, tags); } return condition; } catch (e) { - catchError('Unable to retrieve scheduling condition', e as Error); + catchError('log', 'Unable to retrieve scheduling condition', e as Error); return null; } }, @@ -5292,12 +5339,12 @@ const effects = { const { goal } = data; if (goal) { - logMessage(`Retrieved scheduling goal "${goal.name}" (ID=${goal.id}).`); + logMessage('log', `Retrieved scheduling goal "${goal.name}" (ID=${goal.id}).`); return convertResponseToMetadata(goal, tags); } return goal; } catch (e) { - catchError('Unable to retrieve scheduling goal', e as Error); + catchError('log', 'Unable to retrieve scheduling goal', e as Error); return null; } }, @@ -5323,12 +5370,12 @@ const effects = { ); const { schedulingProcedureEffectiveArgumentsBulk } = data; if (schedulingProcedureEffectiveArgumentsBulk !== null) { - logMessage(`Retrieved effective arguments for ${goals.length} procedural scheduling goals.`); + logMessage('log', `Retrieved effective arguments for ${goals.length} procedural scheduling goals.`); return schedulingProcedureEffectiveArgumentsBulk; } return []; } catch (e) { - catchError('Failed to retrieve procedural scheduling goal effective arguments', e as Error); + catchError('log', 'Failed to retrieve procedural scheduling goal effective arguments', e as Error); return []; } }, @@ -5347,10 +5394,10 @@ const effects = { user, ); const { scheduling_specification_conditions: schedulingSpecificationConditions } = data; - logMessage(`Retrieved scheduling conditions specification for condition ID=${conditionId}.`); + logMessage('log', `Retrieved scheduling conditions specification for condition ID=${conditionId}.`); return schedulingSpecificationConditions; } catch (e) { - catchError('Unable to retrieve scheduling conditions specification for condition', e as Error); + catchError('log', 'Unable to retrieve scheduling conditions specification for condition', e as Error); return null; } } else { @@ -5370,10 +5417,10 @@ const effects = { user, ); const { scheduling_specification_goals: schedulingSpecificationGoals } = data; - logMessage(`Retrieved scheduling goals specification for goal ID=${goalId}.`); + logMessage('log', `Retrieved scheduling goals specification for goal ID=${goalId}.`); return schedulingSpecificationGoals; } catch (e) { - catchError('Unable to retrieve scheduling goals specification for goal', e as Error); + catchError('log', 'Unable to retrieve scheduling goals specification for goal', e as Error); return null; } } else { @@ -5394,11 +5441,14 @@ const effects = { const { sequence_adaptation: sequenceAdaptation } = data; if (sequenceAdaptation && sequenceAdaptation.length > 0) { - logMessage(`Retrieved sequence adaptation "${sequenceAdaptation[0].name}" (ID=${sequenceAdaptationId}).`); + logMessage( + 'log', + `Retrieved sequence adaptation "${sequenceAdaptation[0].name}" (ID=${sequenceAdaptationId}).`, + ); return sequenceAdaptation[0]; } } catch (e) { - catchError('Unable to retrieve sequence adaptation', e as Error); + catchError('log', 'Unable to retrieve sequence adaptation', e as Error); } return null; @@ -5416,9 +5466,9 @@ const effects = { const { span: spans } = data; if (spans != null) { logMessage( + 'log', `Retrieved ${spans.length} simulated activit${spans.length === 1 ? 'y' : 'ies'} for simulation ID=${datasetId}.`, - '', - performance.now() - startTime, + { duration: performance.now() - startTime }, ); return spans.map(span => { const durationMs = getIntervalInMs(span.duration); @@ -5434,7 +5484,7 @@ const effects = { throw Error('Spans not found'); } } catch (e) { - catchError('Unable to retrieve spans', e as Error); + catchError('log', 'Unable to retrieve spans', e as Error); return []; } }, @@ -5445,13 +5495,13 @@ const effects = { const data = await reqHasura(query, {}, user); const { tags } = data; if (tags != null) { - logMessage(`Retrieved ${tags.length} tag${pluralize(tags.length)}.`); + logMessage('log', `Retrieved ${tags.length} tag${pluralize(tags.length)}.`); return tags; } else { throw Error('Tags not found'); } } catch (e) { - catchError('Unable to retrieve tags', e as Error); + catchError('log', 'Unable to retrieve tags', e as Error); return []; } }, @@ -5476,7 +5526,7 @@ const effects = { const { reason, status, typescriptFiles } = dslTypeScriptResponse; if (status === 'success') { - logMessage(`Retrieved TypeScript activity type "${activityTypeName}".`); + logMessage('log', `Retrieved TypeScript activity type "${activityTypeName}".`); return typescriptFiles; } else { throw new Error(reason); @@ -5485,7 +5535,7 @@ const effects = { throw Error(`Unable to get TypeScript activity type "${activityTypeName}"`); } } catch (e) { - catchError('Unable to retrieve TypeScript activity type', e as Error); + catchError('log', 'Unable to retrieve TypeScript activity type', e as Error); return []; } } else { @@ -5509,7 +5559,7 @@ const effects = { const { reason, status, typescriptFiles } = dslTypeScriptResponse; if (status === 'success') { - logMessage(`Retrieved TypeScript command dictionary "${commandDictionaryId}".`); + logMessage('log', `Retrieved TypeScript command dictionary "${commandDictionaryId}".`); return typescriptFiles; } else { throw new Error(reason); @@ -5518,7 +5568,7 @@ const effects = { throw Error(`Unable to get TypeScript command dictionary with ID: "${commandDictionaryId}"`); } } catch (e) { - catchError('Unable to retrieve TypeScript command dictionary', e as Error); + catchError('log', 'Unable to retrieve TypeScript command dictionary', e as Error); return []; } } else { @@ -5539,7 +5589,7 @@ const effects = { const { reason, status, typescriptFiles } = dslTypeScriptResponse; if (status === 'success') { - logMessage(`Retrieved TypeScript constraint files for model ID=${modelId}.`); + logMessage('log', `Retrieved TypeScript constraint files for model ID=${modelId}.`); return typescriptFiles; } else { throw new Error(reason); @@ -5548,7 +5598,7 @@ const effects = { throw Error('Unable to retrieve TypeScript constraint files'); } } catch (e) { - catchError('Unable to retrieve TypeScript constraint files', e as Error); + catchError('log', 'Unable to retrieve TypeScript constraint files', e as Error); return []; } } else { @@ -5565,7 +5615,7 @@ const effects = { const { reason, status, typescriptFiles } = dslTypeScriptResponse; if (status === 'success') { - logMessage(`Retrieved TypeScript scheduling files for model ID=${modelId}.`); + logMessage('log', `Retrieved TypeScript scheduling files for model ID=${modelId}.`); return typescriptFiles; } else { throw new Error(reason); @@ -5574,7 +5624,7 @@ const effects = { throw Error('Unable to retrieve TypeScript scheduling files'); } } catch (e) { - catchError('Unable to retrieve TypeScript scheduling files', e as Error); + catchError('log', 'Unable to retrieve TypeScript scheduling files', e as Error); return []; } } else { @@ -5592,7 +5642,7 @@ const effects = { const mutationQueries = queries.mutationType?.fields ?? []; const viewQueries = queries.queryType?.fields ?? []; - logMessage(`Retrieved user permissions for "${user?.id ?? 'unknown user'}".`); + logMessage('log', `Retrieved user permissions for "${user?.id ?? 'unknown user'}".`); return [...viewQueries, ...mutationQueries].reduce((queriesMap, permissibleQuery) => { return { ...queriesMap, @@ -5606,7 +5656,7 @@ const effects = { return {}; } catch (e) { - catchError('Unable to retrieve user permissions', e as Error); + catchError('log', 'Unable to retrieve user permissions', e as Error); return null; } }, @@ -5616,11 +5666,11 @@ const effects = { const data = await reqHasura(gql.GET_USER_SEQUENCE, { id }, user); const { userSequence } = data; if (userSequence) { - logMessage(`Retrieved user sequence "${userSequence.name}" (ID=${id}).`); + logMessage('log', `Retrieved user sequence "${userSequence.name}" (ID=${id}).`); } return userSequence; } catch (e) { - catchError('Unable to retrieve user sequence', e as Error); + catchError('log', 'Unable to retrieve user sequence', e as Error); return null; } }, @@ -5630,7 +5680,7 @@ const effects = { const data = await reqHasura(gql.GET_USER_SEQUENCE_FROM_SEQ_JSON, { seqJson }, user); const { sequence } = data; if (sequence != null) { - logMessage(`Retrieved user sequence "${sequence}" from SeqJson ID=${seqJson.id}.`); + logMessage('log', `Retrieved user sequence "${sequence}" from SeqJson ID=${seqJson.id}.`); return sequence; } else { throw Error('Unable to retrieve user sequence'); @@ -5658,7 +5708,7 @@ const effects = { if (getUserSequenceSeqJson != null) { const { errors, seqJson, status } = getUserSequenceSeqJson; - logMessage(`Retrieved user sequence JSON.`); + logMessage('log', `Retrieved user sequence JSON.`); if (status === 'FAILURE') { const [firstError] = errors; const { message } = firstError; @@ -5679,7 +5729,7 @@ const effects = { const versionResponse = await fetch(`${base}/version.json`); return await versionResponse.json(); } catch (e) { - catchError('Unable to retrieve application version', e as Error); + catchError('log', 'Unable to retrieve application version', e as Error); return { branch: 'unknown', commit: 'unknown', @@ -5712,10 +5762,10 @@ const effects = { const data = await reqHasura(gql.GET_VIEW, { id: viewIdAsNumber }, user); const { view: fetchedView } = data; view = fetchedView; - logMessage(`Retrieved view "${view?.name}" (ID=${view?.id}).`); + logMessage('log', `Retrieved view "${view?.name}" (ID=${view?.id}).`); } else if (defaultView !== null && defaultView !== undefined) { view = defaultView; - logMessage(`Using default view.`); + logMessage('log', `Using default view.`); } if (view) { @@ -5727,7 +5777,7 @@ const effects = { // Otherwise perform any needed migrations const { migratedView, error, anyMigrationsApplied } = await applyViewMigrations(view); if (migratedView && anyMigrationsApplied) { - logMessage(`Applied migrations to view "${view.name}".`); + logMessage('log', `Applied migrations to view "${view.name}".`); await effects.updateView( migratedView.id, { definition: migratedView.definition }, @@ -5738,7 +5788,7 @@ const effects = { // If migration failed catch the error and return default view if (!migratedView) { - catchError('Unable to automatically migrate view', error as Error); + catchError('log', 'Unable to automatically migrate view', error as Error); showFailureToast(`Unable to automatically migrate view: ${view.name}`); } else { return migratedView; @@ -5747,7 +5797,7 @@ const effects = { } return generateDefaultView(resourceTypes, externalEventTypes); } catch (e) { - catchError('Unable to retrieve view', e as Error); + catchError('log', 'Unable to retrieve view', e as Error); return null; } }, @@ -5759,13 +5809,13 @@ const effects = { const { workspace } = data; if (workspace) { - logMessage(`Retrieved workspace "${workspace.name}" (ID=${workspaceId}).`); + logMessage('log', `Retrieved workspace "${workspace.name}" (ID=${workspaceId}).`); return workspace; } else { return null; } } catch (e) { - catchError('Unable to retrieve retrieve workspace', e as Error); + catchError('log', 'Unable to retrieve retrieve workspace', e as Error); return null; } }, @@ -5781,13 +5831,15 @@ const effects = { const workspaceContents = await WorkspaceApi.getWorkspaceContents(workspaceId, path, user, withMetadata); if (workspaceContents != null) { - logMessage(`Retrieved workspace contents for workspace ID=${workspaceId}.`, '', performance.now() - startTime); + logMessage('log', `Retrieved workspace contents for workspace ID=${workspaceId}.`, { + duration: performance.now() - startTime, + }); return workspaceContents; } else { throw Error(`Workspace contents not found`); } } catch (e) { - catchError('Unable to retrieve workspace', e as Error); + catchError('log', 'Unable to retrieve workspace', e as Error); showFailureToast('Workspace Retrieval Failed'); } @@ -5799,13 +5851,13 @@ const effects = { const fileContents = await WorkspaceApi.getFileContent(workspaceId, filePath, user); if (fileContents != null) { - logMessage(`Retrieved workspace file "${filePath}" for workspace ID=${workspaceId}.`); + logMessage('log', `Retrieved workspace file "${filePath}" for workspace ID=${workspaceId}.`); return fileContents; } else { throw Error(`Workspace file contents not found`); } } catch (e) { - catchError('Unable to retrieve workspace file', e as Error); + catchError('log', 'Unable to retrieve workspace file', e as Error); showFailureToast('Workspace File Retrieval Failed'); } @@ -5821,13 +5873,13 @@ const effects = { const fileContents = await WorkspaceApi.getFileContentBlob(workspace.id, filePath, user); if (fileContents != null) { - logMessage(`Retrieved workspace file "${filePath}" for workspace ID=${workspace.id}.`); + logMessage('log', `Retrieved workspace file "${filePath}" for workspace ID=${workspace.id}.`); return fileContents; } else { throw Error(`Workspace file contents not found`); } } catch (e) { - catchError('Unable to retrieve workspace file', e as Error); + catchError('log', 'Unable to retrieve workspace file', e as Error); showFailureToast('Workspace File Retrieval Failed'); } @@ -5953,13 +6005,13 @@ const effects = { creatingPlanStore.set(false); if (createdPlan != null) { - logMessage(`Imported plan "${name}".`, '', performance.now() - requestStartTime); + logMessage('log', `Imported plan "${name}".`, { duration: performance.now() - requestStartTime }); return { plan: createdPlan }; } else { throw new Error('Plan import failed'); } } catch (e) { - catchError('Unable to import plan', e as Error); + catchError('log', 'Unable to import plan', e as Error); creatingPlanStore.set(false); return { error: e as Error }; } @@ -5997,6 +6049,7 @@ const effects = { if (createdSequenceTemplate != null) { showSuccessToast('Sequence Template Imported Successfully'); logMessage( + 'log', `Imported ${language} sequence template "${name}" for activity type "${activityType}" for parcel ID=${parcelId}.`, ); return createdSequenceTemplate; @@ -6004,7 +6057,7 @@ const effects = { return null; } catch (e) { - catchError('Unable to import sequence template', e as Error); + catchError('log', 'Unable to import sequence template', e as Error); showFailureToast('Failed To Import Sequence Template'); return null; } @@ -6214,12 +6267,12 @@ const effects = { } showSuccessToast(`Workspace File${fileArray.length > 1 ? 's' : ''} Uploaded Successfully`); - logMessage(`Uploaded ${fileArray.length} workspace file${pluralize(fileArray.length)}.`); + logMessage('log', `Uploaded ${fileArray.length} workspace file${pluralize(fileArray.length)}.`); } return joinPath([cleanedTargetPath, fileArray[0].name]); } } catch (e) { - catchError(`Workspace file upload failed`, e as Error); + catchError('log', `Workspace file upload failed`, e as Error); showFailureToast(`Workspace file upload failed`); } @@ -6255,7 +6308,7 @@ const effects = { throw Error('Simulation update not found'); } } catch (e) { - catchError('Unable to update simulation', e as Error); + catchError('log', 'Unable to update simulation', e as Error); return false; } }, @@ -6281,14 +6334,14 @@ const effects = { const { planExternalSourceLink: sourceAssociation } = data; // If the return was null, do nothing - only act on success or non-null if (sourceAssociation !== null) { - logMessage(`Linked derivation group "${derivationGroupName}" to plan "${plan.name}" (ID=${plan.id}).`); + logMessage('log', `Linked derivation group "${derivationGroupName}" to plan "${plan.name}" (ID=${plan.id}).`); showSuccessToast('Derivation Group Linked Successfully'); } } else { throw Error('Plan is not defined.'); } } catch (e) { - catchError('Derivation Group Linking Failed', e as Error); + catchError('log', 'Derivation Group Linking Failed', e as Error); showFailureToast('Derivation Group Linking Failed'); derivationGroupPlanLinkErrorStore.set((e as Error).message); } @@ -6316,6 +6369,7 @@ const effects = { if (sequence != null) { showSuccessToast('Expansion Sequence Added To Activity Successfully'); logMessage( + 'log', `Added expansion sequence "${seqId}" to simulated activity ID=${simulatedActivityId} for simulation ID=${simulationDatasetId}.`, ); const { seq_id: newSeqId } = sequence; @@ -6324,7 +6378,7 @@ const effects = { return null; } } catch (e) { - catchError('Add Expansion Sequence To Activity Failed', e as Error); + catchError('log', 'Add Expansion Sequence To Activity Failed', e as Error); showFailureToast('Add Expansion Sequence To Activity Failed'); return null; } @@ -6375,7 +6429,7 @@ const effects = { }; } } catch (e) { - catchError('Unable to load view from file', e as Error); + catchError('log', 'Unable to load view from file', e as Error); return { definition: null, errors: [(e as Error).message], @@ -6394,7 +6448,7 @@ const effects = { ); return data; } catch (e) { - catchError('Unable to login', e as Error); + catchError('log', 'Unable to login', e as Error); return { message: 'An unexpected error occurred', success: false, @@ -6407,7 +6461,7 @@ const effects = { try { await showManagePlanConstraintsModal(user); } catch (e) { - catchError('Constraint Unable To Be Applied To Plan', e as Error); + catchError('log', 'Constraint Unable To Be Applied To Plan', e as Error); showFailureToast('Constraint Application Failed'); } }, @@ -6416,7 +6470,7 @@ const effects = { try { await showManagePlanDerivationGroups(user); } catch (e) { - catchError('Derivation Group Unable To Be Modified In Plan', e as Error); + catchError('log', 'Derivation Group Unable To Be Modified In Plan', e as Error); showFailureToast('Derivation Group Modification Failed'); } }, @@ -6425,7 +6479,7 @@ const effects = { try { await showManagePlanSchedulingConditionsModal(user); } catch (e) { - catchError('Scheduling Condition Unable To Be Applied To Plan', e as Error); + catchError('log', 'Scheduling Condition Unable To Be Applied To Plan', e as Error); showFailureToast('Scheduling Condition Application Failed'); } }, @@ -6434,7 +6488,7 @@ const effects = { try { await showManagePlanSchedulingGoalsModal(user); } catch (e) { - catchError('Scheduling Goal Unable To Be Applied To Plan', e as Error); + catchError('log', 'Scheduling Goal Unable To Be Applied To Plan', e as Error); showFailureToast('Scheduling Goal Application Failed'); } }, @@ -6474,6 +6528,7 @@ const effects = { showSuccessToast(`Workspace ${displayString} ${shouldCopy ? 'Copied' : 'Moved'} Successfully`); logMessage( + 'log', `${shouldCopy ? 'Copied' : 'Moved'} workspace ${displayString.toLowerCase()} to "${cleanedTargetPath}".`, ); @@ -6486,7 +6541,7 @@ const effects = { } } } catch (e) { - catchError('Unable to move workspace item', e as Error); + catchError('log', 'Unable to move workspace item', e as Error); showFailureToast((e as Error).message); } @@ -6522,12 +6577,14 @@ const effects = { showSuccessToast(`Workspace ${displayString} ${shouldCopy ? 'Duplicated' : 'Moved'} Successfully`); logMessage( + 'log', `${shouldCopy ? 'Duplicated' : 'Moved'} workspace ${displayString.toLowerCase()} from "${workspace.name}" to "${targetWorkspace.name}".`, ); return cleanedTargetPath; } catch (e) { catchError( + 'log', `Workspace ${displayString.toLowerCase()} unable to be ${shouldCopy ? 'duplicated' : 'moved'}`, e as Error, ); @@ -6551,10 +6608,10 @@ const effects = { await WorkspaceApi.createFolder(workspace.id, folderPath, user); showSuccessToast('Workspace Folder Created Successfully'); - logMessage(`Created new workspace folder "${workspace.id}/${folderPath}".`); + logMessage('log', `Created new workspace folder "${workspace.id}/${folderPath}".`); return folderPath; } catch (e) { - catchError('Workspace folder was unable to be created', e as Error); + catchError('log', 'Workspace folder was unable to be created', e as Error); showFailureToast('Workspace Folder Creation Failed'); } } @@ -6576,11 +6633,11 @@ const effects = { await WorkspaceApi.saveFile(workspace.id, filePath, sequenceDefinition, false, user); showSuccessToast('Workspace File Created Successfully'); - logMessage(`Created new workspace file "${workspace.id}/${filePath}".`); + logMessage('log', `Created new workspace file "${workspace.id}/${filePath}".`); return filePath; } catch (e) { - catchError('Workspace file was unable to be created', e as Error); + catchError('log', 'Workspace file was unable to be created', e as Error); showFailureToast('Workspace File Creation Failed'); } } @@ -6634,7 +6691,7 @@ const effects = { return true; } catch (error) { showFailureToast((error as Error)?.message ?? error); - catchError('Pack Activities Failed', error as Error); + catchError('log', 'Pack Activities Failed', error as Error); return false; } }, @@ -6674,7 +6731,7 @@ const effects = { return true; } catch (error) { showFailureToast((error as Error)?.message ?? error); - catchError('Pack Activities Failed', error as Error); + catchError('log', 'Pack Activities Failed', error as Error); return false; } }, @@ -6696,14 +6753,14 @@ const effects = { user, ); if (data.begin_merge != null) { - logMessage(`Began plan merge ID=${mergeRequestId}.`); + logMessage('log', `Began plan merge ID=${mergeRequestId}.`); return true; } else { throw Error('Unable to begin plan merge'); } } catch (error) { showFailureToast((error as Error)?.message ?? error); - catchError('Begin Merge Failed', error as Error); + catchError('log', 'Begin Merge Failed', error as Error); return false; } }, @@ -6725,14 +6782,14 @@ const effects = { user, ); if (data.cancel_merge != null) { - logMessage(`Canceled plan merge ID=${mergeRequestId}.`); + logMessage('log', `Canceled plan merge ID=${mergeRequestId}.`); showSuccessToast('Canceled Merge Request'); return true; } else { throw Error('Unable to cancel merge request'); } } catch (error) { - catchError('Cancel Merge Request Failed', error as Error); + catchError('log', 'Cancel Merge Request Failed', error as Error); showFailureToast('Cancel Merge Request Failed'); return false; } @@ -6755,14 +6812,14 @@ const effects = { user, ); if (data.commit_merge != null) { - logMessage(`Approved changes for merge request ID=${mergeRequestId}.`); + logMessage('log', `Approved changes for merge request ID=${mergeRequestId}.`); showSuccessToast('Approved Merge Request Changes'); return true; } else { throw Error('Unable to approve merge request'); } } catch (error) { - catchError('Approve Merge Request Changes Failed', error as Error); + catchError('log', 'Approve Merge Request Changes Failed', error as Error); showFailureToast('Approve Merge Request Changes Failed'); return false; } @@ -6785,14 +6842,14 @@ const effects = { user, ); if (data.deny_merge != null) { - logMessage(`Denied changes for merge request ID=${mergeRequestId}.`); + logMessage('log', `Denied changes for merge request ID=${mergeRequestId}.`); showSuccessToast('Denied Merge Request Changes'); return true; } else { throw Error('Unable to deny merge request'); } } catch (error) { - catchError('Deny Merge Request Changes Failed', error as Error); + catchError('log', 'Deny Merge Request Changes Failed', error as Error); showFailureToast('Deny Merge Request Changes Failed'); return false; } @@ -6815,7 +6872,7 @@ const effects = { user, ); if (data.withdraw_merge_request != null) { - logMessage(`Withdrew merge request ID=${mergeRequestId}.`); + logMessage('log', `Withdrew merge request ID=${mergeRequestId}.`); showSuccessToast('Withdrew Merge Request'); return true; } else { @@ -6823,7 +6880,7 @@ const effects = { } } catch (error) { showFailureToast('Withdraw Merge Request Failed'); - catchError('Withdraw Merge Request Failed', error as Error); + catchError('log', 'Withdraw Merge Request Failed', error as Error); return false; } }, @@ -6848,10 +6905,10 @@ const effects = { if (data.set_resolution_bulk == null) { throw Error('Unable to resolve all merge request conflicts'); } - logMessage(`Resolved all conflicts for merge request ID=${mergeRequestId}.`); + logMessage('log', `Resolved all conflicts for merge request ID=${mergeRequestId}.`); } catch (e) { showFailureToast('Resolve All Merge Request Conflicts Failed'); - catchError('Resolve All Merge Request Conflicts Failed', e as Error); + catchError('log', 'Resolve All Merge Request Conflicts Failed', e as Error); } }, @@ -6876,10 +6933,10 @@ const effects = { if (data.set_resolution == null) { throw Error('Unable to resolve merge request conflict'); } - logMessage(`Resolved conflict for activity ID=${activityId} for merge request ID=${mergeRequestId}.`); + logMessage('log', `Resolved conflict for activity ID=${activityId} for merge request ID=${mergeRequestId}.`); } catch (e) { showFailureToast('Resolve Merge Request Conflict Failed'); - catchError('Resolve Merge Request Conflict Failed', e as Error); + catchError('log', 'Resolve Merge Request Conflict Failed', e as Error); } }, @@ -6900,7 +6957,7 @@ const effects = { user, ); if (data.delete_preset_to_directive_by_pk != null) { - logMessage(`Removed preset ID=${presetId} from activity directive ID=${activityDirectiveId}.`); + logMessage('log', `Removed preset ID=${presetId} from activity directive ID=${activityDirectiveId}.`); showSuccessToast('Removed Activity Preset Successfully'); return true; } else { @@ -6909,7 +6966,7 @@ const effects = { ); } } catch (e) { - catchError('Activity Preset Removal Failed', e as Error); + catchError('log', 'Activity Preset Removal Failed', e as Error); showFailureToast('Activity Preset Removal Failed'); return false; } @@ -6934,11 +6991,14 @@ const effects = { await WorkspaceApi.moveFile(workspace.id, originalPath, `./${cleanedTargetPath}`, false, false, user); showSuccessToast(`Workspace ${typeString} Renamed Successfully`); - logMessage(`Renamed workspace ${typeString.toLowerCase()} from "${originalPath}" to "${cleanedTargetPath}".`); + logMessage( + 'log', + `Renamed workspace ${typeString.toLowerCase()} from "${originalPath}" to "${cleanedTargetPath}".`, + ); return cleanedTargetPath; } } catch (e) { - catchError(`Workspace ${typeString.toLowerCase()} was unable to be renamed`, e as Error); + catchError('log', `Workspace ${typeString.toLowerCase()} was unable to be renamed`, e as Error); showFailureToast(`Workspace ${typeString} Rename Failed`); } @@ -6963,14 +7023,14 @@ const effects = { ); if (data.restoreActivityFromChangelog != null) { - logMessage(`Restored activity ID=${activityId} to revision ${revision} from changelog.`); + logMessage('log', `Restored activity ID=${activityId} to revision ${revision} from changelog.`); showSuccessToast('Restored Activity from Changelog'); return true; } else { throw Error(`Unable to restore activity revision ${revision} from changelog`); } } catch (e) { - catchError('Restoring Activity From Changelog Failed', e as Error); + catchError('log', 'Restoring Activity From Changelog Failed', e as Error); showFailureToast('Restoring Activity from Changelog Failed'); return false; } @@ -7002,7 +7062,7 @@ const effects = { ); if (data.restore_from_snapshot != null) { showSuccessToast('Plan Snapshot Restored Successfully'); - logMessage(`Restored plan snapshot "${snapshot.snapshot_name}" (ID=${snapshot.snapshot_id}).`); + logMessage('log', `Restored plan snapshot "${snapshot.snapshot_name}" (ID=${snapshot.snapshot_id}).`); goto(`${base}/plans/${snapshot.plan_id}`); return true; @@ -7011,7 +7071,7 @@ const effects = { } } } catch (e) { - catchError('Restore Plan Snapshot Failed', e as Error); + catchError('log', 'Restore Plan Snapshot Failed', e as Error); showFailureToast('Restore Plan Snapshot Failed'); return false; } @@ -7050,13 +7110,13 @@ const effects = { } showSuccessToast('Model Extraction Retriggered Successfully'); - logMessage(`Retriggered model extraction for model ID=${id}.`); + logMessage('log', `Retriggered model extraction for model ID=${id}.`); return data; } else { throw Error(`Unable to retrigger model extraction with ID: "${id}"`); } } catch (e) { - catchError('Model Extraction Failed', e as Error); + catchError('log', 'Model Extraction Failed', e as Error); showFailureToast('Model Extraction Failed'); } return null; @@ -7086,13 +7146,14 @@ const effects = { if (confirm && value) { const { id } = value; logMessage( + 'log', `Ran action "${actionDefinition.name}" (ID=${actionDefinition.id}) on sequence${pluralize(workspaceSequences.length)} "${workspaceSequences.map(w => w.name).join(', ')}" in workspace ID=${actionDefinition.workspace_id}.`, ); return id; } return null; } catch (e) { - catchError('Run Action Failed', e as Error); + catchError('log', 'Run Action Failed', e as Error); showFailureToast('Run Action Failed'); return null; } @@ -7103,14 +7164,15 @@ const effects = { await WorkspaceApi.saveFile(workspaceId, filePath, fileContent, true, user); showSuccessToast('Workspace File Saved Successfully'); - logMessage(`Saved workspace file "${filePath}".`); + logMessage('log', `Saved workspace file "${filePath}".`); } catch (e) { - catchError('Workspace file was unable to be saved', e as Error); + catchError('log', 'Workspace file was unable to be saved', e as Error); showFailureToast('Workspace File Save Failed'); } }, async schedule(analysisOnly: boolean = false, plan: Plan | null, user: User | null): Promise { + clearConsoleEntries('scheduling'); try { if (plan) { if ( @@ -7140,7 +7202,7 @@ const effects = { if (schedule) { const { reason, analysisId } = schedule; if (reason) { - catchSchedulingError(reason); + catchError('scheduling', '', reason); showFailureToast(`Scheduling ${analysisOnly ? 'Analysis ' : ''}Failed`); return; } @@ -7171,15 +7233,13 @@ const effects = { } } showSuccessToast(`Scheduling ${analysisOnly ? 'Analysis ' : ''}Complete`); - logMessage( - `Completed scheduling${analysisOnly ? ' analysis' : ''}.`, - '', - performance.now() - startTime, - ); + logMessage('log', `Completed scheduling${analysisOnly ? ' analysis' : ''}.`, { + duration: performance.now() - startTime, + }); unsubscribe(); } else if (matchingRequest.status === 'failed') { if (matchingRequest.reason) { - catchSchedulingError(matchingRequest.reason); + catchError('scheduling', '', matchingRequest.reason); } showFailureToast(`Scheduling ${analysisOnly ? 'Analysis ' : ''}Failed`); unsubscribe(); @@ -7200,7 +7260,7 @@ const effects = { throw Error('Plan is not defined.'); } } catch (e) { - catchError('Unable to schedule', e as Error); + catchError('scheduling', 'Unable to schedule', e as Error); showFailureToast('Scheduling failed'); } }, @@ -7222,7 +7282,7 @@ const effects = { }; await reqActionServer('/secrets', 'POST', JSON.stringify(body), user); } catch (e) { - catchError('Sending Action Secret Parameters Failed', e as Error); + catchError('log', 'Sending Action Secret Parameters Failed', e as Error); showFailureToast('Sending Action Secret Parameters Failed'); } }, @@ -7279,7 +7339,7 @@ const effects = { throw new Error('Workspace File Creation Failed'); } } catch (e) { - catchError('Workspace file was unable to be created', e as Error); + catchError('log', 'Workspace file was unable to be created', e as Error); showFailureToast('Workspace File Creation Failed'); } return null; @@ -7290,7 +7350,7 @@ const effects = { const data = await reqGateway('/auth/session', 'GET', null, user, false); return data; } catch (e) { - catchError('Unable to retrieve session data', e as Error); + catchError('log', 'Unable to retrieve session data', e as Error); return { message: 'An unexpected error occurred', success: false }; } }, @@ -7337,13 +7397,14 @@ const effects = { return false; } catch (error) { showFailureToast((error as Error)?.message ?? error); - catchError('Shift Activities Failed', error as Error); + catchError('log', 'Shift Activities Failed', error as Error); return false; } }, async simulate(plan: Plan | null, force: boolean = false, user: User | null): Promise { - let simulateResponse: SimulateResponse | null = null; + clearConsoleEntries('simulation'); + clearConsoleEntries('constraint'); try { if (plan !== null) { if (!queryPermissions.SIMULATE(user, plan, plan.model)) { @@ -7355,20 +7416,19 @@ const effects = { const data = await reqHasura(gql.SIMULATE, { force, planId: plan.id }, user); const { simulate } = data; if (simulate != null) { - simulateResponse = simulate; const { simulationDatasetId: newSimulationDatasetId } = simulate; simulationDatasetIdStore.set(newSimulationDatasetId); - // React if the simulation immediately fails if (simulate.status === 'failed') { - throw new CompoundError(`Unable to run simulation ID=${newSimulationDatasetId}`, { - data: simulateResponse.reason.data, - level: 'error', - message: `Unable to run simulation ID=${newSimulationDatasetId}. ${simulateResponse.reason.message}.`, - timestamp: new Date().toISOString(), - type: ErrorTypes.CAUGHT_ERROR, + catchError('simulation', '', { + ...simulate.reason, + message: `Unable to run simulation ID=${newSimulationDatasetId}. ${simulate.reason.message}.`, + timestamp: simulate.reason.timestamp ?? new Date().toISOString(), + type: simulate.reason.type ?? ErrorTypes.CAUGHT_ERROR, }); + showFailureToast('Simulation failed'); + return; } - logMessage(`Running simulation ID=${newSimulationDatasetId} ${force ? ' (force)' : ''}.`); + logMessage('log', `Running simulation ID=${newSimulationDatasetId} ${force ? ' (force)' : ''}.`); } else { throw Error('Unable to simulate this plan'); } @@ -7376,7 +7436,7 @@ const effects = { throw Error('Plan is not defined.'); } } catch (e) { - catchError('Simulation failed', e as Error); + catchError('simulation', 'Simulation failed', e as Error); showFailureToast('Simulation failed'); } }, @@ -7402,12 +7462,12 @@ const effects = { if (updateActionDefinitionByPk != null) { showSuccessToast(`Action Updated Successfully`); - logMessage(`Updated definition for action ID=${id}.`); + logMessage('log', `Updated definition for action ID=${id}.`); } else { throw Error(`Unable to update action with ID: "${id}"`); } } catch (e) { - catchError('Action Update Failed', e as Error); + catchError('log', 'Action Update Failed', e as Error); showFailureToast('Action Update Failed'); } }, @@ -7431,7 +7491,7 @@ const effects = { throw Error('Unable to update action definition version'); } } catch (e) { - catchError('Version Update Failed', e as Error); + catchError('log', 'Version Update Failed', e as Error); showFailureToast('Version Update Failed'); } }, @@ -7504,12 +7564,12 @@ const effects = { }); }); showSuccessToast('Activity Directive Updated Successfully'); - logMessage(`Updated activity directive ID=${id}.`); + logMessage('log', `Updated activity directive ID=${id}.`); } else { throw Error(`Unable to update directive with ID: "${id}"`); } } catch (e) { - catchError('Activity Directive Update Failed', e as Error); + catchError('log', 'Activity Directive Update Failed', e as Error); showFailureToast(`Activity Directive Update Failed: \n${(e as Error).message}`); } }, @@ -7533,12 +7593,12 @@ const effects = { if (updateActivityPresetsByPk != null) { const { name: presetName } = updateActivityPresetsByPk; showSuccessToast(`Activity Preset ${presetName} Updated Successfully`); - logMessage(`Updated activity preset "${presetName}".`); + logMessage('log', `Updated activity preset "${presetName}".`); } else { throw Error(`Unable to update activity preset with ID: "${id}"`); } } catch (e) { - catchError('Activity Preset Update Failed', e as Error); + catchError('log', 'Activity Preset Update Failed', e as Error); showFailureToast('Activity Preset Update Failed'); } }, @@ -7565,7 +7625,7 @@ const effects = { if (insertConstraintDefinitionTags != null && deleteConstraintDefinitionTags != null) { const { affected_rows: affectedRows } = insertConstraintDefinitionTags; - logMessage(`Updated constraint tags for constraint ID=${constraintId}.`); + logMessage('log', `Updated constraint tags for constraint ID=${constraintId}.`); showSuccessToast('Constraint Updated Successfully'); return affectedRows; @@ -7573,7 +7633,7 @@ const effects = { throw Error('Unable to create constraint definition tags'); } } catch (e) { - catchError('Create Constraint Definition Tags Failed', e as Error); + catchError('log', 'Create Constraint Definition Tags Failed', e as Error); showFailureToast('Create Constraint Definition Tags Failed'); return null; } @@ -7606,10 +7666,10 @@ const effects = { } showSuccessToast('Constraint Updated Successfully'); - logMessage(`Updated constraint metadata for constraint ID=${id}.`); + logMessage('log', `Updated constraint metadata for constraint ID=${id}.`); return true; } catch (e) { - catchError('Constraint Metadata Update Failed', e as Error); + catchError('log', 'Constraint Metadata Update Failed', e as Error); showFailureToast('Constraint Metadata Update Failed'); return false; } @@ -7634,13 +7694,16 @@ const effects = { ); if (updateConstraintModelSpecification !== null) { - logMessage(`Updated model specification for constraint invocation ID=${constraintSpecToUpdate.invocation_id}.`); + logMessage( + 'log', + `Updated model specification for constraint invocation ID=${constraintSpecToUpdate.invocation_id}.`, + ); showSuccessToast(`Constraint Model Specification Updated Successfully`); } else { throw Error('Unable to update the constraint specification for the model'); } } catch (e) { - catchError('Constraint Model Specification Update Failed', e as Error); + catchError('log', 'Constraint Model Specification Update Failed', e as Error); showFailureToast('Constraint Model Specification Update Failed'); } }, @@ -7663,12 +7726,12 @@ const effects = { if (addConstraintModelSpecifications !== null || deleteConstraintModelSpecifications !== null) { showSuccessToast(`Constraint Model Specifications Updated Successfully`); - logMessage(`Updated constraint model specifications.`); + logMessage('log', `Updated constraint model specifications.`); } else { throw Error('Unable to update the constraint specifications for the model'); } } catch (e) { - catchError('Constraint Model Specifications Update Failed', e as Error); + catchError('log', 'Constraint Model Specifications Update Failed', e as Error); showFailureToast('Constraint Model Specifications Update Failed'); } }, @@ -7704,12 +7767,12 @@ const effects = { if (updateConstraintPlanSpecification !== null) { showSuccessToast(`Constraint Plan Specification Updated Successfully`); - logMessage(`Updated constraint plan specification.`); + logMessage('log', `Updated constraint plan specification.`); } else { throw Error('Unable to update the constraint specification for the plan'); } } catch (e) { - catchError('Constraint Plan Specification Update Failed', e as Error); + catchError('log', 'Constraint Plan Specification Update Failed', e as Error); showFailureToast('Constraint Plan Specification Update Failed'); } }, @@ -7733,12 +7796,12 @@ const effects = { if (insertConstraintPlanSpecifications !== null || deleteConstraintPlanSpecifications !== null) { showSuccessToast(`Constraint Plan Specifications Updated Successfully`); - logMessage(`Updated constraint plan specifications.`); + logMessage('log', `Updated constraint plan specifications.`); } else { throw Error('Unable to update the constraint specifications for the plan'); } } catch (e) { - catchError('Constraint Plan Specifications Update Failed', e as Error); + catchError('log', 'Constraint Plan Specifications Update Failed', e as Error); showFailureToast('Constraint Plan Specifications Update Failed'); } }, @@ -7762,7 +7825,7 @@ const effects = { throw Error(`Unable to log derivation group update recognition`); } } catch (e) { - catchError('Derivation Group Update Visibility Recognition Failed', e as Error); + catchError('log', 'Derivation Group Update Visibility Recognition Failed', e as Error); } }, @@ -7780,14 +7843,14 @@ const effects = { if (updateExpansionRule != null) { const { updated_at: updatedAt } = updateExpansionRule; showSuccessToast('Expansion Rule Updated Successfully'); - logMessage(`Updated expansion rule "${rule.name}" (ID=${id}).`); + logMessage('log', `Updated expansion rule "${rule.name}" (ID=${id}).`); savingExpansionRuleStore.set(false); return updatedAt; } else { throw Error(`Unable to update expansion rule with ID: "${id}"`); } } catch (e) { - catchError('Expansion Rule Update Failed', e as Error); + catchError('log', 'Expansion Rule Update Failed', e as Error); showFailureToast('Expansion Rule Update Failed'); savingExpansionRuleStore.set(false); createExpansionRuleErrorStore.set((e as Error).message); @@ -7813,13 +7876,13 @@ const effects = { if (data != null) { showSuccessToast('Model Updated Successfully'); - logMessage(`Updated model ID=${id}.`); + logMessage('log', `Updated model ID=${id}.`); return data.updateModel; } else { throw Error(`Unable to update model with ID: "${id}"`); } } catch (e) { - catchError('Model Update Failed', e as Error); + catchError('log', 'Model Update Failed', e as Error); showFailureToast('Model Update Failed'); } return null; @@ -7844,10 +7907,10 @@ const effects = { } showSuccessToast('Parcel Updated Successfully'); - logMessage(`Updated parcel ID=${id}.`); + logMessage('log', `Updated parcel ID=${id}.`); return ''; } catch (e) { - catchError('Parcel Update Failed', e as Error); + catchError('log', 'Parcel Update Failed', e as Error); showFailureToast('Parcel Update Failed'); return null; } @@ -7864,13 +7927,13 @@ const effects = { if (updatePlan.id != null) { showSuccessToast('Plan Updated Successfully'); - logMessage(`Updated plan "${plan.name}" (ID=${plan.id}).`); + logMessage('log', `Updated plan "${plan.name}" (ID=${plan.id}).`); return; } else { throw Error(`Unable to update plan with ID: "${plan.id}"`); } } catch (e) { - catchError('Plan Update Failed', e as Error); + catchError('log', 'Plan Update Failed', e as Error); showFailureToast('Plan Update Failed'); return; } @@ -7890,14 +7953,14 @@ const effects = { const data = await reqHasura(gql.MIGRATE_PLAN_TO_MODEL, { new_model_id: value.id, plan_id: plan.id }, user); if (data.migrate_plan_to_model?.result === 'success') { showSuccessToast('Model Migration Success'); - logMessage(`Migrated plan from model ID=${plan.model_id} to model ID=${value.id}.`); + logMessage('log', `Migrated plan from model ID=${plan.model_id} to model ID=${value.id}.`); return true; } else { throw Error(data.migrate_plan_to_model?.result); } } } catch (e) { - catchError('Model Migration Failed', e as Error); + catchError('log', 'Model Migration Failed', e as Error); showFailureToast('Model Migration Failed'); } return false; @@ -7914,13 +7977,13 @@ const effects = { if (updatedPlanSnapshotId != null) { showSuccessToast('Plan Snapshot Updated Successfully'); - logMessage(`Updated plan snapshot ID=${id}.`); + logMessage('log', `Updated plan snapshot ID=${id}.`); return; } else { throw Error(`Unable to update plan snapshot with ID: "${id}"`); } } catch (e) { - catchError('Plan Snapshot Update Failed', e as Error); + catchError('log', 'Plan Snapshot Update Failed', e as Error); showFailureToast('Plan Snapshot Update Failed'); return; } @@ -7948,7 +8011,7 @@ const effects = { if (insertSchedulingConditionDefinitionTags != null && deleteSchedulingConditionDefinitionTags != null) { const { affected_rows: affectedRows } = insertSchedulingConditionDefinitionTags; - logMessage(`Updated tags for scheduling condition ID=${conditionId}.`); + logMessage('log', `Updated tags for scheduling condition ID=${conditionId}.`); showSuccessToast('Scheduling Condition Updated Successfully'); return affectedRows; @@ -7956,7 +8019,7 @@ const effects = { throw Error('Unable to create scheduling condition definition tags'); } } catch (e) { - catchError('Create Scheduling Condition Definition Tags Failed', e as Error); + catchError('log', 'Create Scheduling Condition Definition Tags Failed', e as Error); showFailureToast('Create Scheduling Condition Definition Tags Failed'); return null; } @@ -7989,10 +8052,10 @@ const effects = { } showSuccessToast('Scheduling Condition Updated Successfully'); - logMessage(`Updated metadata for scheduling condition ID=${id}.`); + logMessage('log', `Updated metadata for scheduling condition ID=${id}.`); return true; } catch (e) { - catchError('Scheduling Condition Metadata Update Failed', e as Error); + catchError('log', 'Scheduling Condition Metadata Update Failed', e as Error); showFailureToast('Scheduling Condition Metadata Update Failed'); return false; } @@ -8023,12 +8086,15 @@ const effects = { if (updateSchedulingConditionModelSpecifications !== null || deleteConstraintModelSpecifications !== null) { showSuccessToast(`Scheduling Conditions Updated Successfully`); - logMessage(`Updated scheduling condition model specification for model "${model.name}" (ID=${model.id}).`); + logMessage( + 'log', + `Updated scheduling condition model specification for model "${model.name}" (ID=${model.id}).`, + ); } else { throw Error('Unable to update the scheduling condition specifications for the model'); } } catch (e) { - catchError('Scheduling Condition Model Specifications Update Failed', e as Error); + catchError('log', 'Scheduling Condition Model Specifications Update Failed', e as Error); showFailureToast('Scheduling Condition Model Specifications Update Failed'); } }, @@ -8053,12 +8119,12 @@ const effects = { if (updateSchedulingConditionPlanSpecification !== null) { showSuccessToast(`Scheduling Condition Plan Specification Updated Successfully`); - logMessage(`Updated scheduling condition plan specification for plan "${plan.name}" (ID=${plan.id}).`); + logMessage('log', `Updated scheduling condition plan specification for plan "${plan.name}" (ID=${plan.id}).`); } else { throw Error('Unable to update the scheduling condition specification for the plan'); } } catch (e) { - catchError('Scheduling Condition Plan Specification Update Failed', e as Error); + catchError('log', 'Scheduling Condition Plan Specification Update Failed', e as Error); showFailureToast('Scheduling Condition Plan Specification Update Failed'); } }, @@ -8086,12 +8152,12 @@ const effects = { if (updateSchedulingConditionPlanSpecifications !== null || deleteConstraintPlanSpecifications !== null) { showSuccessToast(`Scheduling Conditions Updated Successfully`); - logMessage(`Updated scheduling condition plan specifications for plan "${plan.name}" (ID=${plan.id}).`); + logMessage('log', `Updated scheduling condition plan specifications for plan "${plan.name}" (ID=${plan.id}).`); } else { throw Error('Unable to update the scheduling condition specifications for the plan'); } } catch (e) { - catchError('Scheduling Condition Plan Specifications Update Failed', e as Error); + catchError('log', 'Scheduling Condition Plan Specifications Update Failed', e as Error); showFailureToast('Scheduling Condition Plan Specifications Update Failed'); } }, @@ -8119,13 +8185,13 @@ const effects = { const { affected_rows: affectedRows } = insertSchedulingGoalDefinitionTags; showSuccessToast('Scheduling Goal Updated Successfully'); - logMessage(`Updated tags for scheduling goal ID=${goalId}.`); + logMessage('log', `Updated tags for scheduling goal ID=${goalId}.`); return affectedRows; } else { throw Error('Unable to create scheduling goal definition tags'); } } catch (e) { - catchError('Create Scheduling Goal Definition Tags Failed', e as Error); + catchError('log', 'Create Scheduling Goal Definition Tags Failed', e as Error); showFailureToast('Create Scheduling Goal Definition Tags Failed'); return null; } @@ -8158,9 +8224,9 @@ const effects = { } showSuccessToast('Scheduling Goal Updated Successfully'); - logMessage(`Updated metadata for scheduling goal ID=${id}.`); + logMessage('log', `Updated metadata for scheduling goal ID=${id}.`); } catch (e) { - catchError('Scheduling Goal Metadata Update Failed', e as Error); + catchError('log', 'Scheduling Goal Metadata Update Failed', e as Error); showFailureToast('Scheduling Goal Metadata Update Failed'); } }, @@ -8188,12 +8254,12 @@ const effects = { if (updateSchedulingGoalModelSpecification !== null) { showSuccessToast(`Scheduling Goal Model Specification Updated Successfully`); - logMessage(`Updated scheduling goal model specification.`); + logMessage('log', `Updated scheduling goal model specification.`); } else { throw Error('Unable to update the scheduling goal specification for the model'); } } catch (e) { - catchError('Scheduling Goal Model Specification Update Failed', e as Error); + catchError('log', 'Scheduling Goal Model Specification Update Failed', e as Error); showFailureToast('Scheduling Goal Model Specification Update Failed'); } }, @@ -8218,12 +8284,12 @@ const effects = { if (addSchedulingGoalModelSpecifications !== null || deleteConstraintModelSpecifications !== null) { showSuccessToast(`Scheduling Goals Updated Successfully`); - logMessage(`Updated scheduling goal model specifications.`); + logMessage('log', `Updated scheduling goal model specifications.`); } else { throw Error('Unable to update the scheduling goal specifications for the model'); } } catch (e) { - catchError('Scheduling Goal Model Specifications Update Failed', e as Error); + catchError('log', 'Scheduling Goal Model Specifications Update Failed', e as Error); showFailureToast('Scheduling Goal Model Specifications Update Failed'); } }, @@ -8274,12 +8340,12 @@ const effects = { if (updateSchedulingGoalPlanSpecification !== null) { showSuccessToast(`Scheduling Goal Plan Specification Updated Successfully`); - logMessage(`Updated scheduling goal plan specification for plan "${plan.name}" (ID=${plan.id}).`); + logMessage('log', `Updated scheduling goal plan specification for plan "${plan.name}" (ID=${plan.id}).`); } else { throw Error('Unable to update the scheduling goal specification for the plan'); } } catch (e) { - catchError('Scheduling Goal Plan Specification Update Failed', e as Error); + catchError('log', 'Scheduling Goal Plan Specification Update Failed', e as Error); showFailureToast('Scheduling Goal Plan Specification Update Failed'); } }, @@ -8305,12 +8371,12 @@ const effects = { if (insertSchedulingGoalPlanSpecifications !== null || deleteConstraintPlanSpecifications !== null) { showSuccessToast(`Scheduling Goals Updated Successfully`); - logMessage(`Updated scheduling goal plan specifications for plan "${plan.name}" (ID=${plan.id}).`); + logMessage('log', `Updated scheduling goal plan specifications for plan "${plan.name}" (ID=${plan.id}).`); } else { throw Error('Unable to update the scheduling goal specifications for the plan'); } } catch (e) { - catchError('Scheduling Goal Plan Specifications Update Failed', e as Error); + catchError('log', 'Scheduling Goal Plan Specifications Update Failed', e as Error); showFailureToast('Scheduling Goal Plan Specifications Update Failed'); } }, @@ -8330,9 +8396,9 @@ const effects = { if (data.updateSchedulingSpec == null) { throw Error(`Scheduling spec with ID: "${id}" not found`); } - logMessage(`Updated scheduling specification ID=${id} for plan "${plan.name}" (ID=${plan.id}).`); + logMessage('log', `Updated scheduling specification ID=${id} for plan "${plan.name}" (ID=${plan.id}).`); } catch (e) { - catchError('Unable to update scheduling specification', e as Error); + catchError('log', 'Unable to update scheduling specification', e as Error); } }, @@ -8350,13 +8416,13 @@ const effects = { const data = await reqHasura(gql.UPDATE_SEQUENCE_FILTER, { filter, filterId, filterName }, user); if (data.updateSequenceFilter !== null) { - logMessage(`Updated sequence filter "${filterName}" (ID=${filterId}).`); + logMessage('log', `Updated sequence filter "${filterName}" (ID=${filterId}).`); showSuccessToast('Updated Sequence Filter'); } else { throw Error(`Unable to update sequence filter with ID: "${filterId}"`); } } catch (e) { - catchError('Failed to Update Sequence Filter', e as Error); + catchError('log', 'Failed to Update Sequence Filter', e as Error); showFailureToast('Failed To Update Sequence Template'); } }, @@ -8373,13 +8439,13 @@ const effects = { const data = await reqHasura(gql.UPDATE_SEQUENCE_TEMPLATE, { definition, id: sequenceTemplate.id }, user); if (data.updateSequenceTemplate !== null) { - logMessage(`Updated sequence template "${sequenceTemplate.name}" (ID=${sequenceTemplate.id}).`); + logMessage('log', `Updated sequence template "${sequenceTemplate.name}" (ID=${sequenceTemplate.id}).`); showSuccessToast('Updated Sequence Template'); } else { throw Error(`Unable to update sequence template with ID: "${sequenceTemplate.id}"`); } } catch (e) { - catchError('Failed To Update Sequence Template', e as Error); + catchError('log', 'Failed To Update Sequence Template', e as Error); showFailureToast('Failed To Update Sequence Template'); } }, @@ -8412,13 +8478,13 @@ const effects = { user, ); if (data.updateSimulation !== null) { - logMessage(`Updated simulation ID=${simulationSetInput.id}.`); + logMessage('log', `Updated simulation ID=${simulationSetInput.id}.`); showSuccessToast('Simulation Updated Successfully'); } else { throw Error(`Unable to update simulation with ID: "${simulationSetInput.id}"`); } } catch (e) { - catchError('Simulation Update Failed', e as Error); + catchError('log', 'Simulation Update Failed', e as Error); showFailureToast('Simulation Update Failed'); } }, @@ -8452,12 +8518,12 @@ const effects = { if (updateSimulationTemplateByPk != null) { const { description: templateDescription } = updateSimulationTemplateByPk; showSuccessToast(`Simulation Template ${templateDescription} Updated Successfully`); - logMessage(`Updated simulation template "${templateDescription}" (ID=${id}).`); + logMessage('log', `Updated simulation template "${templateDescription}" (ID=${id}).`); } else { throw Error(`Unable to update simulation template with ID: "${id}"`); } } catch (e) { - catchError('Simulation Template Update Failed', e as Error); + catchError('log', 'Simulation Template Update Failed', e as Error); showFailureToast('Simulation Template Update Failed'); } }, @@ -8479,13 +8545,13 @@ const effects = { showSuccessToast('Tag Updated Successfully'); } if (updatedTag) { - logMessage(`Updated tag "${updatedTag.name}" (ID=${updatedTag.id}).`); + logMessage('log', `Updated tag "${updatedTag.name}" (ID=${updatedTag.id}).`); } createTagErrorStore.set(null); return updatedTag; } catch (e) { createTagErrorStore.set((e as Error).message); - catchError('Update Tags Failed', e as Error); + catchError('log', 'Update Tags Failed', e as Error); showFailureToast('Update Tags Failed'); return null; } @@ -8499,14 +8565,14 @@ const effects = { const data = await reqHasura(gql.UPDATE_VIEW, { id, view }, user); if (data.updatedView) { - logMessage(`Updated view "${data.updatedView.name}" (ID=${data.updatedView.id}).`); + logMessage('log', `Updated view "${data.updatedView.name}" (ID=${data.updatedView.id}).`); showSuccessToast(message ?? 'View Updated Successfully'); return true; } else { throw Error(`Unable to update view with ID: "${id}"`); } } catch (e) { - catchError('View Update Failed', e as Error); + catchError('log', 'View Update Failed', e as Error); showFailureToast('View Update Failed'); return false; } @@ -8530,14 +8596,14 @@ const effects = { const { updatedWorkspace } = data; if (updatedWorkspace != null) { - logMessage(`Updated workspace "${workspace.name}" (ID=${workspace.id}).`); + logMessage('log', `Updated workspace "${workspace.name}" (ID=${workspace.id}).`); showSuccessToast('Workspace Updated Successfully'); return updatedWorkspace; } else { throw Error(`Unable to update workspace "${workspace.name}"`); } } catch (e) { - catchError('Workspace Update Failed', e as Error); + catchError('log', 'Workspace Update Failed', e as Error); showFailureToast('Workspace Update Failed'); } @@ -8560,12 +8626,12 @@ const effects = { if (uploadedActivities != null) { showSuccessToast('Activities Uploaded Successfully'); - logMessage(`Uploaded ${uploadedActivities} activites from file '${file.name}'`); + logMessage('log', `Uploaded ${uploadedActivities} activites from file '${file.name}'`); return uploadedActivities; } throw Error('Uploaded activities not found'); } catch (e) { - catchError('Unable to upload activities', e as Error); + catchError('log', 'Unable to upload activities', e as Error); showFailureToast('Activity Upload Failed'); return null; } @@ -8603,10 +8669,10 @@ const effects = { throw Error(`Unable to upload Dictionary`); } - logMessage(`Uploaded dictionary.`); + logMessage('log', `Uploaded dictionary.`); return newDictionaries; } catch (e) { - catchError(`Dictionary Upload Failed`, e as Error); + catchError('log', `Dictionary Upload Failed`, e as Error); return null; } }, @@ -8668,13 +8734,13 @@ const effects = { if (uploadedDatasetId != null) { showSuccessToast('External Dataset Uploaded Successfully'); - logMessage(`Uploaded external dataset ID=${uploadedDatasetId}.`); + logMessage('log', `Uploaded external dataset ID=${uploadedDatasetId}.`); return uploadedDatasetId; } throw Error('Uploaded dataset not found'); } catch (e) { - catchError('Unable to upload external dataset', e as Error); + catchError('log', 'Unable to upload external dataset', e as Error); showFailureToast('External Dataset Upload Failed'); return null; } @@ -8688,7 +8754,7 @@ const effects = { const { id } = data; return id; } catch (e) { - catchError('Unable to upload file', e as Error); + catchError('log', 'Unable to upload file', e as Error); return null; } }, @@ -8720,7 +8786,7 @@ const effects = { return generatedFilenames; } catch (e) { - catchError('Unable to upload files', e as Error); + catchError('log', 'Unable to upload files', e as Error); return {}; } }, @@ -8742,14 +8808,14 @@ const effects = { if (newView != null) { viewStore.update(() => newView); setQueryParam(SearchParameters.VIEW_ID, `${newView.id}`); - logMessage(`Uploaded view "${newView.name}" (ID=${newView.id}).`); + logMessage('log', `Uploaded view "${newView.name}" (ID=${newView.id}).`); return true; } else { throw Error('Unable to upload view'); } } } catch (e) { - catchError('View Upload Failed', e as Error); + catchError('log', 'View Upload Failed', e as Error); showFailureToast('View Upload Failed'); } @@ -8776,7 +8842,7 @@ const effects = { const { validateActivityArguments } = data; if (validateActivityArguments != null) { - logMessage(`Validated activity arguments for "${activityTypeName}" (ID=${activityId}).`); + logMessage('log', `Validated activity arguments for "${activityTypeName}" (ID=${activityId}).`); return validateActivityArguments; } else { throw Error('Unable to validate activity arguments'); @@ -8801,7 +8867,7 @@ const effects = { valid, }; } catch (e) { - catchError('Unable to validate view JSON', e as Error); + catchError('log', 'Unable to validate view JSON', e as Error); const { message } = e as Error; return { errors: [message], valid: false }; } diff --git a/src/utilities/errors.test.ts b/src/utilities/errors.test.ts index 3632651da3..3b7a2c9c28 100644 --- a/src/utilities/errors.test.ts +++ b/src/utilities/errors.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from 'vitest'; -import type { AnchorValidationError, SchedulingError } from '../types/errors'; +import type { AnchorValidationError, BaseError } from '../types/errors'; import { ErrorTypes, generateActivityValidationErrorRollups, @@ -234,7 +234,7 @@ describe('Errors Util', () => { message: '', timestamp: '', type: ErrorTypes.GLOBAL_SCHEDULING_CONDITIONS_FAILED, - } as SchedulingError), + } as BaseError), ).deep.eq([1, 2]); }); }); diff --git a/src/utilities/errors.ts b/src/utilities/errors.ts index bd79758e60..e330152abc 100644 --- a/src/utilities/errors.ts +++ b/src/utilities/errors.ts @@ -7,9 +7,6 @@ import type { ActivityValidationErrors, AnchorValidationError, BaseError, - LogMessage, - SchedulingError, - SimulationDatasetError, } from '../types/errors'; export enum ErrorTypes { @@ -17,24 +14,49 @@ export enum ErrorTypes { ANCHOR_VALIDATION_ERROR = 'ANCHOR_VALIDATION_ERROR', CAUGHT_ERROR = 'CAUGHT_ERROR', CONSTRAINT_RUN_ERROR = 'CONSTRAINT_RUN_ERROR', // TODO this is made up by client, is that ok? + DATABASE_EXCEPTION = 'DATABASE_EXCEPTION', + ENDPOINT_VALIDATION_EXCEPTION = 'ENDPOINT_VALIDATION_EXCEPTION', + FILE_LOCKED = 'FILE_LOCKED', + FILE_OPERATION_EXCEPTION = 'FILE_OPERATION_EXCEPTION', + FORBIDDEN = 'FORBIDDEN', GLOBAL_SCHEDULING_CONDITIONS_FAILED = 'GLOBAL_SCHEDULING_CONDITIONS_FAILED', - IO_EXCEPTION = 'IO_EXCEPTION', + GRAPHQL_SERVICE_EXCEPTION = 'GRAPHQL_SERVICE_EXCEPTION', + HTTP_RESPONSE_EXCEPTION = 'HTTP_RESPONSE_EXCEPTION', + ILLEGAL_ARGUMENT = 'ILLEGAL_ARGUMENT', + INPUT_MISMATCH_EXCEPTION = 'INPUT_MISMATCH_EXCEPTION', INSTANTIATION_ERRORS = 'INSTANTIATION_ERRORS', + INTERNAL_ERROR = 'INTERNAL_ERROR', + IO_EXCEPTION = 'IO_EXCEPTION', + JSON_PARSING_EXCEPTION = 'JSON_PARSING_EXCEPTION', LOG = 'LOG', - MISSION_MODEL_ERROR = 'MISSION_MODEL_ERROR', // TODO this is made up by client, is that ok? + MALFORMED_REQUEST = 'MALFORMED_REQUEST', + MISSION_MODEL_LOAD_EXCEPTION = 'MISSION_MODEL_LOAD_EXCEPTION', NO_SUCH_ACTIVITY_TYPE = 'NO_SUCH_ACTIVITY_TYPE', + NO_SUCH_CONSTRAINT = 'NO_SUCH_CONSTRAINT', + NO_SUCH_FILE = 'NO_SUCH_FILE', NO_SUCH_MISSION_MODEL = 'NO_SUCH_MISSION_MODEL', NO_SUCH_PLAN = 'NO_SUCH_PLAN', - NO_SUCH_SPECIFICATION = 'NO_SUCH_SPECIFICATION', + NO_SUCH_PLAN_DATASET = 'NO_SUCH_PLAN_DATASET', + NO_SUCH_SCHEDULING_SPECIFICATION = 'NO_SUCH_SCHEDULING_SPECIFICATION', + NO_SUCH_WORKSPACE = 'NO_SUCH_WORKSPACE', + NULL_POINTER_EXCEPTION = 'NULL_POINTER_EXCEPTION', + NUMBER_PARSING_EXCEPTION = 'NUMBER_PARSING_EXCEPTION', + PERMISSIONS_SERVICE_EXCEPTION = 'PERMISSIONS_SERVICE_EXCEPTION', PLAN_CONTAINS_UNCONSTRUCTABLE_ACTIVITIES = 'PLAN_CONTAINS_UNCONSTRUCTABLE_ACTIVITIES', PLAN_SERVICE_EXCEPTION = 'PLAN_SERVICE_EXCEPTION', + PROCEDURE_LOAD_EXCEPTION = 'PROCEDURE_LOAD_EXCEPTION', RESULTS_PROTOCOL_FAILURE = 'RESULTS_PROTOCOL_FAILURE', SCHEDULING_GOALS_FAILED = 'SCHEDULING_GOALS_FAILED', + SECURITY_EXCEPTION = 'SECURITY_EXCEPTION', SIMULATION_EXCEPTION = 'SIMULATION_EXCEPTION', SIMULATION_REQUEST_NOT_RELEVANT = 'SIMULATION_REQUEST_NOT_RELEVANT', + SIM_DATASET_MISMATCH_EXCEPTION = 'SIM_DATASET_MISMATCH_EXCEPTION', SPECIFICATION_LOAD_EXCEPTION = 'SPECIFICATION_LOAD_EXCEPTION', + SQL_EXCEPTION = 'SQL_EXCEPTION', + UNAUTHORIZED = 'UNAUTHORIZED', UNEXPECTED_SCHEDULER_EXCEPTION = 'UNEXPECTED_SCHEDULER_EXCEPTION', UNEXPECTED_SIMULATION_EXCEPTION = 'UNEXPECTED_SIMULATION_EXCEPTION', + UNKNOWN_ERROR = 'UNKNOWN_ERROR', VALIDATION_NOTICES = 'VALIDATION_NOTICES', WORKSPACE_ACTION_RUN = 'WORKSPACE_ACTION_RUN', WORKSPACE_ADAPTATION_ERROR = 'WORKSPACE_ADAPTATION_ERROR', @@ -60,10 +82,6 @@ export function isValidationNoticesError( return (validation as ActivityDirectiveValidationNoticesFailure).type === ErrorTypes.VALIDATION_NOTICES; } -export function isLogMessage(log: BaseError): log is LogMessage { - return log.type === ErrorTypes.LOG || log.type === ErrorTypes.CAUGHT_ERROR; -} - export function generateActivityValidationErrorRollups( activityValidationErrors: ActivityValidationErrors[], ): ActivityErrorRollup[] { @@ -125,9 +143,6 @@ export function generateActivityValidationErrorRollups( }); } -/** - * Extract activity IDs from different error types - */ export function getActivityIdsFromError(error: BaseError): number[] { if (error.type === ErrorTypes.ANCHOR_VALIDATION_ERROR || error.type === ErrorTypes.ACTIVITY_VALIDATION_ERROR) { return [(error as AnchorValidationError).data.activityId]; @@ -136,14 +151,14 @@ export function getActivityIdsFromError(error: BaseError): number[] { error.type === ErrorTypes.SCHEDULING_GOALS_FAILED || error.type === ErrorTypes.UNEXPECTED_SIMULATION_EXCEPTION ) { - const errorWithIds = error as SchedulingError | SimulationDatasetError; - if (errorWithIds.data?.errors) { - return Object.keys(errorWithIds.data.errors) + const errors = error.data?.errors; + if (errors && typeof errors === 'object') { + return Object.keys(errors) .map(id => parseInt(id)) .filter(id => !isNaN(id)); } } else if (error.type === ErrorTypes.SIMULATION_EXCEPTION) { - const id = (error as SimulationDatasetError).data.executingDirectiveId; + const id = error.data?.executingDirectiveId; if (typeof id === 'number') { return [id]; } diff --git a/src/utilities/requests.test.ts b/src/utilities/requests.test.ts new file mode 100644 index 0000000000..3a11784f42 --- /dev/null +++ b/src/utilities/requests.test.ts @@ -0,0 +1,176 @@ +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; +import type { BaseUser } from '../types/app'; +import { ErrorTypes } from './errors'; +import { CompoundError, reqHasura } from './requests'; + +vi.mock('$env/dynamic/public', () => ({ + env: { + PUBLIC_HASURA_CLIENT_URL: 'http://test/hasura', + PUBLIC_HASURA_SERVER_URL: 'http://test/hasura', + }, +})); + +vi.mock('$app/environment', () => ({ browser: true })); + +vi.mock('./login', () => ({ logout: vi.fn() })); + +const user: BaseUser = { id: 'test-user', token: 'test-token' }; + +function mockHasuraResponse(body: unknown, ok = true, status = 200): void { + global.fetch = vi.fn().mockResolvedValue({ + json: () => Promise.resolve(body), + ok, + status, + statusText: ok ? 'OK' : 'Server Error', + } as unknown as Response); +} + +describe('reqHasura error parsing', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + test('extracts extensions.type from a formatted backend error (PR #1777 example)', async () => { + mockHasuraResponse({ + errors: [ + { + extensions: { + data: { specification_id: 659 }, + message: 'Could not check permissions on scheduling specification 659: specification does not exist.', + service: 'aerie_permissions', + timestamp: '2026-05-18T16:10:49.084229462Z', + trace: 'at gov.nasa.jpl.aerie...', + type: 'NO_SUCH_SCHEDULING_SPECIFICATION', + }, + message: 'Could not check permissions on scheduling specification 659: specification does not exist.', + }, + ], + }); + + await expect(reqHasura('query { x }', {}, user)).rejects.toMatchObject({ + errors: [ + { + data: { specification_id: 659 }, + message: 'Could not check permissions on scheduling specification 659: specification does not exist.', + service: 'aerie_permissions', + timestamp: '2026-05-18T16:10:49.084229462Z', + trace: 'at gov.nasa.jpl.aerie...', + type: ErrorTypes.NO_SUCH_SCHEDULING_SPECIFICATION, + }, + ], + name: 'CompoundError', + }); + }); + + test('preserves cause and trace as separate fields', async () => { + mockHasuraResponse({ + errors: [ + { + extensions: { + cause: 'root-cause text', + service: 'aerie_merlin', + trace: 'stack-trace text', + type: 'NO_SUCH_PLAN', + }, + message: 'Plan not found', + }, + ], + }); + + try { + await reqHasura('query { x }', {}, user); + } catch (e) { + expect(e).toBeInstanceOf(CompoundError); + const ce = e as CompoundError; + expect(ce.errors[0].cause).toBe('root-cause text'); + expect(ce.errors[0].trace).toBe('stack-trace text'); + expect(ce.errors[0].type).toBe(ErrorTypes.NO_SUCH_PLAN); + } + expect.assertions(4); + }); + + test('falls back to CAUGHT_ERROR when extensions.type is missing', async () => { + mockHasuraResponse({ + errors: [ + { + extensions: { service: 'aerie_merlin' }, + message: 'A vague error', + }, + ], + }); + + try { + await reqHasura('query { x }', {}, user); + } catch (e) { + const ce = e as CompoundError; + expect(ce.errors[0].type).toBe(ErrorTypes.CAUGHT_ERROR); + expect(ce.errors[0].service).toBe('aerie_merlin'); + expect(ce.errors[0].message).toBe('A vague error'); + } + expect.assertions(3); + }); + + test('does not use extensions.type for Hasura postgres errors (code=unexpected)', async () => { + mockHasuraResponse({ + errors: [ + { + extensions: { + code: 'unexpected', + internal: { error: { message: 'pg fk constraint violated' } }, + }, + message: 'unexpected', + }, + ], + }); + + try { + await reqHasura('query { x }', {}, user); + } catch (e) { + const ce = e as CompoundError; + expect(ce.errors[0].type).toBe(ErrorTypes.CAUGHT_ERROR); + expect(ce.errors[0].message).toBe('pg fk constraint violated'); + } + expect.assertions(2); + }); + + test('does not use extensions.type for Hasura parse-failed errors', async () => { + mockHasuraResponse({ + errors: [ + { + extensions: { + code: 'parse-failed', + internal: { response: { body: { errors: ['nested error A', 'nested error B'] } } }, + type: 'NO_SUCH_PLAN', // should be ignored — this is a Hasura-level error + }, + message: 'parse failed', + }, + ], + }); + + try { + await reqHasura('query { x }', {}, user); + } catch (e) { + const ce = e as CompoundError; + expect(ce.errors).toHaveLength(2); + expect(ce.errors[0].type).toBe(ErrorTypes.CAUGHT_ERROR); + expect(ce.errors[0].message).toBe('nested error A'); + expect(ce.errors[1].message).toBe('nested error B'); + } + expect.assertions(4); + }); + + test('returns data when there are no errors', async () => { + mockHasuraResponse({ data: { plan: { id: 1, name: 'Test' } } }); + const data = await reqHasura<{ id: number; name: string }>('query { plan { id name } }', {}, user); + expect(data).toEqual({ plan: { id: 1, name: 'Test' } }); + }); + + test('throws CompoundError when response is not OK', async () => { + mockHasuraResponse({}, false, 500); + await expect(reqHasura('query { x }', {}, user)).rejects.toBeInstanceOf(CompoundError); + }); +}); diff --git a/src/utilities/requests.ts b/src/utilities/requests.ts index bd658811b5..8243ea0ab9 100644 --- a/src/utilities/requests.ts +++ b/src/utilities/requests.ts @@ -206,13 +206,13 @@ export async function reqHasura( const defaultErrorMessage = 'An unexpected error occurred'; json.errors.forEach((error: any) => { - const extensions: (Omit & { code: string; internal?: any }) | undefined = error?.extensions; + const extensions: + | (Omit & { code?: string; internal?: any; type?: string }) + | undefined = error?.extensions; - // Extract legacy and current fields from extensions if they exist - const { data, service, timestamp, trace, cause, code } = extensions ?? {}; + const { data, service, timestamp, trace, cause, code, type } = extensions ?? {}; const baseErrorFields = { data, service, timestamp: timestamp ?? defaultError.timestamp, trace }; - // May need a custom error or piggyback cause const errorMessage = extensions?.internal?.error?.message ?? error?.message ?? defaultErrorMessage; if (code === 'unexpected' || code === 'postgres-error') { @@ -247,8 +247,9 @@ export async function reqHasura( errors.push({ ...defaultError, ...baseErrorFields, + cause, message: error?.message ?? defaultErrorMessage, - trace: cause, + type: (type as ErrorTypes) ?? ErrorTypes.CAUGHT_ERROR, }); } }); diff --git a/src/utilities/simulation.ts b/src/utilities/simulation.ts index dfa339fa89..8487d8cfad 100644 --- a/src/utilities/simulation.ts +++ b/src/utilities/simulation.ts @@ -35,7 +35,8 @@ export function getSimulationProgress(simulationDataset: SimulationDataset | nul export function getSimulationExtent(simulationDataset: SimulationDataset): string | null { // Look for the extent in the reason if the sim failed, otherwise grab it from the extent object if (simulationDataset.status === 'failed' || simulationDataset.canceled) { - return simulationDataset.reason?.data.elapsedTime ?? null; + const elapsedTime = simulationDataset.reason?.data?.elapsedTime; + return typeof elapsedTime === 'string' ? elapsedTime : null; } else { return simulationDataset.extent?.extent ?? null; } From 110fc9e11c4ff682b123749ce20c349a66782030 Mon Sep 17 00:00:00 2001 From: AaronPlave Date: Wed, 20 May 2026 09:53:03 -0700 Subject: [PATCH 2/6] =?UTF-8?q?refactor:=20rename=20BaseError=20=E2=86=92?= =?UTF-8?q?=20ConsoleEntry=20and=20errors=20=E2=86=92=20console=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unified store holds backend exceptions, thrown errors, info logs, and validation problems through a single shape. "BaseError" and the "errors.ts" filenames implied error-only content; renaming makes the types and file names match what the code actually represents. - BaseError → ConsoleEntry across all consumers and component props. - src/types/errors.ts → src/types/console.ts. - src/stores/errors.ts → src/stores/console.ts (and .test.ts). - Per-tab readables: simulationDatasetErrors → simulationErrors, constraintRunErrors → constraintErrors (the "Dataset" / "Run" qualifiers referenced backend entities that no longer have a 1:1 relationship with the store contents). src/utilities/errors.ts kept its name — it genuinely holds error domain code (ErrorTypes enum, validation type guards). --- .../activity/ActivityDirectiveForm.svelte | 4 +-- .../activity/ActivityDirectivesTable.svelte | 2 +- .../ActivityDirectivesTablePanel.svelte | 2 +- .../console/views/ActivityErrors.svelte | 2 +- .../console/views/ConsoleLog.svelte | 4 +-- .../console/views/ConsoleLogs.svelte | 6 ++-- .../console/views/PlanLogMessage.svelte | 4 +-- .../console/views/WorkspaceLogMessage.svelte | 4 +-- .../menus/ActivityStatusMenu.svelte | 2 +- .../parameters/ExtraneousParameters.svelte | 2 +- .../sequencing/SequenceEditor.svelte | 2 +- .../actions/ActionRunDetailView.svelte | 2 +- src/components/timeline/Row.svelte | 2 +- src/components/ui/ActivityErrorsRollup.svelte | 2 +- src/components/ui/TextEditor.svelte | 2 +- src/routes/+layout.svelte | 2 +- src/routes/plans/[id]/+page.svelte | 16 +++++----- .../workspaces/[workspaceId]/+page.svelte | 4 +-- .../{errors.test.ts => console.test.ts} | 10 +++---- src/stores/{errors.ts => console.ts} | 30 +++++++++---------- src/stores/workspaceErrors.ts | 12 ++++---- src/types/activity.ts | 2 +- src/types/{errors.ts => console.ts} | 28 +++++++++-------- src/types/scheduling.ts | 6 ++-- src/types/simulation.ts | 8 ++--- src/utilities/codemirror/lint.ts | 2 +- src/utilities/effects.test.ts | 2 +- src/utilities/effects.ts | 4 +-- src/utilities/errors.test.ts | 4 +-- src/utilities/errors.ts | 6 ++-- src/utilities/requests.ts | 4 +-- 31 files changed, 92 insertions(+), 90 deletions(-) rename src/stores/{errors.test.ts => console.test.ts} (95%) rename src/stores/{errors.ts => console.ts} (94%) rename src/types/{errors.ts => console.ts} (76%) diff --git a/src/components/activity/ActivityDirectiveForm.svelte b/src/components/activity/ActivityDirectiveForm.svelte index 6ee1c38d3a..b6661ea994 100644 --- a/src/components/activity/ActivityDirectiveForm.svelte +++ b/src/components/activity/ActivityDirectiveForm.svelte @@ -9,7 +9,7 @@ import { createEventDispatcher } from 'svelte'; import { PlanStatusMessages } from '../../enums/planStatusMessages'; import { activityArgumentDefaultsMap } from '../../stores/activities'; - import { activityErrorRollupsMap, activityValidationErrors } from '../../stores/errors'; + import { activityErrorRollupsMap, activityValidationErrors } from '../../stores/console'; import { field } from '../../stores/form'; import { plan, planReadOnly } from '../../stores/plan'; import { plugins } from '../../stores/plugins'; @@ -27,7 +27,7 @@ ActivityDirectiveInstantiationFailure, ActivityErrorCategories, ActivityErrorRollup, - } from '../../types/errors'; + } from '../../types/console'; import type { FieldStore } from '../../types/form'; import type { Argument, ArgumentsMap, FormParameter, ParameterName } from '../../types/parameter'; import type { ActivityDirectiveTagsInsertInput, Tag, TagsChangeEvent } from '../../types/tags'; diff --git a/src/components/activity/ActivityDirectivesTable.svelte b/src/components/activity/ActivityDirectivesTable.svelte index 07038a1add..a35494ec6a 100644 --- a/src/components/activity/ActivityDirectivesTable.svelte +++ b/src/components/activity/ActivityDirectivesTable.svelte @@ -8,7 +8,7 @@ import type { ActivityDirective, ActivityDirectiveId, ActivityType } from '../../types/activity'; import type { User } from '../../types/app'; import type { DataGridColumnDef } from '../../types/data-grid'; - import type { ActivityErrorCounts, ActivityErrorRollup } from '../../types/errors'; + import type { ActivityErrorCounts, ActivityErrorRollup } from '../../types/console'; import type { Plan } from '../../types/plan'; import type { SpansMap, SpanUtilityMaps } from '../../types/simulation'; import { copyActivityDirectivesToClipboard } from '../../utilities/activities'; diff --git a/src/components/activity/ActivityDirectivesTablePanel.svelte b/src/components/activity/ActivityDirectivesTablePanel.svelte index 12efa12594..2fc3d41de8 100644 --- a/src/components/activity/ActivityDirectivesTablePanel.svelte +++ b/src/components/activity/ActivityDirectivesTablePanel.svelte @@ -14,7 +14,7 @@ import { get } from 'svelte/store'; import { InvalidDate } from '../../constants/time'; import { activityDirectivesMap, selectActivity, selectedActivityDirectiveId } from '../../stores/activities'; - import { activityErrorRollupsMap } from '../../stores/errors'; + import { activityErrorRollupsMap } from '../../stores/console'; import { maxTimeRange, plan, planModelActivityTypes, planReadOnly, viewTimeRange } from '../../stores/plan'; import { plugins } from '../../stores/plugins'; import { spansMap, spanUtilityMaps } from '../../stores/simulation'; diff --git a/src/components/console/views/ActivityErrors.svelte b/src/components/console/views/ActivityErrors.svelte index 6ac06de9a7..d35ed76463 100644 --- a/src/components/console/views/ActivityErrors.svelte +++ b/src/components/console/views/ActivityErrors.svelte @@ -5,7 +5,7 @@ import type { ICellRendererParams, IRowNode } from 'ag-grid-community'; import { getContext } from 'svelte'; import type { DataGridColumnDef } from '../../../types/data-grid'; - import type { ActivityErrorCategories, ActivityErrorCounts, ActivityErrorRollup } from '../../../types/errors'; + import type { ActivityErrorCategories, ActivityErrorCounts, ActivityErrorRollup } from '../../../types/console'; import EmptyState from '../../console/EmptyState.svelte'; import ActivityErrorsRollup from '../../ui/ActivityErrorsRollup.svelte'; import DataGrid from '../../ui/DataGrid/DataGrid.svelte'; diff --git a/src/components/console/views/ConsoleLog.svelte b/src/components/console/views/ConsoleLog.svelte index f7d28475d4..5c3f1dfb59 100644 --- a/src/components/console/views/ConsoleLog.svelte +++ b/src/components/console/views/ConsoleLog.svelte @@ -4,12 +4,12 @@ import { cn } from '@nasa-jpl/stellar-svelte'; import { ChevronDown, ChevronRight } from 'lucide-svelte'; import { onMount } from 'svelte'; - import type { BaseError, LogMessage } from '../../../types/errors'; + import type { ConsoleEntry, LogMessage } from '../../../types/console'; import { safeStringify } from '../../../utilities/text'; import { formatMS } from '../../../utilities/time'; - export let log: BaseError; + export let log: ConsoleEntry; export let defaultExpanded: boolean = false; export let showLevel: boolean = true; export let showTimestamp: boolean = true; diff --git a/src/components/console/views/ConsoleLogs.svelte b/src/components/console/views/ConsoleLogs.svelte index 19777dcdab..5e484a7c8c 100644 --- a/src/components/console/views/ConsoleLogs.svelte +++ b/src/components/console/views/ConsoleLogs.svelte @@ -3,7 +3,7 @@