Skip to content
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
Original file line number Diff line number Diff line change
@@ -1,96 +1,121 @@
import React from 'react';
import {
Model,
ModelKind,
withPanZoom,
GraphComponent,
useComponentFactory,
useModel,
ComponentFactory,
useLayoutFactory,
Graph,
Layout,
PipelineDagreLayout,
PipelineNodeModel,
Visualization,
VisualizationProvider,
useEventListener,
SelectionEventListener,
SELECTION_EVENT,
TopologyView,
VisualizationSurface,
useVisualizationController,
NODE_SEPARATION_HORIZONTAL,
GRAPH_LAYOUT_END_EVENT,
getSpacerNodes,
getEdgesFromNodes,
useVisualizationController
DEFAULT_EDGE_TYPE
} from '@patternfly/react-topology';
import '@patternfly/react-styles/css/components/Topology/topology-components.css';
import withTopologySetup from './utils/withTopologySetup';
import pipelineComponentFactory from './components/pipelineComponentFactory';
import { createFinallyTasks, createParallelTasks, createStatusTasks, setWhenStatus } from './utils/pipelineUtils';
import pipelineComponentFactory, { GROUPED_EDGE_TYPE } from './components/pipelineComponentFactory';
import { usePipelineOptions } from './usePipelineOptions';
import { useDemoPipelineNodes } from './useDemoPipelineNodes';
import { GROUPED_PIPELINE_NODE_SEPARATION_HORIZONTAL } from './components/DemoTaskGroupEdge';

export const PIPELINE_NODE_SEPARATION_VERTICAL = 65;

export const LAYOUT_TITLE = 'Layout';

const getModel = (layout: string): Model => {
const tasks: PipelineNodeModel[] = createStatusTasks('task', 4, undefined, false, true, true, true);
const PIPELINE_LAYOUT = 'PipelineLayout';
const GROUPED_PIPELINE_LAYOUT = 'GroupedPipelineLayout';

const whenTasks = tasks.reduce((acc, task, index) => {
if (index % (Math.floor(tasks.length / 3) + 1) !== 0) {
acc.push(task);
}
return acc;
}, []);
setWhenStatus(whenTasks);
const TopologyPipelineLayout: React.FC = () => {
const [selectedIds, setSelectedIds] = React.useState<string[]>();

for (let i = 0; i < tasks.length; i++) {
tasks[i + 1].runAfterTasks.push(tasks[i].id);
i++;
if (i + 1 < tasks.length) {
tasks[i + 1].runAfterTasks.push(tasks[i].id);
}
i++;
if (i + 1 < tasks.length) {
tasks[i + 1].runAfterTasks.push(tasks[i].id);
}
i++;
}
const controller = useVisualizationController();
const { contextToolbar, showContextMenu, showBadges, showIcons, showGroups, badgeTooltips } = usePipelineOptions(
true
);
const pipelineNodes = useDemoPipelineNodes(
showContextMenu,
showBadges,
showIcons,
badgeTooltips,
'PipelineDagreLayout',
showGroups
);

const parallelTasks = createParallelTasks('parallelTasks', tasks[9].id, 3, 2, true, true);
tasks.push(...parallelTasks);
React.useEffect(() => {
const spacerNodes = getSpacerNodes(pipelineNodes);
const nodes = [...pipelineNodes, ...spacerNodes];
const edges = getEdgesFromNodes(
nodes.filter(n => !n.group),
showGroups ? GROUPED_EDGE_TYPE : DEFAULT_EDGE_TYPE
);

const finallyNodes = createFinallyTasks('finally', 2, tasks, true);
const finallyGroup = {
id: 'finally-group',
type: 'finally-group',
children: finallyNodes.map(n => n.id),
group: true,
style: { padding: [35, 17] }
};
controller.fromModel(
{
graph: {
id: 'g1',
type: 'graph',
x: 25,
y: 25,
layout: showGroups ? GROUPED_PIPELINE_LAYOUT : PIPELINE_LAYOUT
},
nodes,
edges
},
true
);
controller.getGraph().layout();
}, [controller, pipelineNodes, showGroups]);

const spacerNodes = getSpacerNodes([...tasks, ...finallyNodes]);
const edges = getEdgesFromNodes([...tasks, ...finallyNodes, ...spacerNodes]);
useEventListener<SelectionEventListener>(SELECTION_EVENT, ids => {
setSelectedIds(ids);
});

return {
graph: {
id: 'g1',
type: 'graph',
x: 25,
y: 25,
layout
},
nodes: [...tasks, ...finallyNodes, ...spacerNodes, finallyGroup],
edges
};
return (
<TopologyView contextToolbar={contextToolbar}>
<VisualizationSurface state={{ selectedIds }} />
</TopologyView>
);
};

export const PipelineLayout = withTopologySetup(() => {
useLayoutFactory((type: string, graph: Graph): Layout | undefined => new PipelineDagreLayout(graph, { nodesep: 95 }));
useComponentFactory(pipelineComponentFactory);
const controller = useVisualizationController();
controller.setFitToScreenOnLayout(true);
TopologyPipelineLayout.displayName = 'TopologyPipelineLayout';

// support pan zoom and drag
useComponentFactory(
React.useCallback<ComponentFactory>(kind => {
if (kind === ModelKind.graph) {
return withPanZoom()(GraphComponent);
export const PipelineLayout = React.memo(() => {
const controller = new Visualization();
controller.setFitToScreenOnLayout(true);
controller.registerComponentFactory(pipelineComponentFactory);
controller.registerLayoutFactory(
(type: string, graph: Graph): Layout | undefined =>
new PipelineDagreLayout(graph, {
nodesep: PIPELINE_NODE_SEPARATION_VERTICAL,
ranksep:
type === GROUPED_PIPELINE_LAYOUT ? GROUPED_PIPELINE_NODE_SEPARATION_HORIZONTAL : NODE_SEPARATION_HORIZONTAL,
ignoreGroups: true
})
);
controller.fromModel(
{
graph: {
id: 'g1',
type: 'graph',
x: 25,
y: 25,
layout: PIPELINE_LAYOUT
}
return undefined;
}, [])
},
false
);
controller.addEventListener(GRAPH_LAYOUT_END_EVENT, () => {
controller.getGraph().fit(75);
});

useModel(getModel('PipelineDagreLayout'));
return null;
return (
<VisualizationProvider controller={controller}>
<TopologyPipelineLayout />
</VisualizationProvider>
);
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import { Checkbox, Flex, FlexItem, Radio, ToolbarItem } from '@patternfly/react-core';
import {
TopologyView,
Visualization,
Expand All @@ -12,150 +11,44 @@ import {
} from '@patternfly/react-topology';
import '@patternfly/react-styles/css/components/Topology/topology-components.css';
import pipelineComponentFactory from './components/pipelineComponentFactory';
import { createFinallyTasks, createStatusTasks, setWhenStatus } from './utils/pipelineUtils';
import { usePipelineOptions } from './usePipelineOptions';
import { useDemoPipelineNodes } from './useDemoPipelineNodes';

export const TASKS_TITLE = 'Tasks';

export const PipelineTasks: React.FC = () => {
const [showContext, setShowContext] = React.useState<boolean>(false);
const [showBadges, setShowBadges] = React.useState<boolean>(false);
const [showIcons, setShowIcons] = React.useState<boolean>(false);
const [selectedIds, setSelectedIds] = React.useState<string[]>();
const [badgeTooltips, setBadgeTooltips] = React.useState<boolean>(false);

const controller = useVisualizationController();
const { contextToolbar, showContextMenu, showBadges, showIcons, badgeTooltips } = usePipelineOptions();
const pipelineNodes = useDemoPipelineNodes(showContextMenu, showBadges, showIcons, badgeTooltips);

React.useEffect(() => {
const tasks = createStatusTasks(
'task',
4,
undefined,
false,
false,
showContext,
showBadges,
showIcons,
badgeTooltips
);
setWhenStatus(tasks);
const finallyNodes = createFinallyTasks('finally', 2, tasks);
const finallyGroup = {
id: 'finally-group',
type: 'finally-group',
children: finallyNodes.map(n => n.id),
group: true,
style: { padding: 30 }
};
const model = {
graph: {
id: 'g1',
type: 'graph',
x: 25,
y: 25
controller.fromModel(
{
graph: {
id: 'g1',
type: 'graph',
x: 25,
y: 25
},
nodes: pipelineNodes
},
nodes: [...tasks, ...finallyNodes, finallyGroup]
};
controller.fromModel(model, false);
}, [badgeTooltips, controller, showBadges, showContext, showIcons]);
false
);
}, [controller, pipelineNodes]);

useEventListener<SelectionEventListener>(SELECTION_EVENT, ids => {
setSelectedIds(ids);
});

const contextToolbar = (
<>
<ToolbarItem>
<Flex alignItems={{ default: 'alignItemsCenter' }}>
<FlexItem>Icons:</FlexItem>
<FlexItem>
<Radio
id="show-icons"
aria-label="Show icons"
label="Show"
name="show-icons"
isChecked={showIcons}
onChange={checked => checked && setShowIcons(true)}
/>
</FlexItem>
<FlexItem>
<Radio
id="hide-icons"
aria-label="Hide icons"
label="Hide"
name="hide-icons"
isChecked={!showIcons}
onChange={checked => checked && setShowIcons(false)}
/>
</FlexItem>
</Flex>
</ToolbarItem>
<ToolbarItem>
<Flex alignItems={{ default: 'alignItemsCenter' }}>
<FlexItem>Badges:</FlexItem>
<FlexItem>
<Radio
id="show-badges"
aria-label="Show badges"
label="Show"
name="show-badges"
isChecked={showBadges}
onChange={checked => checked && setShowBadges(true)}
/>
</FlexItem>
<FlexItem>
<Radio
id="hide-badges"
aria-label="Hide badges"
label="Hide"
name="hide-badges"
isChecked={!showBadges}
onChange={checked => checked && setShowBadges(false)}
/>
</FlexItem>
</Flex>
</ToolbarItem>
<ToolbarItem>
<Flex alignItems={{ default: 'alignItemsCenter' }}>
<FlexItem>Context menus:</FlexItem>
<FlexItem>
<Radio
id="show-menus"
aria-label="Show context menus"
label="Show"
name="show-menus"
isChecked={showContext}
onChange={checked => checked && setShowContext(true)}
/>
</FlexItem>
<FlexItem>
<Radio
id="hide-context"
aria-label="Hide context menus"
label="Hide"
name="hide-context"
isChecked={!showContext}
onChange={checked => checked && setShowContext(false)}
/>
</FlexItem>
<FlexItem className="pf-u-ml-2xl">
<Checkbox
id="badge-tips-checkbox"
label="Use tooltips for badges"
isChecked={badgeTooltips}
onChange={setBadgeTooltips}
/>
</FlexItem>
</Flex>
</ToolbarItem>
</>
);

return (
<TopologyView contextToolbar={contextToolbar}>
<VisualizationSurface state={{ selectedIds }} />
</TopologyView>
);
};

PipelineTasks.displayName = 'PipelineTasks';

export const TopologyPipelineTasks = React.memo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@
.pf-ri__topology-demo .pf-c-toolbar__item .pf-l-flex {
--pf-l-flex--FlexWrap: no-wrap;
}
.pf-ri__topology-demo .pf-c-toolbar__item .pf-l-flex > * {
--pf-l-flex--spacer: 8px;
}

.pf-ri__topology-demo .pf-c-toolbar__item .pf-c-form-control {
width: 85px;
}
Expand Down
Loading