go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/build/legacy/build_page/steps_tab/steps_tab.tsx (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-button';
    16  import { css, html } from 'lit';
    17  import { customElement } from 'lit/decorators.js';
    18  import { makeObservable, observable } from 'mobx';
    19  
    20  import '@/generic_libs/components/hotkey';
    21  import './step_display_config';
    22  import './step_list';
    23  import { RecoverableErrorBoundary } from '@/common/components/error_handling';
    24  import { consumeStore, StoreInstance } from '@/common/store';
    25  import { commonStyles } from '@/common/styles/stylesheets';
    26  import { MobxExtLitElement } from '@/generic_libs/components/lit_mobx_ext';
    27  import { useTabId } from '@/generic_libs/components/routed_tabs';
    28  import {
    29    errorHandler,
    30    forwardWithoutMsg,
    31    reportRenderError,
    32  } from '@/generic_libs/tools/error_handler';
    33  import { consumer } from '@/generic_libs/tools/lit_context';
    34  
    35  import { BuildPageStepListElement } from './step_list';
    36  
    37  @customElement('milo-steps-tab')
    38  @errorHandler(forwardWithoutMsg)
    39  @consumer
    40  export class StepsTabElement extends MobxExtLitElement {
    41    @observable.ref
    42    @consumeStore()
    43    store!: StoreInstance;
    44  
    45    private allStepsWereExpanded = false;
    46    private toggleAllSteps(expand: boolean) {
    47      this.allStepsWereExpanded = expand;
    48      this.shadowRoot!.querySelector<BuildPageStepListElement>(
    49        'milo-bp-step-list',
    50      )!.toggleAllSteps(expand);
    51    }
    52    private readonly toggleAllStepsByHotkey = () =>
    53      this.toggleAllSteps(!this.allStepsWereExpanded);
    54  
    55    constructor() {
    56      super();
    57      makeObservable(this);
    58    }
    59  
    60    protected render = reportRenderError(this, () => {
    61      return html`
    62        <div id="header">
    63          <milo-bp-step-display-config></milo-bp-step-display-config>
    64          <milo-hotkey
    65            .key=${'x'}
    66            .handler=${this.toggleAllStepsByHotkey}
    67            title="press x to expand/collapse all entries"
    68          >
    69            <mwc-button
    70              class="action-button"
    71              dense
    72              unelevated
    73              @click=${() => this.toggleAllSteps(true)}
    74            >
    75              Expand All
    76            </mwc-button>
    77            <mwc-button
    78              class="action-button"
    79              dense
    80              unelevated
    81              @click=${() => this.toggleAllSteps(false)}
    82            >
    83              Collapse All
    84            </mwc-button>
    85          </milo-hotkey>
    86        </div>
    87        <milo-bp-step-list id="main" tabindex="0"></milo-bp-step-list>
    88      `;
    89    });
    90  
    91    static styles = [
    92      commonStyles,
    93      css`
    94        #header {
    95          display: grid;
    96          grid-template-columns: 1fr auto;
    97          grid-gap: 5px;
    98          height: 30px;
    99          padding: 5px 10px 3px 10px;
   100          position: sticky;
   101          top: 0px;
   102          background: white;
   103          border-bottom: 1px solid var(--divider-color);
   104        }
   105  
   106        mwc-button {
   107          margin-top: 1px;
   108          width: var(--expand-button-width);
   109        }
   110  
   111        milo-bp-step-list {
   112          padding-top: 5px;
   113          padding-left: 10px;
   114          outline: none;
   115        }
   116      `,
   117    ];
   118  }
   119  
   120  declare global {
   121    // eslint-disable-next-line @typescript-eslint/no-namespace
   122    namespace JSX {
   123      interface IntrinsicElements {
   124        'milo-steps-tab': Record<string, never>;
   125      }
   126    }
   127  }
   128  
   129  export function StepsTab() {
   130    return <milo-steps-tab />;
   131  }
   132  
   133  export function Component() {
   134    useTabId('steps');
   135  
   136    return (
   137      // See the documentation for `<LoginPage />` for why we handle error this
   138      // way.
   139      <RecoverableErrorBoundary key="steps">
   140        <StepsTab />
   141      </RecoverableErrorBoundary>
   142    );
   143  }