0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-02-23 12:55:43 +01:00

fix: Improve RepoActionView console styling and WorkflowGraph UX

RepoActionView:
- Restore original console styles in RepoActionView.vue
- Fix light theme console colors (variables were hardcoded to dark values)
- Improve overall UI appearance and readability

WorkflowGraph:
- Remove artificial delay during graph panning
- Fix graph movement behavior
- Add persistence for zoom/position state when switching between jobs
- Rename prop `current-job-id` to `current-job-idx` for accuracy
- Remove border from graph container
This commit is contained in:
Semenets V. Pavel 2026-02-20 11:52:51 +03:00
parent d757d3c71d
commit d88a53785f
3 changed files with 101 additions and 58 deletions

View File

@ -66,14 +66,14 @@ gitea-theme-meta-info {
--color-secondary-hover: var(--color-secondary-dark-5);
--color-secondary-active: var(--color-secondary-dark-6);
/* console colors - used for actions console and console files */
--color-console-fg: #f7f8f9;
--color-console-fg-subtle: #bdc4cc;
--color-console-bg: #171b1e;
--color-console-border: #2e353b;
--color-console-hover-bg: #272d33;
--color-console-active-bg: #2e353b;
--color-console-menu-bg: #262b31;
--color-console-menu-border: #414b55;
--color-console-fg: #0d1117;
--color-console-fg-subtle: #40474d;
--color-console-bg: #ffffff;
--color-console-border: #d0d7de;
--color-console-hover-bg: #f1f3f5;
--color-console-active-bg: #d0d7de;
--color-console-menu-bg: #f8f9fb;
--color-console-menu-border: #d0d7de;
/* named colors */
--color-red: #db2828;
--color-orange: #f2711c;

View File

@ -603,7 +603,7 @@ export default defineComponent({
<WorkflowGraph
v-if="showSummary && run.jobs.length > 1"
:jobs="run.jobs"
:current-job-id="parseInt(jobIndex)"
:current-job-idx="parseInt(jobIndex)"
class="workflow-graph-container"
/>
@ -867,14 +867,14 @@ export default defineComponent({
.action-view-right {
flex: 1;
color: var(--color-text);
color: var(--color-console-fg-subtle);
max-height: 100%;
width: 70%;
display: flex;
flex-direction: column;
border: 1px solid var(--color-secondary);
border: 1px solid var(--color-console-border);
border-radius: var(--border-radius);
background: var(--color-body);
background: var(--color-console-bg);
align-self: flex-start;
}
@ -883,17 +883,17 @@ export default defineComponent({
.action-view-right .ui.button,
.action-view-right .ui.button:focus {
background: transparent;
color: var(--color-text);
color: var(--color-console-fg-subtle);
}
.action-view-right .ui.button:hover {
background: var(--color-hover);
color: var(--color-text);
background: var(--color-console-hover-bg);
color: var(--color-console-fg);
}
.action-view-right .ui.button:active {
background: var(--color-active);
color: var(--color-text);
background: var(--color-console-active-bg);
color: var(--color-console-fg);
}
/* end fomantic button overrides */
@ -901,31 +901,31 @@ export default defineComponent({
/* begin fomantic dropdown menu overrides */
.action-view-right .ui.dropdown .menu {
background: var(--color-menu);
border-color: var(--color-secondary);
background: var(--color-console-menu-bg);
border-color: var(--color-console-menu-border);
}
.action-view-right .ui.dropdown .menu > .item {
color: var(--color-text);
color: var(--color-console-fg);
}
.action-view-right .ui.dropdown .menu > .item:hover {
color: var(--color-text);
background: var(--color-hover);
color: var(--color-console-fg);
background: var(--color-console-hover-bg);
}
.action-view-right .ui.dropdown .menu > .item:active {
color: var(--color-text);
background: var(--color-active);
color: var(--color-console-fg);
background: var(--color-console-active-bg);
}
.action-view-right .ui.dropdown .menu > .divider {
border-top-color: var(--color-secondary-alpha-30);
border-top-color: var(--color-console-menu-border);
}
.action-view-right .ui.pointing.dropdown > .menu:not(.hidden)::after {
background: var(--color-menu);
box-shadow: -1px -1px 0 0 var(--color-secondary);
background: var(--color-console-menu-bg);
box-shadow: -1px -1px 0 0 var(--color-console-menu-border);
}
/* end fomantic dropdown menu overrides */
@ -939,7 +939,7 @@ export default defineComponent({
top: 0;
height: 60px;
z-index: 1; /* above .job-step-container */
background: var(--color-body);
background: var(--color-console-bg);
border-radius: 3px;
}
@ -948,13 +948,13 @@ export default defineComponent({
}
.job-info-header .job-info-header-title {
color: var(--color-text);
color: var(--color-console-fg);
font-size: 16px;
margin: 0;
}
.job-info-header .job-info-header-detail {
color: var(--color-text);
color: var(--color-console-fg-subtle);
font-size: 12px;
}
@ -965,7 +965,7 @@ export default defineComponent({
.job-step-container {
max-height: 100%;
border-radius: 0 0 var(--border-radius) var(--border-radius);
border-top: 1px solid var(--color-secondary);
border-top: 1px solid var(--color-console-border);
z-index: 0;
}
@ -981,8 +981,8 @@ export default defineComponent({
}
.job-step-container .job-step-summary.step-expandable:hover {
color: var(--color-text);
background: var(--color-hover);
color: var(--color-console-fg);
background: var(--color-console-hover-bg);
}
.job-step-container .job-step-summary .step-summary-msg {
@ -994,8 +994,8 @@ export default defineComponent({
}
.job-step-container .job-step-summary.selected {
color: var(--color-text);
background-color: var(--color-active);
color: var(--color-console-fg);
background-color: var(--color-console-active-bg);
position: sticky;
top: 60px;
}
@ -1031,7 +1031,7 @@ export default defineComponent({
.job-log-line:hover,
.job-log-line:target {
background-color: var(--color-hover);
background-color: var(--color-console-hover-bg);
}
.job-log-line:target {

View File

@ -35,9 +35,6 @@
ref="container"
@wheel="handleWheel"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"
@mouseleave="handleMouseLeave"
:class="{ 'dragging': isDragging }"
>
<svg
@ -66,7 +63,7 @@
:key="job.id"
class="job-node-group"
:class="{
'current-job': job.index === currentJobId
'current-job': job.index === currentJobIdx
}"
@click="onNodeClick(job, $event)"
@mouseenter="handleNodeMouseEnter(job)"
@ -79,8 +76,8 @@
:height="nodeHeight"
rx="8"
:fill="getNodeColor(job.status)"
:stroke="job.index === currentJobId ? 'var(--color-primary)' : 'var(--color-card-border)'"
:stroke-width="job.index === currentJobId ? '3' : '2'"
:stroke="job.index === currentJobIdx ? 'var(--color-primary)' : 'var(--color-card-border)'"
:stroke-width="job.index === currentJobIdx ? '3' : '2'"
class="job-rect"
/>
@ -278,7 +275,7 @@
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, ref, watch, onMounted } from 'vue'
interface Job {
id: number
@ -310,7 +307,7 @@ interface BezierEdge extends Edge {
const props = defineProps<{
jobs: Job[]
currentJobId?: number
currentJobIdx?: number
}>()
const scale = ref(1)
@ -323,6 +320,53 @@ const animationFrameId = ref<number | null>(null)
const container = ref<HTMLElement | null>(null)
const hoveredJobId = ref<number | null>(null)
// Генерация ключа для localStorage на основе runId (для всего workflow)
const getStorageKey = () => {
// Получаем runId из URL
const runMatch = window.location.pathname.match(/\/runs\/(\d+)/)
const runId = runMatch ? runMatch[1] : 'unknown'
return `workflow-graph-view-${runId}`
}
// Загрузка сохраненного состояния из localStorage
const loadSavedState = () => {
try {
const saved = localStorage.getItem(getStorageKey())
if (saved) {
const state = JSON.parse(saved)
if (state.scale !== undefined) scale.value = state.scale
if (state.translateX !== undefined) translateX.value = state.translateX
if (state.translateY !== undefined) translateY.value = state.translateY
}
} catch (e) {
console.error('Failed to load workflow graph state from localStorage:', e)
}
}
// Сохранение текущего состояния в localStorage
const saveState = () => {
try {
const state = {
scale: scale.value,
translateX: translateX.value,
translateY: translateY.value
}
localStorage.setItem(getStorageKey(), JSON.stringify(state))
} catch (e) {
console.error('Failed to save workflow graph state to localStorage:', e)
}
}
// Загрузка сохраненного состояния при монтировании
onMounted(() => {
loadSavedState()
})
// Сохранение состояния при изменении translateX, translateY или scale
watch([translateX, translateY, scale], () => {
saveState()
})
const nodeWidth = computed(() => {
const maxNameLength = Math.max(...props.jobs.map(j => j.name.length))
return Math.min(Math.max(140, maxNameLength * 8), 180)
@ -534,9 +578,11 @@ function handleMouseDown(event: MouseEvent) {
}
document.body.style.userSelect = 'none'
document.addEventListener('mouseup', handleMouseUpOnDocument)
document.addEventListener('mousemove', handleMouseMoveOnDocument)
}
function handleMouseMove(event: MouseEvent) {
function handleMouseMoveOnDocument(event: MouseEvent) {
if (!isDragging.value) return
if (animationFrameId.value !== null) {
@ -554,7 +600,9 @@ function handleMouseMove(event: MouseEvent) {
})
}
function handleMouseUp() {
function handleMouseUpOnDocument() {
if (!isDragging.value) return
if (animationFrameId.value !== null) {
cancelAnimationFrame(animationFrameId.value)
animationFrameId.value = null
@ -567,10 +615,8 @@ function handleMouseUp() {
}
document.body.style.userSelect = ''
}
function handleMouseLeave() {
handleMouseUp()
document.removeEventListener('mouseup', handleMouseUpOnDocument)
document.removeEventListener('mousemove', handleMouseMoveOnDocument)
}
function handleNodeMouseEnter(job: JobNode) {
@ -854,7 +900,7 @@ function computeJobLevels(jobs: Job[]): Map<string, number> {
}
function onNodeClick(job: JobNode, event?: MouseEvent) {
if (job.index === props.currentJobId) {
if (job.index === props.currentJobIdx) {
return
}
@ -893,12 +939,11 @@ function onNodeClick(job: JobNode, event?: MouseEvent) {
<style scoped>
.workflow-graph {
margin: 20px 0;
padding: 20px;
padding: 5px 12px;
background: var(--color-box-body);
border-radius: 12px;
/* border-radius: 12px;
border: 1px solid var(--color-secondary-alpha-20);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); */
position: relative;
}
@ -987,8 +1032,7 @@ function onNodeClick(job: JobNode, event?: MouseEvent) {
.graph-container {
overflow: auto;
padding: 10px;
margin: -10px;
padding: 12px;
border-radius: 8px;
background: var(--color-body);
cursor: grab;
@ -1005,7 +1049,6 @@ function onNodeClick(job: JobNode, event?: MouseEvent) {
.graph-svg {
display: block;
transition: transform 0.1s ease;
will-change: transform;
}