Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,17 @@ const getExecutionData = async (projectId: string, domainId: string, executionId
};

const isExecutionTaskOrWorkflow = (executionData: Execution) => {
return executionData.spec.launchPlan.resourceType === ResourceType.TASK
return executionData.closure.workflowId.resourceType === ResourceType.TASK
? ResourceType.TASK
: ResourceType.WORKFLOW;
};

const getTaskOrWorkflowName = (executionData: Execution): string => {
return executionData.spec.launchPlan.name;
return executionData.closure.workflowId.name;
};

const getTaskOrWorkflowVersion = (executionData: Execution): string => {
return executionData.spec.launchPlan.version;
return executionData.closure.workflowId.version;
};

const getExecutionValue = (location: Location) => {
Expand Down Expand Up @@ -127,7 +127,7 @@ export const executonTaskWorkFlowNameAsyncSelfLink: BreadcrumbEntitySelfLinkAsyn
const resourceType = isExecutionTaskOrWorkflow(executionData);

const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain(
executionData.spec.launchPlan,
executionData.closure.workflowId,
breadcrumb,
);

Expand All @@ -154,7 +154,7 @@ export const executionTaskWorkflowVersions: BreadcrumbAsyncPopOverData = async (
const entityResourceVersion = getTaskOrWorkflowVersion(executionData);

const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain(
executionData.spec.launchPlan,
executionData.closure.workflowId,
breadcrumb,
);

Expand Down Expand Up @@ -341,7 +341,7 @@ export const executionTaskWorkflowViewAll: BreadcrumbAsyncViewAllLink = async (
const entityResourceName = getTaskOrWorkflowName(executionData);

const { project: desinationProject, domain: desinationDomain } = getExecutionSpecProjectDomain(
executionData.spec.launchPlan,
executionData.closure.workflowId,
breadcrumb,
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import Core from '@clients/common/flyteidl/core';
import { Execution } from '../../../../models/Execution/types';
import {
executonTaskWorkFlowNameAsyncValue,
executonTaskWorkFlowNameAsyncSelfLink,
executonNamedEntityAsyncValue,
} from '../executionContext';

jest.mock('@clients/primitives/SimpleCache/SimpleCacheCallbackManager', () => ({
SimpleCacheCallbackManager: jest.fn().mockImplementation(() => ({
getCachedOrFetch: jest.fn((_key: string, fn: () => Promise<Execution>) => fn()),
})),
}));

const mockGetExecution = jest.fn();
jest.mock('../../../../models/Execution/api', () => ({
getExecution: (...args: unknown[]) => mockGetExecution(...args),
listExecutions: jest.fn(),
}));

jest.mock('../../../../routes/routes', () => ({
Routes: {
WorkflowDetails: {
makeUrl: jest.fn(
(project: string, domain: string, name: string) =>
`/projects/${project}/domains/${domain}/workflows/${name}`,
),
},
TaskDetails: {
makeUrl: jest.fn(
(project: string, domain: string, name: string) =>
`/projects/${project}/domains/${domain}/tasks/${name}`,
),
},
ExecutionDetails: {
makeUrl: jest.fn(
({ project, domain, name }: { project: string; domain: string; name: string }) =>
`/projects/${project}/domains/${domain}/executions/${name}`,
),
},
EntityVersionDetails: {
makeUrl: jest.fn(),
},
},
}));

const createMockExecutionWithDifferentNames = (): Execution => ({
id: {
project: 'execution-project',
domain: 'execution-domain',
name: 'wf-execution-001',
},
spec: {
launchPlan: {
resourceType: Core.ResourceType.LAUNCH_PLAN,
project: 'launch-plan-project',
domain: 'launch-plan-domain',
name: 'hello_world_lp',
version: '2025-04-09-15-56-08',
},
inputs: { literals: {} },
metadata: {
mode: 0,
principal: 'user',
nesting: 0,
},
notifications: { notifications: [] },
},
closure: {
workflowId: {
resourceType: Core.ResourceType.WORKFLOW,
project: 'workflow-project',
domain: 'workflow-domain',
name: 'hello_world_wf',
version: '2025-04-09-15-56-08',
},
phase: 4,
createdAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 },
startedAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 },
},
});

const createMockTaskExecution = (): Execution => ({
id: {
project: 'test-project',
domain: 'development',
name: 'task-execution-001',
},
spec: {
launchPlan: {
resourceType: Core.ResourceType.LAUNCH_PLAN,
project: 'test-project',
domain: 'development',
name: 'my-task-launch-plan',
version: 'v1',
},
inputs: { literals: {} },
metadata: {
mode: 0,
principal: 'user',
nesting: 0,
},
notifications: { notifications: [] },
},
closure: {
workflowId: {
resourceType: Core.ResourceType.TASK,
project: 'test-project',
domain: 'development',
name: 'my-actual-task',
version: 'v1',
},
phase: 3,
createdAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 },
startedAt: { seconds: { low: 1732000000, high: 0, unsigned: false }, nanos: 0 },
},
});

describe('executionContext breadcrumb functions', () => {
const mockBreadcrumb = {
projectId: 'workflow-domain',
domainId: 'browsing-domain',
value: '',
defaultValue: () => '',
};

beforeEach(() => {
jest.clearAllMocks();
});

describe('executonTaskWorkFlowNameAsyncValue', () => {
it('should return the workflow name from closure.workflowId, NOT the launch plan name', async () => {
const mockExecution = createMockExecutionWithDifferentNames();
mockGetExecution.mockResolvedValue(mockExecution);

const mockLocation = {
pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001',
} as Location;

const result = await executonTaskWorkFlowNameAsyncValue(mockLocation, mockBreadcrumb as any);

expect(result).toBe('hello_world_wf');
expect(result).not.toBe('hello_world_lp');
});

it('should return the task name for task executions', async () => {
const mockExecution = createMockTaskExecution();
mockGetExecution.mockResolvedValue(mockExecution);

const mockLocation = {
pathname: '/projects/test-project/domains/development/executions/task-execution-001',
} as Location;

const result = await executonTaskWorkFlowNameAsyncValue(mockLocation, {
...mockBreadcrumb,
projectId: 'test-project',
} as any);

expect(result).toBe('my-actual-task');
expect(result).not.toBe('my-task-launch-plan');
});
});

describe('executonNamedEntityAsyncValue', () => {
it('should return "workflows" for workflow executions', async () => {
const mockExecution = createMockExecutionWithDifferentNames();
mockGetExecution.mockResolvedValue(mockExecution);

const mockLocation = {
pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001',
} as Location;

const result = await executonNamedEntityAsyncValue(mockLocation, mockBreadcrumb as any);

expect(result).toBe('workflows');
});

it('should return "tasks" for task executions', async () => {
const mockExecution = createMockTaskExecution();
mockGetExecution.mockResolvedValue(mockExecution);

const mockLocation = {
pathname: '/projects/test-project/domains/development/executions/task-execution-001',
} as Location;

const result = await executonNamedEntityAsyncValue(mockLocation, {
...mockBreadcrumb,
projectId: 'test-project',
} as any);

expect(result).toBe('tasks');
});
});

describe('executonTaskWorkFlowNameAsyncSelfLink', () => {
it('should generate link to the actual workflow, not the launch plan', async () => {
const mockExecution = createMockExecutionWithDifferentNames();
mockGetExecution.mockResolvedValue(mockExecution);

const mockLocation = {
pathname: '/projects/flytesnacks/domains/development/executions/wf-execution-001',
} as Location;

const result = await executonTaskWorkFlowNameAsyncSelfLink(
mockLocation,
mockBreadcrumb as any,
);

expect(result).toBe(
'/projects/workflow-project/domains/workflow-domain/workflows/hello_world_wf',
);
expect(result).not.toContain('hello_world_lp');
});

it('should generate link to task details for task executions', async () => {
const mockExecution = createMockTaskExecution();
mockGetExecution.mockResolvedValue(mockExecution);

const mockLocation = {
pathname: '/projects/test-project/domains/development/executions/task-execution-001',
} as Location;

const result = await executonTaskWorkFlowNameAsyncSelfLink(mockLocation, {
...mockBreadcrumb,
projectId: 'test-project',
} as any);

expect(result).toContain('my-actual-task');
expect(result).toContain('/tasks/');
expect(result).not.toContain('my-task-launch-plan');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const contextualBreadcrumbRegistryList: Breadcrumb[] = [
}),
makeBreadcrumb({
id: 'executions:task-workflow-name',
label: 'Launch Plan Name',
label: 'Workflow Name',
defaultValue: 'Executions',
popoverTitle: 'Versions',
asyncValue: executonTaskWorkFlowNameAsyncValue,
Expand Down