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:
parent
d757d3c71d
commit
d88a53785f
@ -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;
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user