Add log line anchor for action logs (#25532)
Close #24593 Some behavior: - If log step line in hash exists, expand the step and scroll to the log line. - If step exists but line not exists, the step will be expanded. - If step not exists, stays on the job's page. Some Notes: - Changed mounted to async because need to await for first `loadJob` so `currentJobStepsStates` can be initialized and used in `hashChangeListener `. --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
36f1fa7792
commit
640a88fa09
1 changed files with 38 additions and 7 deletions
|
@ -204,15 +204,19 @@ const sfc = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
async mounted() {
|
||||||
// load job data and then auto-reload periodically
|
// load job data and then auto-reload periodically
|
||||||
this.loadJob();
|
// need to await first loadJob so this.currentJobStepsStates is initialized and can be used in hashChangeListener
|
||||||
|
await this.loadJob();
|
||||||
this.intervalID = setInterval(this.loadJob, 1000);
|
this.intervalID = setInterval(this.loadJob, 1000);
|
||||||
document.body.addEventListener('click', this.closeDropdown);
|
document.body.addEventListener('click', this.closeDropdown);
|
||||||
|
this.hashChangeListener();
|
||||||
|
window.addEventListener('hashchange', this.hashChangeListener);
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
document.body.removeEventListener('click', this.closeDropdown);
|
document.body.removeEventListener('click', this.closeDropdown);
|
||||||
|
window.removeEventListener('hashchange', this.hashChangeListener);
|
||||||
},
|
},
|
||||||
|
|
||||||
unmounted() {
|
unmounted() {
|
||||||
|
@ -280,14 +284,16 @@ const sfc = {
|
||||||
this.fetchPost(`${this.run.link}/approve`);
|
this.fetchPost(`${this.run.link}/approve`);
|
||||||
},
|
},
|
||||||
|
|
||||||
createLogLine(line, startTime) {
|
createLogLine(line, startTime, stepIndex) {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.classList.add('job-log-line');
|
div.classList.add('job-log-line');
|
||||||
|
div.setAttribute('id', `jobstep-${stepIndex}-${line.index}`);
|
||||||
div._jobLogTime = line.timestamp;
|
div._jobLogTime = line.timestamp;
|
||||||
|
|
||||||
const lineNumber = document.createElement('div');
|
const lineNumber = document.createElement('a');
|
||||||
lineNumber.className = 'line-num';
|
lineNumber.classList.add('line-num', 'muted');
|
||||||
lineNumber.textContent = line.index;
|
lineNumber.textContent = line.index;
|
||||||
|
lineNumber.setAttribute('href', `#jobstep-${stepIndex}-${line.index}`);
|
||||||
div.append(lineNumber);
|
div.append(lineNumber);
|
||||||
|
|
||||||
// for "Show timestamps"
|
// for "Show timestamps"
|
||||||
|
@ -318,7 +324,7 @@ const sfc = {
|
||||||
for (const line of logLines) {
|
for (const line of logLines) {
|
||||||
// TODO: group support: ##[group]GroupTitle , ##[endgroup]
|
// TODO: group support: ##[group]GroupTitle , ##[endgroup]
|
||||||
const el = this.getLogsContainer(stepIndex);
|
const el = this.getLogsContainer(stepIndex);
|
||||||
el.append(this.createLogLine(line, startTime));
|
el.append(this.createLogLine(line, startTime, stepIndex));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -429,6 +435,21 @@ const sfc = {
|
||||||
} else {
|
} else {
|
||||||
actionBodyEl.append(fullScreenEl);
|
actionBodyEl.append(fullScreenEl);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async hashChangeListener() {
|
||||||
|
const selectedLogStep = window.location.hash;
|
||||||
|
if (!selectedLogStep) return;
|
||||||
|
const [_, step, _line] = selectedLogStep.split('-');
|
||||||
|
if (!this.currentJobStepsStates[step]) return;
|
||||||
|
if (!this.currentJobStepsStates[step].expanded && this.currentJobStepsStates[step].cursor === null) {
|
||||||
|
this.currentJobStepsStates[step].expanded = true;
|
||||||
|
// need to await for load job if the step log is loaded for the first time
|
||||||
|
// so logline can be selected by querySelector
|
||||||
|
await this.loadJob();
|
||||||
|
}
|
||||||
|
const logLine = this.$refs.steps.querySelector(selectedLogStep);
|
||||||
|
if (!logLine) return;
|
||||||
|
logLine.querySelector('.line-num').click();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -802,10 +823,15 @@ export function initRepositoryActionView() {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-step-section .job-step-logs .job-log-line:hover {
|
.job-log-line:hover,
|
||||||
|
.job-log-line:target {
|
||||||
background-color: var(--color-console-hover-bg);
|
background-color: var(--color-console-hover-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.job-log-line:target {
|
||||||
|
scroll-margin-top: 95px;
|
||||||
|
}
|
||||||
|
|
||||||
/* class names 'log-time-seconds' and 'log-time-stamp' are used in the method toggleTimeDisplay */
|
/* class names 'log-time-seconds' and 'log-time-stamp' are used in the method toggleTimeDisplay */
|
||||||
.job-log-line .line-num, .log-time-seconds {
|
.job-log-line .line-num, .log-time-seconds {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
|
@ -814,6 +840,11 @@ export function initRepositoryActionView() {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.job-log-line:target > .line-num {
|
||||||
|
color: var(--color-primary);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.log-time-seconds {
|
.log-time-seconds {
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue