Skip to content
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fb68429
feat(RHOAIENG-66823): make pipeline graphs accessible to keyboard and…
danreed-rh Oct 9, 2026
8e4b054
test(RHOAIENG-66823): avoid fake clock with Monaco tokenizer
danreed-rh Oct 9, 2026
65986b0
fix(RHOAIENG-66823): address pipeline graph review feedback
danreed-rh Oct 9, 2026
e69fb4c
fix(RHOAIENG-66823): activate grouped tasks with keyboard
danreed-rh Oct 9, 2026
332f2d3
Merge branch 'main' into RHOAIENG-66823/pipeline-a11y-fixed
danreed-rh Oct 12, 2026
e957b28
fix(RHOAIENG-66823): pan pipeline graph to keyboard focus
danreed-rh Oct 12, 2026
c9aa256
Fix pipeline graph keyboard focus and group controls
danreed-rh Oct 12, 2026
312ebb6
Merge branch 'main' into RHOAIENG-66823/pipeline-a11y-fixed
danreed-rh Oct 13, 2026
e0ed2f4
Merge branch 'main' into RHOAIENG-66823/pipeline-a11y-fixed
danreed-rh Oct 15, 2026
f574886
RHOAIENG-66823: Align cached group task status and simplify graph sty…
danreed-rh Oct 15, 2026
612eca3
fix(RHOAIENG-66823): address pipeline graph review feedback
danreed-rh Oct 15, 2026
4c455e7
test(RHOAIENG-66823): use stable artifact hover selectors
danreed-rh Oct 15, 2026
78329b2
Merge branch 'main' into RHOAIENG-66823/pipeline-a11y-fixed
danreed-rh Oct 16, 2026
1529955
fix: preserve focus when opening pipeline group details
danreed-rh Oct 16, 2026
5c95c6b
Merge branch 'main' into RHOAIENG-66823/pipeline-a11y-fixed
danreed-rh Oct 19, 2026
029b5be
fix(pipelines): address topology accessibility review findings
danreed-rh Oct 20, 2026
48975be
fix(pipelines): align group controls and preserve keyboard focus
danreed-rh Oct 20, 2026
8f44785
fix: preserve drawer focus after group popover closes
danreed-rh Oct 20, 2026
dcf9f4f
RHOAIENG-66823 Address pipeline graph review feedback
danreed-rh Oct 21, 2026
db0375a
RHOAIENG-66823: preserve focus on group toggle
danreed-rh Oct 21, 2026
346c983
Merge branch 'main' into RHOAIENG-66823/pipeline-a11y-fixed
danreed-rh Oct 22, 2026
a14c0d2
fix(pipelines): address group accessibility review feedback
danreed-rh Oct 22, 2026
048ae7c
Merge branch 'main' into RHOAIENG-66823/pipeline-a11y-fixed
danreed-rh Oct 23, 2026
e874590
Merge branch 'main' into RHOAIENG-66823/pipeline-a11y-fixed
danreed-rh Oct 27, 2026
4777516
fix(pipelines): address graph accessibility review feedback
danreed-rh Oct 27, 2026
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
7 changes: 7 additions & 0 deletions frontend/docs/pipelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
- Manage Kubeflow Pipelines (KFP) v2 workflows in a Data Science Project: import definitions, create and schedule runs, inspect DAGs and outputs, compare metrics, and browse MLMD artifacts and executions.
- Namespace-scoped; requires a ready pipeline server (`DSPipelineKind` CR) before operations are available.

## Keyboard interaction with pipeline graphs

- Tab through task, artifact, and task-group controls in visual reading order. Screen readers announce each control's name and available status.
- Press Enter or Space on a task or artifact to open its details. Closing the details returns focus to the graph control.
- For a collapsed task group, use its task-list button to choose a child or view group details. Use the task-group toggle to expand or collapse the group.
- Focusing a graph control pans it into the visible graph viewport when needed.

## UI Entry Points

| Nav Item | Route | Feature Flag(s) Required |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const PipelineDetails: PipelineCoreDetailsPageComponent = ({ breadcrumbPath }) =
const panelContent = selectedNode ? (
<SelectedTaskDrawerContent
task={selectedNode.data.pipelineTask}
onClose={() => setSelectedIds(undefined)}
onClose={() => setSelectedIds([])}
/>
) : null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const SelectedTaskDrawerContent: React.FC<SelectedTaskDrawerContentProps> = ({ t
return (
<>
<DrawerHead>
<Title headingLevel="h2" size="xl" data-testid="pipeline-task-name">
<Title headingLevel="h2" size="xl" tabIndex={-1} data-testid="pipeline-drawer-task-title">
{task.name} {task.type === 'artifact' ? 'Artifact details' : ''}
</Title>
<DrawerActions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const PipelineRecurringRunDetails: PipelineCoreDetailsPageComponent = ({
const panelContent = selectedNode ? (
<SelectedTaskDrawerContent
task={selectedNode.data.pipelineTask}
onClose={() => setSelectedIds(undefined)}
onClose={() => setSelectedIds([])}
/>
) : null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const PipelineRunDetails: React.FC<
<PipelineRunDrawerRightContent
task={selectedNode.data.pipelineTask}
upstreamTaskName={selectedNode.runAfterTasks?.[0]}
onClose={() => setSelectedIds(undefined)}
onClose={() => setSelectedIds([])}
executions={drawerExecutions}
run={run}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ const PipelineRunDrawerRightContent: React.FC<PipelineRunDrawerRightContentProps
) : (
<>
<DrawerHead>
<Title headingLevel="h2" size="xl">
<Title
headingLevel="h2"
size="xl"
tabIndex={-1}
data-testid="pipeline-drawer-task-title"
>
{task.name}
</Title>
{task.status?.podName && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,12 @@ const PipelineRunDrawerRightTabs: React.FC<PipelineRunDrawerRightTabsProps> = ({

return (
<>
<Tabs activeKey={selection} mountOnEnter>
<Tabs
activeKey={selection}
mountOnEnter
aria-label="Pipeline task details"
onSelect={(_, tabKey) => setSelection(String(tabKey))}
>
{Object.entries(tabs).map(([tabName, { title, isDisabled }]) => (
<Tab
data-testid={`right-drawer-tab-${tabName}`}
Expand All @@ -90,7 +95,6 @@ const PipelineRunDrawerRightTabs: React.FC<PipelineRunDrawerRightTabsProps> = ({
eventKey={tabName}
tabContentId={tabName}
isDisabled={isDisabled}
onClick={() => setSelection(tabName)}
/>
))}
</Tabs>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const ArtifactNodeDrawerContent: React.FC<ArtifactNodeDrawerContentProps>
return task ? (
<>
<DrawerHead>
<Title headingLevel="h2" size="xl">
<Title headingLevel="h2" size="xl" tabIndex={-1} data-testid="pipeline-drawer-task-title">
{task.name}
</Title>
{task.status?.podName && <Content component="small">{task.status.podName}</Content>}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jest.mock('@patternfly/react-topology', () => ({
Skipped: 'Skipped',
},
observer: (c: unknown) => c,
action: (fn: (...args: unknown[]) => unknown) => fn,
GraphComponent: {},
ModelKind: { graph: 'graph', node: 'node', edge: 'edge' },
ComponentFactory: {},
Expand Down
25 changes: 21 additions & 4 deletions frontend/src/concepts/topology/NodeStatusIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,31 @@ import {
CheckCircleIcon,
ExclamationCircleIcon,
InProgressIcon,
OutlinedWindowRestoreIcon,
PendingIcon,
} from '@patternfly/react-icons';
import { RunStatus } from '@patternfly/react-topology';
import { Icon, Tooltip } from '@patternfly/react-core';
import { runtimeStateLabels, RuntimeStateKF } from '#~/concepts/pipelines/kfTypes';
import {
ExecutionStateKF,
runtimeStateLabels,
RuntimeStateKF,
} from '#~/concepts/pipelines/kfTypes';

const NodeStatusIcon: React.FC<{ runStatus: RunStatus | string }> = ({ runStatus }) => {
const NodeStatusIcon: React.FC<{
runStatus?: RunStatus | string;
executionState?: ExecutionStateKF | string;
}> = ({ runStatus, executionState }) => {
let icon: React.ReactNode;
let status: React.ComponentProps<typeof Icon>['status'];
let label: string;

switch (runStatus) {
switch (executionState === ExecutionStateKF.CACHED ? ExecutionStateKF.CACHED : runStatus) {
case ExecutionStateKF.CACHED:
icon = <OutlinedWindowRestoreIcon />;
status = 'success';
label = 'Cached';
break;
case RunStatus.Pending:
case RunStatus.Idle:
icon = <PendingIcon />;
Expand Down Expand Up @@ -54,9 +67,13 @@ const NodeStatusIcon: React.FC<{ runStatus: RunStatus | string }> = ({ runStatus
label = '';
}

if (!icon || !label) {
return null;
}

return (
<Tooltip content={label}>
Comment thread
danreed-rh marked this conversation as resolved.
<Icon status={status} isInline>
<Icon status={status} isInline role="img" aria-label={label}>
{icon}
</Icon>
</Tooltip>
Expand Down
Loading
Loading