More work on the visualiser
This commit is contained in:
parent
64c601d8c8
commit
5852d1f67a
@ -89,6 +89,24 @@ const VisualiserTab: React.FC<VisualiserTabProps> = ({
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If multiple predecessors, position task at the average of their columns
|
||||
if (predecessors.length > 1) {
|
||||
const predColumns = predecessors
|
||||
.map((predGuid) => {
|
||||
const predTask = byGuid.get(predGuid);
|
||||
return predTask ? getColumn(predTask) : 0;
|
||||
})
|
||||
.filter((col) => col !== undefined);
|
||||
|
||||
if (predColumns.length > 0) {
|
||||
const avgColumn =
|
||||
predColumns.reduce((sum, col) => sum + col, 0) / predColumns.length;
|
||||
const column = Math.round(avgColumn);
|
||||
columnByGuid.set(guid, column);
|
||||
return column;
|
||||
}
|
||||
}
|
||||
|
||||
// Get predecessor column and find which child index this is
|
||||
const predTask = byGuid.get(predecessors[0]);
|
||||
if (!predTask) {
|
||||
@ -231,19 +249,130 @@ const VisualiserTab: React.FC<VisualiserTabProps> = ({
|
||||
if (numColumns <= 1) return [50];
|
||||
|
||||
return levelTasks.map((task) => {
|
||||
const predecessors = (task.config.predecessors as string[]) ?? [];
|
||||
const taskColumn =
|
||||
taskColumnMap.current.get(task.config.guid as string) ?? 0;
|
||||
|
||||
if (predecessors.length > 1) {
|
||||
const predColumns = predecessors
|
||||
.map((predGuid) => taskColumnMap.current.get(predGuid))
|
||||
.filter((col) => col !== undefined) as number[];
|
||||
|
||||
if (predColumns.length > 0) {
|
||||
const avgPredColumn =
|
||||
predColumns.reduce((sum, col) => sum + col, 0) / predColumns.length;
|
||||
const gridCol = avgPredColumn - columnRange.min;
|
||||
// Map averaged column to percentage for centered merges
|
||||
return ((gridCol + 0.5) / numColumns) * 100;
|
||||
}
|
||||
}
|
||||
|
||||
const gridCol = taskColumn - columnRange.min;
|
||||
// Map grid column to percentage (e.g., 2 columns: col 0 = 25%, col 1 = 75%)
|
||||
return ((gridCol + 0.5) / numColumns) * 100;
|
||||
});
|
||||
};
|
||||
|
||||
const getPredecessorPositionsByColumn = (
|
||||
levelTasks: CreateWorkflowTemplateVersion["tasks"][],
|
||||
): number[] => {
|
||||
const numColumns = columnRange.max - columnRange.min + 1;
|
||||
if (numColumns <= 1) return [50];
|
||||
|
||||
const predColumns = new Set<number>();
|
||||
|
||||
levelTasks.forEach((task) => {
|
||||
const preds = (task.config.predecessors as string[]) ?? [];
|
||||
preds.forEach((predGuid) => {
|
||||
const predColumn = taskColumnMap.current.get(predGuid);
|
||||
if (predColumn !== undefined) {
|
||||
predColumns.add(predColumn);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return Array.from(predColumns).map((predColumn) => {
|
||||
const gridCol = predColumn - columnRange.min;
|
||||
return ((gridCol + 0.5) / numColumns) * 100;
|
||||
});
|
||||
};
|
||||
|
||||
const renderConnector = (
|
||||
count: number,
|
||||
positions?: number[],
|
||||
predecessorPositions?: number[],
|
||||
currentLevelTasks?: CreateWorkflowTemplateVersion["tasks"][],
|
||||
) => {
|
||||
// Check if any task in this level has multiple predecessors from different columns
|
||||
const hasMultiplePredecessorColumns =
|
||||
currentLevelTasks &&
|
||||
currentLevelTasks.some((task) => {
|
||||
const preds = (task.config.predecessors as string[]) ?? [];
|
||||
if (preds.length <= 1) return false;
|
||||
|
||||
const predColumns = preds
|
||||
.map((predGuid) => taskColumnMap.current.get(predGuid))
|
||||
.filter((col) => col !== undefined) as number[];
|
||||
|
||||
return new Set(predColumns).size > 1; // Multiple different columns
|
||||
});
|
||||
|
||||
// If we have a merging scenario (multiple predecessors converging)
|
||||
if (
|
||||
hasMultiplePredecessorColumns &&
|
||||
predecessorPositions &&
|
||||
predecessorPositions.length > 1 &&
|
||||
positions
|
||||
) {
|
||||
const minPredX = Math.min(...predecessorPositions);
|
||||
const maxPredX = Math.max(...predecessorPositions);
|
||||
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="visualiser-connector-branch"
|
||||
viewBox="0 0 100 40"
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
{/* Vertical lines from each predecessor */}
|
||||
{predecessorPositions.map((x, idx) => (
|
||||
<line
|
||||
key={`pred-${idx}`}
|
||||
className="visualiser-connector-branch-line"
|
||||
x1={x}
|
||||
y1="0"
|
||||
x2={x}
|
||||
y2="14"
|
||||
/>
|
||||
))}
|
||||
{/* Horizontal line connecting all predecessors */}
|
||||
<line
|
||||
className="visualiser-connector-branch-line"
|
||||
x1={minPredX}
|
||||
y1="14"
|
||||
x2={maxPredX}
|
||||
y2="14"
|
||||
/>
|
||||
{/* Vertical lines down to children */}
|
||||
{positions.map((x, idx) => (
|
||||
<g key={`child-${idx}`}>
|
||||
<line
|
||||
className="visualiser-connector-branch-line"
|
||||
x1={x}
|
||||
y1="14"
|
||||
x2={x}
|
||||
y2="28"
|
||||
/>
|
||||
<polygon
|
||||
className="visualiser-connector-branch-arrow"
|
||||
points={`${x - 1.5},28 ${x + 1.5},28 ${x},34`}
|
||||
/>
|
||||
</g>
|
||||
))}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
if (count <= 1) {
|
||||
// For a single child, use predecessor position if available
|
||||
let startX = 50;
|
||||
@ -431,7 +560,8 @@ const VisualiserTab: React.FC<VisualiserTabProps> = ({
|
||||
renderConnector(
|
||||
levels[0].length,
|
||||
getConnectorPositionsByColumn(levels[0]),
|
||||
undefined,
|
||||
getPredecessorPositionsByColumn(levels[0]),
|
||||
levels[0],
|
||||
)}
|
||||
{levels.map((level, index) => (
|
||||
<React.Fragment key={`level-${index}`}>
|
||||
@ -461,6 +591,10 @@ const VisualiserTab: React.FC<VisualiserTabProps> = ({
|
||||
)?.length;
|
||||
const numColumns = columnRange.max - columnRange.min + 1;
|
||||
|
||||
const predecessors = task.config.predecessors as
|
||||
| string[]
|
||||
| undefined;
|
||||
|
||||
let styleObj: React.CSSProperties = {};
|
||||
|
||||
if (isRootTask && numColumns > 1) {
|
||||
@ -470,6 +604,28 @@ const VisualiserTab: React.FC<VisualiserTabProps> = ({
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
};
|
||||
} else if (predecessors && predecessors.length > 1) {
|
||||
// Tasks with multiple predecessors - span across predecessor columns
|
||||
const predColumns = predecessors
|
||||
.map((predGuid) => taskColumnMap.current.get(predGuid))
|
||||
.filter((col) => col !== undefined) as number[];
|
||||
|
||||
if (predColumns.length > 1) {
|
||||
const minPredCol = Math.min(...predColumns);
|
||||
const maxPredCol = Math.max(...predColumns);
|
||||
const startGridCol = minPredCol - columnRange.min + 1;
|
||||
const endGridCol = maxPredCol - columnRange.min + 2;
|
||||
|
||||
styleObj = {
|
||||
gridColumn: `${startGridCol} / ${endGridCol}`,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
};
|
||||
} else {
|
||||
// Fallback to normal positioning
|
||||
const gridColumn = taskColumn - columnRange.min + 1;
|
||||
styleObj = { gridColumn };
|
||||
}
|
||||
} else {
|
||||
// Child tasks positioned in their specific column
|
||||
const gridColumn = taskColumn - columnRange.min + 1;
|
||||
@ -503,12 +659,14 @@ const VisualiserTab: React.FC<VisualiserTabProps> = ({
|
||||
? renderConnector(
|
||||
levels[index + 1].length,
|
||||
getConnectorPositionsByColumn(levels[index + 1]),
|
||||
getConnectorPositionsByColumn(levels[index]),
|
||||
getPredecessorPositionsByColumn(levels[index + 1]),
|
||||
levels[index + 1],
|
||||
)
|
||||
: renderConnector(1, undefined, undefined)}
|
||||
: renderConnector(1, undefined, undefined, undefined)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
{levels.length === 0 && renderConnector(1)}
|
||||
{levels.length === 0 &&
|
||||
renderConnector(1, undefined, undefined, undefined)}
|
||||
<div className="visualiser-node">
|
||||
<div className="visualiser-node-content">
|
||||
<span>End</span>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user