golang.org/x/build@v0.0.0-20240506185731-218518f32b70/devapp/templates/reviews.tmpl (about)

     1  <!DOCTYPE html>
     2  <html lang="en">
     3  <meta charset="utf-8">
     4  <meta name="viewport" content="width=device-width, initial-scale=1">
     5  <title>Open Go Code Reviews</title>
     6  <style>
     7  * {
     8    box-sizing: border-box;
     9    margin: 0;
    10    padding: 0;
    11  }
    12  body {
    13    font: 13px system-ui, sans-serif;
    14    padding: 1rem;
    15  }
    16  h2 {
    17    margin: 1em 0 .35em;
    18  }
    19  h3:first-of-type {
    20    padding: 0
    21  }
    22  a:link,
    23  a:visited {
    24    color: #00c;
    25  }
    26  header {
    27    border-bottom: 1px solid #666;
    28    margin-bottom: 10px;
    29    padding-bottom: 10px;
    30  }
    31  .header-subtitle {
    32    color: #666;
    33    font-size: .9em;
    34  }
    35  .filters {
    36    display: block;
    37    margin: 1em 0;
    38  }
    39  .filter-input {
    40    font: inherit;
    41    width: 30em;
    42  }
    43  .how-to {
    44    cursor: pointer;
    45    margin-top: 1em;
    46    max-width: 40em;
    47  }
    48  .how-to-container {
    49    padding: 0 1em;
    50  }
    51  .how-to ul {
    52    list-style: none;
    53    margin-top: .5em;
    54  }
    55  .how-to li {
    56    margin: .25em 1em .75em;
    57  }
    58  .examples li {
    59    margin: .25em 1em;
    60  }
    61  .row {
    62    border-bottom: 1px solid #f1f2f3;
    63    display: flex;
    64    padding: .5em 0;
    65    white-space: nowrap;
    66  }
    67  .date {
    68    min-width: 6rem;
    69  }
    70  .owner {
    71    min-width: 10rem;
    72    max-width: 10rem;
    73    overflow: hidden;
    74    text-overflow: ellipsis;
    75    padding-right: 1em;
    76  }
    77  .icons,
    78  .number {
    79    flex-shrink: 0;
    80  }
    81  .icons {
    82    height: 20px;
    83    margin-right: 1.5em;
    84    text-align: right;
    85    width: 12em;
    86  }
    87  .number {
    88    margin-right: 1.5em;
    89    text-align: right;
    90    width: 6ch;
    91  }
    92  .subject {
    93    overflow: hidden;
    94    text-overflow: ellipsis;
    95  }
    96  .pill,
    97  .pill:link,
    98  .pill:visited {
    99    color: #000;
   100    display: inline-block;
   101    border-radius: 2px;
   102    padding: 2px 5px;
   103    text-decoration: none;
   104  }
   105  .plus-two:link,
   106  .plus-two:visited,
   107  .minus-two:link,
   108  .minus-two:visited {
   109    color: #fff;
   110  }
   111  .plus-two {
   112    background-color: #2e7d32;
   113  }
   114  .plus-one {
   115    background-color: #dcedc8;
   116  }
   117  .minus-one {
   118    background-color: #fdaeb7;
   119  }
   120  .minus-two {
   121    background-color: #b71c1c;
   122  }
   123  .no-human-comments {
   124    background-color: #e0e0e0;
   125  }
   126  .release-milestone {
   127    background-color: #a0e8ff;
   128  }
   129  [hidden] {
   130    display: none;
   131  }
   132  </style>
   133  <header>
   134    <strong>{{.TotalChanges}} open changes</strong>
   135    <div class="header-subtitle">
   136      Excluding those marked WIP, having hashtags "wait-author", "wait-release", "wait-issue", or description containing "DO NOT REVIEW".
   137    </div>
   138    <div class="header-subtitle">
   139      <a href="https://go.googlesource.com/build/+/master/devapp/reviews.go">Source code</a>
   140    </div>
   141  </header>
   142  <div class="filters">
   143    <label class="filter-label">Filter: <input class="filter-input js-filter-input" type="text"></label>
   144    <details class="how-to">
   145      <summary>Filters How-to</summary>
   146      <div class="how-to-container">
   147        <ul>
   148          <li>You can filter on any displayed field below, along with a few other fields not shown, such as reviewer.
   149          <li>Exclude terms by prefixing them with a <code>-</code>.
   150          <li>The <code>t:</code> operator is short for "tag" and coincides with the colored tags you see in the rows below.
   151          <li>Supported tag values include "Changes without a human comment" (<code>t:attn</code>) and <code>Code-Review</code>
   152              label values (<code>t:-2</code>, <code>t:+1</code>, and <code>t:+2</code>).
   153          <li>All terms use substring matching, meaning that you can type <code>reviewer:iant</code> instead of <code>reviewer:iant@golang.org</code>
   154          <li>The following operators are supported: <code>t:, repo:, reviewer:, cc:, involves:, and owner:</code>
   155        </ul>
   156          Examples:
   157          <ul>
   158            <li><a href="?q=reviewer%3Abradfitz+repo%3Anet">http2 changes in the net repo where brad is a reviewer</a>
   159            <li><a href="?q=-involves%3Aaustin+runtime%3A">runtime changes that don't involve austin</a>
   160          </ul>
   161      </div>
   162    </details>
   163  </div>
   164  {{range $p := .Projects}}
   165    {{if .Changes}}
   166      <section hidden>
   167        <h2>{{.Project}}</h2>
   168        {{range .Changes}}
   169          <div class="row" data-terms="{{.SearchTerms}}">
   170            <span class="date">{{.FormattedLastUpdate}}</span>
   171            <span class="owner">{{.Owner.Name}}</span>
   172            <span class="icons">
   173              {{if .NoHumanComments}}<a class="pill no-human-comments" href="?q=t%3Aattn" title="Has no human comments">→</a>{{end}}
   174              {{if .HasMinusTwo}}️<a class="pill minus-two" href="?q=t%3A-2" title="Code-Review: -2">-2</a>{{end}}
   175              {{if .HasMinusOne}}<a class="pill minus-one" href="?q=t%3A-1" title="Code-Review: -1">-1</a>{{end}}
   176              {{if .HasPlusOne}}<a class="pill plus-one" href="?q=t%3A%2B1" title="Code-Review: +1">+1</a>{{end}}
   177              {{if .HasPlusTwo}}<a class="pill plus-two" href="?q=t%3A%2B2" title="Code-Review: +2">+2</a>{{end}}
   178              {{if .TryBotMinusOne}}<a class="pill minus-one" href="?q=trybot%3A-1" title="Run-TryBot: -1">🤖-1</a>{{end}}
   179              {{if .TryBotPlusOne}}<a class="pill plus-one" href="?q=trybot%3A%2B1" title="Run-TryBot: +1">🤖+1</a>{{end}}
   180              {{if .ReleaseMilestone}}<a class="pill release-milestone" href="?q=release%3A{{.ReleaseMilestone}}" title="References an issue in Go{{.ReleaseMilestone}}">{{.ReleaseMilestone}}</a>{{end}}
   181            </span>
   182            <a class="number" href="https://{{$p.ReviewServer}}/{{.Number}}" target="_blank">{{.Number}}</a>
   183            <span class="subject">
   184              {{.Subject}}
   185            </span>
   186          </div>
   187        {{end}}
   188      </section>
   189  	{{end}}
   190  {{end}}
   191  <script>
   192  function filter(query) {
   193    console.time('filter');
   194    query = query.toLowerCase();
   195    document.querySelectorAll('.row').forEach(el => {
   196      const terms = el.dataset.terms;
   197      const queryTerms = query.split(' ');
   198      let match = true;
   199      for (let i = 0; i < queryTerms.length; i++) {
   200        let q = queryTerms[i].trim();
   201        if (q.length === 0 || q === '-') { continue; }
   202        if (q.startsWith('-')) {
   203          match = match && !terms.includes(q.substr(1));
   204        } else {
   205          match = match && terms.includes(q);
   206        }
   207      }
   208      el.hidden = !match;
   209    });
   210    document.querySelectorAll('section').forEach(el => {
   211      el.hidden = el.querySelectorAll('.row:not([hidden])').length === 0;
   212    });
   213    console.timeEnd('filter');
   214  }
   215  
   216  let debounceTimerId = null;
   217  const filterInputEl = document.querySelector('.js-filter-input')
   218  filterInputEl.addEventListener('keyup', e => {
   219    const q = e.target.value.trim();
   220    let url = new URL(window.location.href);
   221    if (!!q) {
   222      url.searchParams.set('q', q);
   223    } else {
   224      url.searchParams.delete('q');
   225    }
   226    window.history.replaceState({}, null, url.toString());
   227  
   228    if (debounceTimerId) {
   229      window.clearTimeout(debounceTimerId);
   230      debounceTimerId = null;
   231    }
   232    debounceTimerId = window.setTimeout(() => { filter(q); }, 200);
   233  });
   234  
   235  const initialQuery = (new URL(window.location.href)).searchParams.get('q') || '';
   236  filterInputEl.value = initialQuery;
   237  filter(initialQuery);
   238  </script>