mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 21:16:26 +01:00 
			
		
		
		
	Add action auto-scroll (#30057)
Adds an auto-scroll/follow feature to running actions (fix #25186, fix #28535). When new log lines are appended and the bottom of the logs container (`.action-view-right`) is visible at this time, the page automatically scrolls down to the bottom of the logs. --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		
							parent
							
								
									143946834a
								
							
						
					
					
						commit
						5d6d62493b
					
				@ -7,8 +7,8 @@ import {SvgIcon} from '../svg.ts';
 | 
			
		||||
 | 
			
		||||
withDefaults(defineProps<{
 | 
			
		||||
  status: 'success' | 'skipped' | 'waiting' | 'blocked' | 'running' | 'failure' | 'cancelled' | 'unknown',
 | 
			
		||||
  size: number,
 | 
			
		||||
  className: string,
 | 
			
		||||
  size?: number,
 | 
			
		||||
  className?: string,
 | 
			
		||||
  localeStatus?: string,
 | 
			
		||||
}>(), {
 | 
			
		||||
  size: 16,
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,11 @@ function parseLineCommand(line: LogLine): LogLineCommand | null {
 | 
			
		||||
  return null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isLogElementInViewport(el: HTMLElement): boolean {
 | 
			
		||||
  const rect = el.getBoundingClientRect();
 | 
			
		||||
  return rect.top >= 0 && rect.bottom <= window.innerHeight; // only check height but not width
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const sfc = {
 | 
			
		||||
  name: 'RepoActionView',
 | 
			
		||||
  components: {
 | 
			
		||||
@ -142,9 +147,14 @@ const sfc = {
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    // get the active container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group`
 | 
			
		||||
    getLogsContainer(stepIndex: number) {
 | 
			
		||||
      const el = this.$refs.logs[stepIndex];
 | 
			
		||||
    // get the job step logs container ('.job-step-logs')
 | 
			
		||||
    getJobStepLogsContainer(stepIndex: number): HTMLElement {
 | 
			
		||||
      return this.$refs.logs[stepIndex];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // get the active logs container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group`
 | 
			
		||||
    getActiveLogsContainer(stepIndex: number): HTMLElement {
 | 
			
		||||
      const el = this.getJobStepLogsContainer(stepIndex);
 | 
			
		||||
      return el._stepLogsActiveContainer ?? el;
 | 
			
		||||
    },
 | 
			
		||||
    // begin a log group
 | 
			
		||||
@ -217,9 +227,15 @@ const sfc = {
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    shouldAutoScroll(stepIndex: number): boolean {
 | 
			
		||||
      const el = this.getJobStepLogsContainer(stepIndex);
 | 
			
		||||
      if (!el.lastChild) return false;
 | 
			
		||||
      return isLogElementInViewport(el.lastChild);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    appendLogs(stepIndex: number, startTime: number, logLines: LogLine[]) {
 | 
			
		||||
      for (const line of logLines) {
 | 
			
		||||
        const el = this.getLogsContainer(stepIndex);
 | 
			
		||||
        const el = this.getActiveLogsContainer(stepIndex);
 | 
			
		||||
        const cmd = parseLineCommand(line);
 | 
			
		||||
        if (cmd?.name === 'group') {
 | 
			
		||||
          this.beginLogGroup(stepIndex, startTime, line, cmd);
 | 
			
		||||
@ -278,6 +294,14 @@ const sfc = {
 | 
			
		||||
            this.currentJobStepsStates[i] = {cursor: null, expanded: false};
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // find the step indexes that need to auto-scroll
 | 
			
		||||
        const autoScrollStepIndexes = new Map<number, boolean>();
 | 
			
		||||
        for (const logs of job.logs.stepsLog ?? []) {
 | 
			
		||||
          if (autoScrollStepIndexes.has(logs.step)) continue;
 | 
			
		||||
          autoScrollStepIndexes.set(logs.step, this.shouldAutoScroll(logs.step));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // append logs to the UI
 | 
			
		||||
        for (const logs of job.logs.stepsLog ?? []) {
 | 
			
		||||
          // save the cursor, it will be passed to backend next time
 | 
			
		||||
@ -285,6 +309,15 @@ const sfc = {
 | 
			
		||||
          this.appendLogs(logs.step, logs.started, logs.lines);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // auto-scroll to the last log line of the last step
 | 
			
		||||
        let autoScrollJobStepElement: HTMLElement;
 | 
			
		||||
        for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) {
 | 
			
		||||
          if (!autoScrollStepIndexes.get(stepIndex)) continue;
 | 
			
		||||
          autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex);
 | 
			
		||||
        }
 | 
			
		||||
        autoScrollJobStepElement?.lastElementChild.scrollIntoView({behavior: 'smooth', block: 'nearest'});
 | 
			
		||||
 | 
			
		||||
        // clear the interval timer if the job is done
 | 
			
		||||
        if (this.run.done && this.intervalID) {
 | 
			
		||||
          clearInterval(this.intervalID);
 | 
			
		||||
          this.intervalID = null;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user