Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UI] Human readable workflow task display names #3225

Merged
merged 2 commits into from
Mar 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions frontend/src/lib/ParserUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Metadata } from 'third_party/argo-ui/argo_template';

export function parseTaskDisplayName(metadata?: Metadata): string | undefined {
if (!metadata?.annotations) {
return undefined;
}
const taskDisplayName = metadata.annotations['pipelines.kubeflow.org/task_display_name'];
let componentDisplayName: string | undefined;
try {
componentDisplayName = JSON.parse(metadata.annotations['pipelines.kubeflow.org/component_spec'])
.name;
} catch (err) {
// Expected error: metadata is missing or malformed
}
return taskDisplayName || componentDisplayName;
}
22 changes: 22 additions & 0 deletions frontend/src/lib/StaticGraphParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,28 @@ describe('StaticGraphParser', () => {
expect(g.node('/task-1').label).toEqual('TaskDisplayName');
});

it("uses task's annotation component_name as node label when present", () => {
const workflow = newWorkflow();
workflow.spec.templates[1].metadata = {
annotations: {
'pipelines.kubeflow.org/component_spec': '{"name":"Component Display Name"}',
},
};
const g = createGraph(workflow);
expect(g.node('/task-1').label).toEqual('Component Display Name');
});

it("uses task's default node label when component_name is malformed", () => {
const workflow = newWorkflow();
workflow.spec.templates[1].metadata = {
annotations: {
'pipelines.kubeflow.org/component_spec': '"name":"Component Display Name"}',
},
};
const g = createGraph(workflow);
expect(g.node('/task-1').label).not.toEqual('Component Display Name');
});

it('adds an unconnected node for the onExit template, if onExit is specified', () => {
const workflow = newWorkflow();
workflow.spec.onExit = 'on-exit';
Expand Down
9 changes: 2 additions & 7 deletions frontend/src/lib/StaticGraphParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Template, Workflow } from '../../third_party/argo-ui/argo_template';
import { color } from '../Css';
import { Constants } from './Constants';
import { logger } from './Utils';
import { parseTaskDisplayName } from './ParserUtils';

export type nodeType = 'container' | 'resource' | 'dag' | 'unknown';

Expand Down Expand Up @@ -177,13 +178,7 @@ function buildDag(
if (child.nodeType === 'dag') {
buildDag(graph, task.template, templates, alreadyVisited, nodeId);
} else if (child.nodeType === 'container' || child.nodeType === 'resource') {
const metadata = child.template.metadata;
if (metadata && metadata.annotations) {
const displayName = metadata.annotations['pipelines.kubeflow.org/task_display_name'];
if (displayName) {
nodeLabel = displayName;
}
}
nodeLabel = parseTaskDisplayName(child.template.metadata) || nodeLabel;
_populateInfoFromTemplate(info, child.template);
} else {
throw new Error(
Expand Down
23 changes: 19 additions & 4 deletions frontend/src/lib/WorkflowParser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { color } from '../Css';
import { NodePhase } from '../lib/StatusUtils';
import { Constants } from './Constants';
import WorkflowParser, { StorageService } from './WorkflowParser';
import { Workflow } from 'third_party/argo-ui/argo_template';

describe('WorkflowParser', () => {
describe('createRuntimeGraph', () => {
Expand Down Expand Up @@ -310,15 +311,15 @@ describe('WorkflowParser', () => {
expect(g.node('exitNode').label).toEqual('onExit - clean');
});

it('gives nodes customized labels based on template annotation', () => {
const workflow = {
function singleNodeWorkflow() {
return {
metadata: { name: 'testWorkflow' },
spec: {
templates: [
{
metadata: {
annotations: {
'pipelines.kubeflow.org/task_display_name': 'Customized name',
// 'pipelines.kubeflow.org/task_display_name': 'Customized name',
},
},
name: 'some-template',
Expand All @@ -337,8 +338,22 @@ describe('WorkflowParser', () => {
},
},
};
const g = WorkflowParser.createRuntimeGraph(workflow as any);
}

it('gives nodes customized labels based on template annotation', () => {
const workflow1 = singleNodeWorkflow();
workflow1.spec.templates[0].metadata.annotations = {
'pipelines.kubeflow.org/task_display_name': 'Customized name',
};
const g = WorkflowParser.createRuntimeGraph(workflow1 as any);
expect(g.node('node1').label).toEqual('Customized name');

const workflow2 = singleNodeWorkflow();
workflow2.spec.templates[0].metadata.annotations = {
'pipelines.kubeflow.org/component_spec': '{"name":"Component Name"}',
};
const g2 = WorkflowParser.createRuntimeGraph(workflow2 as any);
expect(g2.node('node1').label).toEqual('Component Name');
});
});

Expand Down
8 changes: 2 additions & 6 deletions frontend/src/lib/WorkflowParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { statusToIcon } from '../pages/Status';
import { Constants } from './Constants';
import { KeyValue } from './StaticGraphParser';
import { hasFinished, NodePhase, statusToBgColor } from './StatusUtils';
import { parseTaskDisplayName } from './ParserUtils';

export enum StorageService {
GCS = 'gcs',
Expand Down Expand Up @@ -96,12 +97,7 @@ export default class WorkflowParser {
const tmpl = workflow.spec.templates.find(
t => !!t && !!t.name && t.name === node.templateName,
);
if (tmpl && tmpl.metadata && tmpl.metadata.annotations) {
const displayName = tmpl.metadata.annotations['pipelines.kubeflow.org/task_display_name'];
if (displayName) {
nodeLabel = displayName;
}
}
nodeLabel = parseTaskDisplayName(tmpl?.metadata) || nodeLabel;
}

g.setNode(node.id, {
Expand Down