go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/common/components/result_entry/text_diff_artifact.ts (about)

     1  // Copyright 2020 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  import '@material/mwc-icon';
    16  import { MobxLitElement } from '@adobe/lit-mobx';
    17  import * as Diff2Html from 'diff2html';
    18  import { css, html } from 'lit';
    19  import { customElement } from 'lit/decorators.js';
    20  import { unsafeHTML } from 'lit/directives/unsafe-html.js';
    21  import { computed, makeObservable, observable } from 'mobx';
    22  import { fromPromise, IPromiseBasedObservable } from 'mobx-utils';
    23  
    24  import '@/generic_libs/components/expandable_entry';
    25  import { ARTIFACT_LENGTH_LIMIT } from '@/common/constants/test';
    26  import { Artifact } from '@/common/services/resultdb';
    27  import { commonStyles } from '@/common/styles/stylesheets';
    28  import {
    29    getRawArtifactURLPath,
    30    getTextDiffArtifactURLPath,
    31  } from '@/common/tools/url_utils';
    32  import { reportRenderError } from '@/generic_libs/tools/error_handler';
    33  import { unwrapObservable } from '@/generic_libs/tools/mobx_utils';
    34  import { urlSetSearchQueryParam } from '@/generic_libs/tools/utils';
    35  
    36  /**
    37   * Renders a text diff artifact.
    38   */
    39  @customElement('milo-text-diff-artifact')
    40  export class TextDiffArtifactElement extends MobxLitElement {
    41    @observable.ref artifact!: Artifact;
    42  
    43    @computed
    44    private get content$(): IPromiseBasedObservable<string> {
    45      return fromPromise(
    46        // TODO(crbug/1206109): use permanent raw artifact URL.
    47        fetch(
    48          urlSetSearchQueryParam(
    49            this.artifact.fetchUrl,
    50            'n',
    51            ARTIFACT_LENGTH_LIMIT,
    52          ),
    53        ).then((res) => res.text()),
    54      );
    55    }
    56  
    57    @computed
    58    private get content() {
    59      return unwrapObservable(this.content$, null);
    60    }
    61  
    62    constructor() {
    63      super();
    64      makeObservable(this);
    65    }
    66  
    67    protected render = reportRenderError(this, () => {
    68      return html`
    69        <link
    70          rel="stylesheet"
    71          type="text/css"
    72          href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css"
    73        />
    74        <milo-expandable-entry .expanded=${true} .contentRuler="invisible">
    75          <span id="header" slot="header">
    76            Unexpected text output from
    77            <a
    78              href=${getTextDiffArtifactURLPath(this.artifact.name)}
    79              target="_blank"
    80            >
    81              ${this.artifact.artifactId}
    82            </a>
    83            (<a href=${getRawArtifactURLPath(this.artifact.name)} target="_blank"
    84              >view raw</a
    85            >)
    86          </span>
    87          <div id="content" slot="content">
    88            ${unsafeHTML(
    89              Diff2Html.html(this.content || '', { drawFileList: false }),
    90            )}
    91          </div>
    92        </milo-expandable-entry>
    93      `;
    94    });
    95  
    96    static styles = [
    97      commonStyles,
    98      css`
    99        #content {
   100          padding-top: 5px;
   101          position: relative;
   102        }
   103        .d2h-code-linenumber {
   104          cursor: default;
   105        }
   106        .d2h-moved-tag {
   107          display: none;
   108        }
   109      `,
   110    ];
   111  }