diff --git a/ui/src/app/shared/artifacts.ts b/ui/src/app/shared/artifacts.ts index 12349448447e..f27746eac5de 100644 --- a/ui/src/app/shared/artifacts.ts +++ b/ui/src/app/shared/artifacts.ts @@ -41,6 +41,24 @@ export const artifactURN = (a: A, ar: ArtifactRepository) => return 'artifact:unknown'; }; +export const artifactRepoHasLocation = (ar: ArtifactRepository) => { + if (ar.gcs) { + return ar.gcs.bucket !== '' && ar.gcs.key !== ''; + } else if (ar.git) { + return ar.git.repo !== ''; + } else if (ar.http) { + return ar.http.url !== ''; + } else if (ar.s3) { + return ar.s3.endpoint !== '' && ar.s3.bucket !== '' && ar.s3.key !== ''; + } else if (ar.oss) { + return ar.oss.bucket !== '' && ar.oss.endpoint !== '' && ar.oss.key !== ''; + } else if (ar.raw) { + return true; + } else if (ar.azure) { + return ar.azure.container !== '' && ar.azure.blob !== ''; + } +}; + export const artifactKey = (a: A) => { if (a.gcs) { return a.gcs.key; diff --git a/ui/src/app/workflows/components/workflow-details/workflow-details.tsx b/ui/src/app/workflows/components/workflow-details/workflow-details.tsx index fab2c6af24b7..90da893d8baa 100644 --- a/ui/src/app/workflows/components/workflow-details/workflow-details.tsx +++ b/ui/src/app/workflows/components/workflow-details/workflow-details.tsx @@ -3,9 +3,9 @@ import * as classNames from 'classnames'; import * as React from 'react'; import {useContext, useEffect, useRef, useState} from 'react'; import {RouteComponentProps} from 'react-router'; -import {execSpec, Link, NodeStatus, Parameter, Workflow} from '../../../../models'; +import {ArtifactRepository, execSpec, Link, NodeStatus, Parameter, Workflow} from '../../../../models'; import {ANNOTATION_KEY_POD_NAME_VERSION} from '../../../shared/annotations'; -import {findArtifact} from '../../../shared/artifacts'; +import {artifactRepoHasLocation, findArtifact} from '../../../shared/artifacts'; import {uiUrl} from '../../../shared/base'; import {CostOptimisationNudge} from '../../../shared/components/cost-optimisation-nudge'; import {ErrorNotice} from '../../../shared/components/error-notice'; @@ -18,6 +18,7 @@ import {historyUrl} from '../../../shared/history'; import {getPodName, getTemplateNameFromNode} from '../../../shared/pod-name'; import {RetryWatch} from '../../../shared/retry-watch'; import {services} from '../../../shared/services'; +import {getResolvedTemplates} from '../../../shared/template-resolution'; import {useQueryParams} from '../../../shared/use-query-params'; import {useResizableWidth} from '../../../shared/use-resizable-width'; import {useTransition} from '../../../shared/use-transition'; @@ -68,6 +69,7 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps< const [error, setError] = useState(); const selectedNode = workflow && workflow.status && workflow.status.nodes && workflow.status.nodes[nodeId]; const selectedArtifact = workflow && workflow.status && findArtifact(workflow.status, nodeId); + const [selectedTemplateArtifactRepo, setSelectedTemplateArtifactRepo] = useState(); const isSidePanelExpanded = !!(selectedNode || selectedArtifact); const isSidePanelAnimating = useTransition(isSidePanelExpanded, ANIMATION_MS + ANIMATION_BUFFER_MS); const {width: sidePanelWidth, dragHandleProps: sidePanelDragHandleProps} = useResizableWidth({ @@ -101,6 +103,22 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps< ); }; + useEffect(() => { + // update the default Artifact Repository for the Template that corresponds to the selectedArtifact + // if there's an ArtifactLocation configured for the Template we use that + // otherwise we use the central one for the Workflow configured in workflow.status.artifactRepositoryRef.artifactRepository + // (Note that individual Artifacts may also override whatever this gets set to) + if (workflow && workflow.status && workflow.status.nodes && selectedArtifact) { + const template = getResolvedTemplates(workflow, workflow.status.nodes[selectedArtifact.nodeId]); + const artifactRepo = template.archiveLocation; + if (artifactRepo && artifactRepoHasLocation(artifactRepo)) { + setSelectedTemplateArtifactRepo(artifactRepo); + } else { + setSelectedTemplateArtifactRepo(workflow.status.artifactRepositoryRef.artifactRepository); + } + } + }, [workflow, selectedArtifact]); + useEffect(() => { history.push(historyUrl('workflows/{namespace}/{name}', {namespace, name, tab, nodeId, nodePanelView, sidePanel})); }, [namespace, name, tab, nodeId, nodePanelView, sidePanel]); @@ -450,9 +468,7 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps< onResume={() => renderResumePopup()} /> )} - {selectedArtifact && ( - - )} + {selectedArtifact && } ))} diff --git a/ui/src/models/workflows.ts b/ui/src/models/workflows.ts index 83bc16b30b2e..7c3d42f4a722 100644 --- a/ui/src/models/workflows.ts +++ b/ui/src/models/workflows.ts @@ -27,19 +27,37 @@ export interface Arguments { export interface AzureArtifactRepository { endpoint: string; container: string; + blob: string; } export interface GCSArtifactRepository { endpoint: string; bucket: string; + key: string; } export interface S3ArtifactRepository { endpoint: string; bucket: string; + key: string; } export interface OSSArtifactRepository { endpoint: string; bucket: string; + key: string; +} + +export interface GitArtifactRepository { + repo?: string; + endpoint?: string; + bucket?: string; +} + +export interface HTTPArtifactRepository { + url: string; +} + +export interface RawArtifactRepository { + data: string; } export interface ArtifactRepository { @@ -47,6 +65,9 @@ export interface ArtifactRepository { s3?: S3ArtifactRepository; oss?: OSSArtifactRepository; azure?: AzureArtifactRepository; + git?: GitArtifactRepository; + http?: HTTPArtifactRepository; + raw?: RawArtifactRepository; } export interface ArtifactRepositoryRefStatus { artifactRepository: ArtifactRepository; @@ -440,6 +461,11 @@ export interface Template { * Sidecars is a list of containers which run alongside the main container Sidecars are automatically killed when the main container completes */ sidecars?: UserContainer[]; + /** + * archiveLocation is the location in which all files related to the step will be stored (logs, artifacts, etc...). + * Can be overridden by individual items in outputs. If omitted, will use the default + */ + archiveLocation?: ArtifactRepository; /** * InitContainers is a list of containers which run before the main container. */