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

     1  // Copyright 2021 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-menu';
    16  import { MobxLitElement } from '@adobe/lit-mobx';
    17  import { css, html } from 'lit';
    18  import { customElement } from 'lit/decorators.js';
    19  import { styleMap } from 'lit/directives/style-map.js';
    20  import { computed, makeObservable, observable } from 'mobx';
    21  
    22  import '@/generic_libs/components/drag_tracker';
    23  import { commonStyles } from '@/common/styles/stylesheets';
    24  import { DragEvent } from '@/generic_libs/components/drag_tracker';
    25  
    26  @customElement('milo-column-header')
    27  export class ColumnHeaderElement extends MobxLitElement {
    28    @observable.ref label!: string;
    29    @observable.ref tooltip!: string;
    30  
    31    // finalized is set to true when the user stopped dragging.
    32    @observable.ref resizeColumn?: (delta: number, finalized: boolean) => void;
    33    @observable.ref sortByColumn?: (ascending: boolean) => void;
    34    @observable.ref groupByColumn?: () => void;
    35    @observable.ref hideColumn?: () => void;
    36  
    37    @observable.ref private menuIsOpen = false;
    38  
    39    @computed private get canResize() {
    40      return Boolean(this.resizeColumn);
    41    }
    42    @computed private get canSort() {
    43      return Boolean(this.sortByColumn);
    44    }
    45    @computed private get canGroup() {
    46      return Boolean(this.groupByColumn);
    47    }
    48    @computed private get canHide() {
    49      return Boolean(this.hideColumn);
    50    }
    51  
    52    constructor() {
    53      super();
    54      makeObservable(this);
    55    }
    56  
    57    private renderResizer() {
    58      if (!this.canResize) {
    59        return html``;
    60      }
    61      let widthDiff = 0;
    62      return html`
    63        <milo-drag-tracker
    64          id="resizer"
    65          @drag=${(e: DragEvent) => {
    66            widthDiff = e.detail.dx;
    67            this.resizeColumn!(widthDiff, false);
    68          }}
    69          @dragend=${() => this.resizeColumn!(widthDiff, true)}
    70        ></milo-drag-tracker>
    71      `;
    72    }
    73  
    74    protected render() {
    75      return html`
    76        <div
    77          id="prop-label"
    78          title=${this.tooltip}
    79          @click=${() => (this.menuIsOpen = !this.menuIsOpen)}
    80        >
    81          ${this.label}
    82        </div>
    83        <div id="padding"></div>
    84        ${this.renderResizer()}
    85        <mwc-menu
    86          x="0"
    87          y="20"
    88          ?open=${this.menuIsOpen}
    89          @closed=${() => (this.menuIsOpen = false)}
    90        >
    91          <mwc-list-item
    92            style=${styleMap({ display: this.canSort ? '' : 'none' })}
    93            @click=${() => this.sortByColumn?.(true)}
    94          >
    95            Sort in ascending order
    96          </mwc-list-item>
    97          <mwc-list-item
    98            style=${styleMap({ display: this.canSort ? '' : 'none' })}
    99            @click=${() => this.sortByColumn?.(false)}
   100          >
   101            Sort in descending order
   102          </mwc-list-item>
   103          <mwc-list-item
   104            style=${styleMap({ display: this.canGroup ? '' : 'none' })}
   105            @click=${() => this.groupByColumn?.()}
   106          >
   107            Group by this column
   108          </mwc-list-item>
   109          <mwc-list-item
   110            style=${styleMap({ display: this.canHide ? '' : 'none' })}
   111            @click=${() => this.hideColumn?.()}
   112          >
   113            Hide column
   114          </mwc-list-item>
   115        </mwc-menu>
   116      `;
   117    }
   118  
   119    static styles = [
   120      commonStyles,
   121      css`
   122        :host {
   123          display: flex;
   124          position: relative;
   125        }
   126  
   127        #prop-label {
   128          flex: 0 1 auto;
   129          cursor: pointer;
   130          color: var(--active-text-color);
   131          overflow: hidden;
   132          text-overflow: ellipsis;
   133        }
   134        #padding {
   135          flex: 1 1 auto;
   136        }
   137        #resizer {
   138          flex: 0 0 auto;
   139          background: linear-gradient(var(--divider-color), var(--divider-color))
   140            2px 0/1px 100% no-repeat;
   141          width: 5px;
   142          cursor: col-resize;
   143        }
   144      `,
   145    ];
   146  }