diff --git a/api/jsonschema/schema.json b/api/jsonschema/schema.json index 74b5820ec259..e8a0bda4f2a4 100644 --- a/api/jsonschema/schema.json +++ b/api/jsonschema/schema.json @@ -3814,11 +3814,11 @@ "type": "string" }, "scope": { - "description": "Either \"workflow\" or \"pod\"", + "description": "\"workflow\", \"pod\", \"pod-logs\", \"event-source-logs\", \"sensor-logs\" or \"chat\"", "type": "string" }, "url": { - "description": "The URL. May contain \"${metadata.namespace}\", \"${metadata.name}\", \"${status.startedAt}\" and \"${status.finishedAt}\".", + "description": "The URL. Can contain \"${metadata.namespace}\", \"${metadata.name}\", \"${status.startedAt}\", \"${status.finishedAt}\" or any other element in workflow yaml, e.g. \"${io.argoproj.workflow.v1alpha1.metadata.annotations.userDefinedKey}\"", "type": "string" } }, diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 1472f0cb6115..7c0b1dc7d92d 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -7234,11 +7234,11 @@ "type": "string" }, "scope": { - "description": "Either \"workflow\" or \"pod\"", + "description": "\"workflow\", \"pod\", \"pod-logs\", \"event-source-logs\", \"sensor-logs\" or \"chat\"", "type": "string" }, "url": { - "description": "The URL. May contain \"${metadata.namespace}\", \"${metadata.name}\", \"${status.startedAt}\" and \"${status.finishedAt}\".", + "description": "The URL. Can contain \"${metadata.namespace}\", \"${metadata.name}\", \"${status.startedAt}\", \"${status.finishedAt}\" or any other element in workflow yaml, e.g. \"${io.argoproj.workflow.v1alpha1.metadata.annotations.userDefinedKey}\"", "type": "string" } }, diff --git a/pkg/apis/workflow/v1alpha1/generated.proto b/pkg/apis/workflow/v1alpha1/generated.proto index 8d18811e0708..5cbdec408239 100644 --- a/pkg/apis/workflow/v1alpha1/generated.proto +++ b/pkg/apis/workflow/v1alpha1/generated.proto @@ -552,10 +552,10 @@ message Link { // The name of the link, E.g. "Workflow Logs" or "Pod Logs" optional string name = 1; - // Either "workflow" or "pod" + // "workflow", "pod", "pod-logs", "event-source-logs", "sensor-logs" or "chat" optional string scope = 2; - // The URL. May contain "${metadata.namespace}", "${metadata.name}", "${status.startedAt}" and "${status.finishedAt}". + // The URL. Can contain "${metadata.namespace}", "${metadata.name}", "${status.startedAt}", "${status.finishedAt}" or any other element in workflow yaml, e.g. "${workflow.metadata.annotations.userDefinedKey}" optional string url = 3; } diff --git a/pkg/apis/workflow/v1alpha1/info.go b/pkg/apis/workflow/v1alpha1/info.go index a8ee216d2c6a..1a17e5af04ce 100644 --- a/pkg/apis/workflow/v1alpha1/info.go +++ b/pkg/apis/workflow/v1alpha1/info.go @@ -6,8 +6,8 @@ package v1alpha1 type Link struct { // The name of the link, E.g. "Workflow Logs" or "Pod Logs" Name string `json:"name" protobuf:"bytes,1,opt,name=name"` - // Either "workflow" or "pod" + // "workflow", "pod", "pod-logs", "event-source-logs", "sensor-logs" or "chat" Scope string `json:"scope" protobuf:"bytes,2,opt,name=scope"` - // The URL. May contain "${metadata.namespace}", "${metadata.name}", "${status.startedAt}" and "${status.finishedAt}". + // The URL. Can contain "${metadata.namespace}", "${metadata.name}", "${status.startedAt}", "${status.finishedAt}" or any other element in workflow yaml, e.g. "${workflow.metadata.annotations.userDefinedKey}" URL string `json:"url" protobuf:"bytes,3,opt,name=url"` } diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index 7a488e9fb58e..f7bd3cd556b9 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -2315,7 +2315,7 @@ func schema_pkg_apis_workflow_v1alpha1_Link(ref common.ReferenceCallback) common }, "scope": { SchemaProps: spec.SchemaProps{ - Description: "Either \"workflow\" or \"pod\"", + Description: "\"workflow\", \"pod\", \"pod-logs\", \"event-source-logs\", \"sensor-logs\" or \"chat\"", Default: "", Type: []string{"string"}, Format: "", @@ -2323,7 +2323,7 @@ func schema_pkg_apis_workflow_v1alpha1_Link(ref common.ReferenceCallback) common }, "url": { SchemaProps: spec.SchemaProps{ - Description: "The URL. May contain \"${metadata.namespace}\", \"${metadata.name}\", \"${status.startedAt}\" and \"${status.finishedAt}\".", + Description: "The URL. Can contain \"${metadata.namespace}\", \"${metadata.name}\", \"${status.startedAt}\", \"${status.finishedAt}\" or any other element in workflow yaml, e.g. \"${workflow.metadata.annotations.userDefinedKey}\"", Default: "", Type: []string{"string"}, Format: "", diff --git a/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx b/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx index acd615825ede..98833955e87a 100644 --- a/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx +++ b/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx @@ -6,6 +6,7 @@ import {execSpec, Link, Workflow} from '../../../../models'; import {uiUrl} from '../../../shared/base'; import {BasePage} from '../../../shared/components/base-page'; import {ErrorNotice} from '../../../shared/components/error-notice'; +import {ProcessURL} from '../../../shared/components/links'; import {Loading} from '../../../shared/components/loading'; import {ResourceEditor} from '../../../shared/components/resource-editor/resource-editor'; import {services} from '../../../shared/services'; @@ -261,10 +262,17 @@ export class ArchivedWorkflowDetails extends BasePage, } private openLink(link: Link) { - document.location.href = link.url - .replace(/\${metadata\.namespace}/g, this.state.workflow.metadata.namespace) - .replace(/\${metadata\.name}/g, this.state.workflow.metadata.name) - .replace(/\${status\.startedAt}/g, this.state.workflow.status.startedAt) - .replace(/\${status\.finishedAt}/g, this.state.workflow.status.finishedAt); + const object = { + metadata: { + namespace: this.state.workflow.metadata.namespace, + name: this.state.workflow.metadata.name + }, + workflow: this.state.workflow, + status: { + startedAt: this.state.workflow.status.startedAt, + finishedAt: this.state.workflow.status.finishedAt + } + }; + document.location.href = ProcessURL(link.url, object); } } diff --git a/ui/src/app/shared/components/links.tsx b/ui/src/app/shared/components/links.tsx index 8d0c176ef6e5..e8c0336c19a6 100644 --- a/ui/src/app/shared/components/links.tsx +++ b/ui/src/app/shared/components/links.tsx @@ -1,11 +1,23 @@ import {ObjectMeta} from 'argo-ui/src/models/kubernetes'; import {useEffect, useState} from 'react'; import React = require('react'); -import {Link} from '../../../models'; +import {Link, Workflow} from '../../../models'; import {services} from '../services'; import {Button} from './button'; -export const Links = ({scope, object, button}: {scope: string; object: {metadata: ObjectMeta; status?: any}; button?: boolean}) => { +export const ProcessURL = (url: string, jsonObject: any) => { + /* replace ${} from input url with corresponding elements from object + return null if element is not found*/ + return url.replace(/\${[^}]*}/g, x => { + const res = x + .replace(/[${}]+/g, '') + .split('.') + .reduce((p: any, c: string) => (p && p[c]) || null, jsonObject); + return res; + }); +}; + +export const Links = ({scope, object, button}: {scope: string; object: {metadata: ObjectMeta; workflow?: Workflow; status?: any}; button?: boolean}) => { const [links, setLinks] = useState(); const [error, setError] = useState(); @@ -18,12 +30,7 @@ export const Links = ({scope, object, button}: {scope: string; object: {metadata }, []); const formatUrl = (url: string) => { - const status = object.status || {}; - return url - .replace(/\${metadata\.namespace}/g, object.metadata.namespace) - .replace(/\${metadata\.name}/g, object.metadata.name) - .replace(/\${status\.startedAt}/g, status.startedAt) - .replace(/\${status\.finishedAt}/g, status.finishedAt); + return ProcessURL(url, object); }; const openLink = (url: string) => { 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 502bc021a6ed..4dc81f63cdbc 100644 --- a/ui/src/app/workflows/components/workflow-details/workflow-details.tsx +++ b/ui/src/app/workflows/components/workflow-details/workflow-details.tsx @@ -7,6 +7,7 @@ import {execSpec, Link, Workflow} from '../../../../models'; import {uiUrl} from '../../../shared/base'; import {CostOptimisationNudge} from '../../../shared/components/cost-optimisation-nudge'; import {ErrorNotice} from '../../../shared/components/error-notice'; +import {ProcessURL} from '../../../shared/components/links'; import {Loading} from '../../../shared/components/loading'; import {SecurityNudge} from '../../../shared/components/security-nudge'; import {hasWarningConditionBadge} from '../../../shared/conditions-panel'; @@ -201,11 +202,19 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps< }, [namespace, name]); const openLink = (link: Link) => { - const url = link.url - .replace(/\${metadata\.namespace}/g, workflow.metadata.namespace) - .replace(/\${metadata\.name}/g, workflow.metadata.name) - .replace(/\${status\.startedAt}/g, workflow.status.startedAt) - .replace(/\${status\.finishedAt}/g, workflow.status.finishedAt); + const object = { + metadata: { + namespace: workflow.metadata.namespace, + name: workflow.metadata.name + }, + workflow, + status: { + startedAt: workflow.status.startedAt, + finishedAt: workflow.status.finishedAt + } + }; + const url = ProcessURL(link.url, object); + if ((window.event as MouseEvent).ctrlKey) { window.open(url, '_blank'); } else { diff --git a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx index e9faaf30756b..2c1bdb7c68fa 100644 --- a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx +++ b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx @@ -122,6 +122,7 @@ export const WorkflowLogsViewer = ({workflow, nodeId, container, archived}: Work namespace: workflow.metadata.namespace, name: podName }, + workflow, status: { startedAt: workflow.status.startedAt, finishedAt: workflow.status.finishedAt diff --git a/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx b/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx index 964c43686eec..44e35d6fba78 100644 --- a/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx +++ b/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx @@ -166,6 +166,7 @@ const WorkflowNodeSummary = (props: Props) => { namespace: props.workflow.metadata.namespace, name: props.node.id }, + workflow: props.workflow, status: { startedAt: props.node.startedAt, finishedAt: props.node.finishedAt