diff --git a/client/modules/_hooks/src/workspace/types.ts b/client/modules/_hooks/src/workspace/types.ts index 4da9fce6e..461c3639c 100644 --- a/client/modules/_hooks/src/workspace/types.ts +++ b/client/modules/_hooks/src/workspace/types.ts @@ -52,6 +52,24 @@ export type TAppFileInput = { targetPath?: string; }; +type TAppNotes = { + label?: string; + shortLabel?: string; + helpUrl?: string; + category?: string; + isInteractive?: boolean; + hideNodeCountAndCoresPerNode?: boolean; + icon?: string; + dynamicExecSystems?: string[]; + queueFilter?: string[]; + hideQueue?: boolean; + hideAllocation?: boolean; + hideMaxMinutes?: boolean; + jobLaunchDescription?: string; + showReservation?: boolean; + showTargetPath?: boolean; +}; + export type TTapisApp = { sharedAppCtx: string; isPublic: boolean; @@ -111,22 +129,7 @@ export type TTapisApp = { tags: string[]; }; tags: string[]; - notes: { - label?: string; - shortLabel?: string; - helpUrl?: string; - category?: string; - isInteractive?: boolean; - hideNodeCountAndCoresPerNode?: boolean; - icon?: string; - dynamicExecSystems?: string[]; - queueFilter?: string[]; - hideQueue?: boolean; - hideAllocation?: boolean; - hideMaxMinutes?: boolean; - jobLaunchDescription?: string; - showReservation?: boolean; - }; + notes: TAppNotes; uuid: string; deleted: boolean; created: string; @@ -183,7 +186,7 @@ export type TTapisJob = { mpiCmd?: string; name: string; nodeCount: number; - notes: string; + notes: TAppNotes; owner: string; parameterSet: string; remoteChecksFailed: number; diff --git a/client/modules/workspace/src/JobsDetailModal/JobsDetailModal.tsx b/client/modules/workspace/src/JobsDetailModal/JobsDetailModal.tsx index 2207b2db8..ae3e45508 100644 --- a/client/modules/workspace/src/JobsDetailModal/JobsDetailModal.tsx +++ b/client/modules/workspace/src/JobsDetailModal/JobsDetailModal.tsx @@ -304,7 +304,12 @@ export const JobsDetailModal: React.FC<{ uuid: string }> = ({ uuid }) => {
Job UUID:
{jobData.uuid}
Application:
-
{JSON.parse(jobData.notes).label || jobData.appId}
+
+ {(typeof jobData.notes === 'string' + ? JSON.parse(jobData.notes) + : jobData.notes + ).label || jobData.appId} +
System:
{jobData.execSystemId}
diff --git a/designsafe/apps/workspace/api/utils.py b/designsafe/apps/workspace/api/utils.py index e80b74617..35d2b9f70 100644 --- a/designsafe/apps/workspace/api/utils.py +++ b/designsafe/apps/workspace/api/utils.py @@ -1,6 +1,8 @@ """Workspace API Utils""" import json +from typing import Union +from tapipy.tapis import TapisResult def get_tapis_timeout_error_messages(job_id): @@ -11,6 +13,18 @@ def get_tapis_timeout_error_messages(job_id): ] +def _get_job_notes(job_notes: Union[str, TapisResult]): + """ + Normalize `job.notes` as in older version of Tapis `notes` is a JSON-formatted string + but this is being changed to a TapisResult object. Once all tenants are migrated to + return structured (non-string) 'notes', this can be + removed + """ + if isinstance(job_notes, str): + return json.loads(job_notes) + return job_notes + + def check_job_for_timeout(job): """ Check an interactive job for timeout status and mark it as finished @@ -18,7 +32,7 @@ def check_job_for_timeout(job): """ if hasattr(job, "notes"): - notes = json.loads(job.notes) + notes = _get_job_notes(job.notes) is_failed = job.status == "FAILED" is_interactive = notes.get("isInteractive", False)