mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-21 16:50:49 +00:00
Backport #38980 The workflow graph decided which job rows belonged to the same matrix by parsing display names: it stripped a trailing `" (...)"` off `name` and grouped rows sharing the prefix. That guesses at a string the user controls, and it fails both ways. `jobparser` only appends the ` (<combination>)` suffix when `name:` contains no `${{ }}`, so a leg named `E2E on ${{ matrix.browser }}` never grouped, while two unrelated jobs `build (fast)` and `build (slow)` folded into one bogus matrix panel. Matrix legs already have a real identity: expansion clones one row per combination, all sharing the workflow's `JobID` and differing only in `Name`. Group on that instead, so a matrix is whatever the backend says it is. Matrix expansion state is keyed on the graph node id for the same reason. Closes https://github.com/go-gitea/gitea/issues/38975, though that report's own example already groups on main, since `explicit (${{ matrix.leg }})` interpolates to a name that still ends in a suffix. The interpolated shapes above are the broken ones. ## Screenshots: Before: <img width="1268" height="618" alt="image" src="https://github.com/user-attachments/assets/2d98dd1f-5454-423c-b610-8db920f1e99c" /> after: <img width="1145" height="607" alt="image" src="https://github.com/user-attachments/assets/25da1804-8386-4f5b-a4e3-f63380010907" /> _Assisted-by: Claude Code:claude-opus-5_ Co-authored-by: bircni <bircni@icloud.com> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import {computed, onMounted, onUnmounted, ref, watch} from 'vue';
|
||||
import {computed, onMounted, onUnmounted, ref, shallowRef, watch} from 'vue';
|
||||
import {SvgIcon} from '../svg.ts';
|
||||
import ActionStatusIcon from './ActionStatusIcon.vue';
|
||||
import {localUserSettings} from '../modules/user-settings.ts';
|
||||
@@ -48,17 +48,17 @@ const graphContainer = ref<HTMLElement | null>(null);
|
||||
const hoveredGraphId = ref<string | null>(null);
|
||||
|
||||
const stateKey = () => `${props.store.viewData.currentRun.repoId}-${props.workflowId}`;
|
||||
const expandedMatrixKeys = ref<Set<string>>(new Set());
|
||||
const expandedMatrixNodeIds = shallowRef<Set<string>>(new Set()); // always replaced wholesale, never mutated
|
||||
|
||||
function isMatrixExpanded(key: string): boolean {
|
||||
return expandedMatrixKeys.value.has(key);
|
||||
function isMatrixExpanded(nodeId: string): boolean {
|
||||
return expandedMatrixNodeIds.value.has(nodeId);
|
||||
}
|
||||
|
||||
function toggleMatrixExpanded(key: string) {
|
||||
const next = new Set(expandedMatrixKeys.value);
|
||||
if (next.has(key)) next.delete(key);
|
||||
else next.add(key);
|
||||
expandedMatrixKeys.value = next;
|
||||
function toggleMatrixExpanded(nodeId: string) {
|
||||
const next = new Set(expandedMatrixNodeIds.value);
|
||||
if (next.has(nodeId)) next.delete(nodeId);
|
||||
else next.add(nodeId);
|
||||
expandedMatrixNodeIds.value = next;
|
||||
}
|
||||
|
||||
const loadSavedState = () => {
|
||||
@@ -86,7 +86,7 @@ const saveState = () => {
|
||||
localUserSettings.setJsonObject(settingKeyStates, Object.fromEntries(sortedStates));
|
||||
};
|
||||
|
||||
const graphModel = computed(() => createWorkflowGraphModel(props.jobs, expandedMatrixKeys.value));
|
||||
const graphModel = computed(() => createWorkflowGraphModel(props.jobs, expandedMatrixNodeIds.value));
|
||||
const jobsWithLayout = computed(() => graphModel.value.nodes);
|
||||
const edges = computed(() => graphModel.value.edges);
|
||||
const routedEdges = computed<RoutedEdge[]>(() => graphModel.value.routedEdges);
|
||||
@@ -309,15 +309,15 @@ function onNodeClick(job: GraphNode | ActionsJob, event: MouseEvent) {
|
||||
@mouseenter="handleNodeMouseEnter(job.id)"
|
||||
@mouseleave="handleNodeMouseLeave"
|
||||
>
|
||||
<title>Matrix: {{ job.matrixKey }}</title>
|
||||
<title>Matrix: {{ job.name }}</title>
|
||||
<rect :x="job.x" :y="job.y" :width="nodeWidth" :height="job.displayHeight" rx="6" class="job-rect"/>
|
||||
<foreignObject :x="job.x" :y="job.y" :width="nodeWidth" :height="job.displayHeight" class="matrix-foreign-object">
|
||||
<div class="matrix-panel" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div class="matrix-panel-label" @click.stop="toggleMatrixExpanded(job.matrixKey!)">Matrix: {{ job.matrixKey }}</div>
|
||||
<div class="matrix-panel-label" @click.stop="toggleMatrixExpanded(job.id)">Matrix: {{ job.name }}</div>
|
||||
<div
|
||||
v-if="!isMatrixExpanded(job.matrixKey!)"
|
||||
v-if="!isMatrixExpanded(job.id)"
|
||||
class="matrix-panel-collapsed"
|
||||
@click.stop="toggleMatrixExpanded(job.matrixKey!)"
|
||||
@click.stop="toggleMatrixExpanded(job.id)"
|
||||
>
|
||||
<div class="matrix-panel-summary-row">
|
||||
<ActionStatusIcon :status="job.status" icon-variant="circle-fill"/>
|
||||
|
||||
Reference in New Issue
Block a user