github.com/zppinho/prow@v0.0.0-20240510014325-1738badeb017/cmd/deck/static/common/common.ts (about)

     1  import moment from "moment";
     2  import {ProwJobState, Pull} from "../api/prow";
     3  
     4  // This file likes namespaces, so stick with it for now.
     5  /* eslint-disable @typescript-eslint/no-namespace */
     6  
     7  // State enum describes different state a job can be in
     8  export enum State {
     9    TRIGGERED = 'triggered',
    10    PENDING = 'pending',
    11    SUCCESS = 'success',
    12    FAILURE = 'failure',
    13    ABORTED = 'aborted',
    14    ERROR = 'error',
    15  }
    16  
    17  // The cell namespace exposes functions for constructing common table cells.
    18  export namespace cell {
    19  
    20    export function text(content: string): HTMLTableDataCellElement {
    21      const c = document.createElement("td");
    22      c.appendChild(document.createTextNode(content));
    23      return c;
    24    }
    25  
    26    export function time(id: string, when: moment.Moment): HTMLTableDataCellElement {
    27      const tid = `time-cell-${  id}`;
    28      const main = document.createElement("div");
    29      const isADayOld = when.isBefore(moment().startOf('day'));
    30      main.textContent = when.format(isADayOld ? 'MMM DD HH:mm:ss' : 'HH:mm:ss');
    31      main.id = tid;
    32  
    33      const tip = tooltip.forElem(tid, document.createTextNode(when.format('MMM DD YYYY, HH:mm:ss [UTC]ZZ')));
    34      const c = document.createElement("td");
    35      c.appendChild(main);
    36      c.appendChild(tip);
    37  
    38      return c;
    39    }
    40  
    41    export function link(displayText: string, url: string): HTMLTableDataCellElement {
    42      const c = document.createElement("td");
    43      const a = document.createElement("a");
    44      a.href = url;
    45      a.appendChild(document.createTextNode(displayText));
    46      c.appendChild(a);
    47      return c;
    48    }
    49  
    50    export function state(s: ProwJobState): HTMLTableDataCellElement {
    51      const c = document.createElement("td");
    52      if (!s) {
    53        c.appendChild(document.createTextNode(""));
    54        return c;
    55      }
    56  
    57      let displayState = stateToAdj(s);
    58      displayState = displayState[0].toUpperCase() + displayState.slice(1);
    59      let displayIcon = "";
    60      switch (s) {
    61        case State.TRIGGERED:
    62          displayIcon = "schedule";
    63          break;
    64        case State.PENDING:
    65          displayIcon = "watch_later";
    66          break;
    67        case State.SUCCESS:
    68          displayIcon = "check_circle";
    69          break;
    70        case State.FAILURE:
    71          displayIcon = "error";
    72          break;
    73        case State.ABORTED:
    74          displayIcon = "remove_circle";
    75          break;
    76        case State.ERROR:
    77          displayIcon = "warning";
    78          break;
    79      }
    80      const stateIndicator = document.createElement("i");
    81      stateIndicator.classList.add("material-icons", "state", s);
    82      stateIndicator.innerText = displayIcon;
    83      c.appendChild(stateIndicator);
    84      c.title = displayState;
    85  
    86      return c;
    87    }
    88  
    89    function stateToAdj(s: ProwJobState): string {
    90      switch (s) {
    91        case "success":
    92          return "succeeded";
    93        case "failure":
    94          return "failed";
    95        default:
    96          return s;
    97      }
    98    }
    99  
   100    export function commitRevision(repo: string, ref: string, SHA: string, pushCommitLink: string): HTMLTableDataCellElement {
   101      const c = document.createElement("td");
   102      const bl = document.createElement("a");
   103      bl.href = pushCommitLink;
   104      if (!bl.href) {
   105        bl.href = `/github-link?dest=${repo}/commit/${SHA}`;
   106      }
   107      bl.text = `${ref} (${SHA.slice(0, 7)})`;
   108      c.appendChild(bl);
   109      return c;
   110    }
   111  
   112    export function prRevision(repo: string, pull: Pull): HTMLTableDataCellElement {
   113      const td = document.createElement("td");
   114      addPRRevision(td, repo, pull);
   115      return td;
   116    }
   117  
   118    let idCounter = 0;
   119    function nextID(): string {
   120      idCounter++;
   121      return `tipID-${  String(idCounter)}`;
   122    }
   123  
   124    export function addPRRevision(elem: Node, repo: string, pull: Pull): void {
   125      elem.appendChild(document.createTextNode("#"));
   126      const pl = document.createElement("a");
   127      if (pull.link) {
   128        pl.href = pull.link;
   129      } else {
   130        pl.href = `/git-provider-link?target=pr&repo='${repo}'&number=${pull.number}`;
   131      }
   132      pl.text = pull.number.toString();
   133      if (pull.title) {
   134        pl.id = `pr-${repo}-${pull.number}-${nextID()}`;
   135        const tip = tooltip.forElem(pl.id, document.createTextNode(pull.title));
   136        pl.appendChild(tip);
   137      }
   138      elem.appendChild(pl);
   139      if (pull.sha) {
   140        elem.appendChild(document.createTextNode(" ("));
   141        const cl = document.createElement("a");
   142        if (pull.commit_link) {
   143          cl.href = pull.commit_link;
   144        } else {
   145          cl.href = `/git-provider-link?target=prcommit&repo='${repo}'&number=${pull.number}&commit=${pull.sha}`;
   146        }
   147        cl.text = pull.sha.slice(0, 7);
   148        elem.appendChild(cl);
   149        elem.appendChild(document.createTextNode(")"));
   150      }
   151      if (pull.author) {
   152        elem.appendChild(document.createTextNode(" by "));
   153        const al = document.createElement("a");
   154        if (pull.author_link) {
   155          al.href = pull.author_link;
   156        } else {
   157          al.href = `/git-provider-link?target=author&repo='${repo}'&author=${pull.author}`;
   158        }
   159        al.text = pull.author;
   160        elem.appendChild(al);
   161      }
   162    }
   163  }
   164  
   165  export namespace tooltip {
   166    export function forElem(elemID: string, tipElem: Node): HTMLElement {
   167      const tip = document.createElement("div");
   168      tip.appendChild(tipElem);
   169      tip.setAttribute("data-mdl-for", elemID);
   170      tip.classList.add("mdl-tooltip", "mdl-tooltip--large");
   171      tip.style.whiteSpace = "normal";
   172      return tip;
   173    }
   174  }
   175  
   176  export namespace icon {
   177    export function create(iconString: string, tip = "", onClick?: (this: HTMLElement, ev: MouseEvent) => any): HTMLAnchorElement {
   178      const i = document.createElement("i");
   179      i.classList.add("icon-button", "material-icons");
   180      i.innerHTML = iconString;
   181      if (tip !== "") {
   182        i.title = tip;
   183      }
   184      if (onClick) {
   185        i.addEventListener("click", onClick);
   186      }
   187  
   188      const container = document.createElement("a");
   189      container.appendChild(i);
   190      container.classList.add("mdl-button", "mdl-js-button", "mdl-button--icon");
   191  
   192      return container;
   193    }
   194  }
   195  
   196  export namespace tidehistory {
   197    export function poolIcon(org: string, repo: string, branch: string): HTMLAnchorElement {
   198      const link = icon.create("timeline", "Pool History");
   199      const encodedRepo = encodeURIComponent(`${org}/${repo}`);
   200      const encodedBranch = encodeURIComponent(branch);
   201      link.href = `/tide-history?repo=${encodedRepo}&branch=${encodedBranch}`;
   202      return link;
   203    }
   204  
   205    export function authorIcon(author: string): HTMLAnchorElement {
   206      const link = icon.create("timeline", "Personal Tide History");
   207      const encodedAuthor = encodeURIComponent(author);
   208      link.href = `/tide-history?author=${encodedAuthor}`;
   209      return link;
   210    }
   211  }
   212  
   213  export function getCookieByName(name: string): string {
   214    if (!document.cookie) {
   215      return "";
   216    }
   217    const docCookies = decodeURIComponent(document.cookie).split(";");
   218    for (const cookie of docCookies) {
   219      const c = cookie.trim();
   220      const pref = `${name  }=`;
   221      if (c.indexOf(pref) === 0) {
   222        return c.slice(pref.length);
   223      }
   224    }
   225    return "";
   226  }
   227  
   228  export function showToast(text: string): void {
   229    const toast = document.getElementById("toast") as SnackbarElement<HTMLDivElement>;
   230    toast.MaterialSnackbar.showSnackbar({message: text});
   231  }
   232  
   233  export function showAlert(text: string): void {
   234    const toast = document.getElementById("toastAlert") as SnackbarElement<HTMLDivElement>;
   235    toast.MaterialSnackbar.showSnackbar({message: text});
   236  }
   237  
   238  // copyToClipboard is from https://stackoverflow.com/a/33928558
   239  // Copies a string to the clipboard. Must be called from within an
   240  // event handler such as click. May return false if it failed, but
   241  // this is not always possible. Browser support for Chrome 43+,
   242  // Firefox 42+, Safari 10+, Edge and IE 10+.
   243  // IE: The clipboard feature may be disabled by an administrator. By
   244  // default a prompt is shown the first time the clipboard is
   245  // used (per session).
   246  export function copyToClipboard(text: string) {
   247    if (window.clipboardData && window.clipboardData.setData) {
   248      // IE specific code path to prevent textarea being shown while dialog is visible.
   249      return window.clipboardData.setData("Text", text);
   250    } else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
   251      const textarea = document.createElement("textarea");
   252      textarea.textContent = text;
   253      textarea.style.position = "fixed";  // Prevent scrolling to bottom of page in MS Edge.
   254      document.body.appendChild(textarea);
   255      textarea.select();
   256      try {
   257        return document.execCommand("copy");  // Security exception may be thrown by some browsers.
   258      } catch (ex) {
   259        console.warn("Copy to clipboard failed.", ex);
   260        return false;
   261      } finally {
   262        document.body.removeChild(textarea);
   263      }
   264    }
   265  }
   266  export function formatDuration(seconds: number): string {
   267    const parts: string[] = [];
   268    if (seconds >= 3600) {
   269      const hours = Math.floor(seconds / 3600);
   270      parts.push(String(hours));
   271      parts.push('h');
   272      seconds = seconds % 3600;
   273    }
   274    if (seconds >= 60) {
   275      const minutes = Math.floor(seconds / 60);
   276      if (minutes > 0) {
   277        parts.push(String(minutes));
   278        parts.push('m');
   279        seconds = seconds % 60;
   280      }
   281    }
   282    if (seconds >= 0) {
   283      parts.push(String(seconds));
   284      parts.push('s');
   285    }
   286    return parts.join('');
   287  }