blob: ea20b54e3615fa0d91ec9de9b5e9f69a1b93a5ef [file] [log] [blame]
Dave Borowitz8cdc76b2018-03-26 10:04:27 -04001/**
2 * @license
Ben Rohlfs94fcbbc2022-05-27 10:45:03 +02003 * Copyright 2016 Google LLC
4 * SPDX-License-Identifier: Apache-2.0
Dave Borowitz8cdc76b2018-03-26 10:04:27 -04005 */
Milutin Kristofic65f35c12020-08-19 20:35:28 +02006import '../../shared/gr-button/gr-button';
Dhruv Srivastavae77b66c2020-12-23 11:44:13 +01007import {ServerInfo} from '../../../types/common';
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +02008import {LitElement, css, html} from 'lit';
Frank Borden42c1a452022-08-11 16:27:20 +02009import {customElement, property, state} from 'lit/decorators.js';
Milutin Kristofic4aa368a2022-04-05 20:49:37 +020010import {sharedStyles} from '../../../styles/shared-styles';
Milutin Kristoficaa1c08b2023-09-06 10:34:16 +020011import {grFormStyles} from '../../../styles/gr-form-styles';
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +020012import {fire} from '../../../utils/event-util';
13import {ValueChangedEvent} from '../../../types/events';
Dhruv980b9102022-05-05 14:22:24 +020014import {ColumnNames} from '../../../constants/constants';
Dhruv Srivastavaefe10d9c2022-06-28 12:22:48 +020015import {subscribe} from '../../lit/subscription-controller';
16import {resolve} from '../../../models/dependency';
17import {configModelToken} from '../../../models/config/config-model';
brohlfsbb5a93a2021-08-27 22:23:46 +020018
Milutin Kristofic65f35c12020-08-19 20:35:28 +020019@customElement('gr-change-table-editor')
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +020020export class GrChangeTableEditor extends LitElement {
21 @property({type: Array})
Ben Rohlfs819aad02021-03-08 16:34:26 +010022 displayedColumns: string[] = [];
Milutin Kristofic65f35c12020-08-19 20:35:28 +020023
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +020024 @property({type: Boolean})
Milutin Kristofic65f35c12020-08-19 20:35:28 +020025 showNumber?: boolean;
26
Dhruv Srivastavae77b66c2020-12-23 11:44:13 +010027 @property({type: Array})
Ben Rohlfsf3f83a52023-08-23 10:49:12 +020028 defaultColumns: string[] = Object.values(ColumnNames);
Dhruv Srivastavae77b66c2020-12-23 11:44:13 +010029
Dhruv Srivastavaefe10d9c2022-06-28 12:22:48 +020030 @state()
31 serverConfig?: ServerInfo;
32
Dhruv Srivastavaefe10d9c2022-06-28 12:22:48 +020033 private readonly getConfigModel = resolve(this, configModelToken);
34
Ben Rohlfs9d6c32a2023-05-24 11:10:59 +020035 static override get styles() {
36 return [
37 sharedStyles,
Milutin Kristoficaa1c08b2023-09-06 10:34:16 +020038 grFormStyles,
Ben Rohlfs9d6c32a2023-05-24 11:10:59 +020039 css`
40 #changeCols {
41 width: auto;
42 }
43 #changeCols .visibleHeader {
44 text-align: center;
45 }
46 .checkboxContainer {
47 cursor: pointer;
48 text-align: center;
49 }
50 .checkboxContainer input {
51 cursor: pointer;
52 }
53 .checkboxContainer:hover {
54 outline: 1px solid var(--border-color);
55 }
56 `,
57 ];
58 }
Milutin Kristofic4aa368a2022-04-05 20:49:37 +020059
Dhruv Srivastavaefe10d9c2022-06-28 12:22:48 +020060 constructor() {
61 super();
62 subscribe(
63 this,
64 () => this.getConfigModel().serverConfig$,
65 config => {
66 this.serverConfig = config;
67 }
68 );
69 }
70
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +020071 override render() {
Milutin Kristofic4aa368a2022-04-05 20:49:37 +020072 return html`<div class="gr-form-styles">
73 <table id="changeCols">
74 <thead>
75 <tr>
76 <th class="nameHeader">Column</th>
77 <th class="visibleHeader">Visible</th>
78 </tr>
79 </thead>
80 <tbody>
81 <tr>
82 <td><label for="numberCheckbox">Number</label></td>
83 <td
84 class="checkboxContainer"
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +020085 @click=${this.handleCheckboxContainerClick}
Milutin Kristofic4aa368a2022-04-05 20:49:37 +020086 >
87 <input
88 id="numberCheckbox"
89 type="checkbox"
90 name="number"
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +020091 @click=${this.handleNumberCheckboxClick}
92 ?checked=${this.showNumber}
Milutin Kristofic4aa368a2022-04-05 20:49:37 +020093 />
94 </td>
95 </tr>
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +020096 ${this.defaultColumns.map(column => this.renderRow(column))}
Milutin Kristofic4aa368a2022-04-05 20:49:37 +020097 </tbody>
98 </table>
99 </div>`;
100 }
101
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200102 renderRow(column: string) {
103 return html`<tr>
104 <td><label for=${column}>${column}</label></td>
105 <td class="checkboxContainer" @click=${this.handleCheckboxContainerClick}>
106 <input
107 id=${column}
108 type="checkbox"
109 name=${column}
110 @click=${this.handleTargetClick}
111 ?checked=${!this.computeIsColumnHidden(column)}
112 />
113 </td>
114 </tr>`;
115 }
116
Frank Bordenca8165b2021-09-28 17:57:09 +0200117 /**
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100118 * Get the list of enabled column names from whichever checkboxes are
119 * checked (excluding the number checkbox).
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200120 * private but used in test
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100121 */
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200122 getDisplayedColumns() {
123 if (this.shadowRoot === null) return [];
Ben Rohlfs3f279682022-02-25 12:07:27 +0100124 return Array.from(
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200125 this.shadowRoot.querySelectorAll<HTMLInputElement>(
Ben Rohlfs3f279682022-02-25 12:07:27 +0100126 '.checkboxContainer input:not([name=number])'
127 )
Chris Poucetcaeea1b2021-08-19 22:12:56 +0000128 )
Milutin Kristofic65f35c12020-08-19 20:35:28 +0200129 .filter(checkbox => checkbox.checked)
130 .map(checkbox => checkbox.name);
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100131 }
132
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200133 private computeIsColumnHidden(columnToCheck?: string) {
134 if (!this.displayedColumns || !columnToCheck) {
Frank Bordenca8165b2021-09-28 17:57:09 +0200135 return false;
136 }
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200137 return !this.displayedColumns.includes(columnToCheck);
Frank Bordenca8165b2021-09-28 17:57:09 +0200138 }
139
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100140 /**
141 * Handle a click on a checkbox container and relay the click to the checkbox it
142 * contains.
143 */
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200144 private handleCheckboxContainerClick(e: MouseEvent) {
Milutin Kristofic65f35c12020-08-19 20:35:28 +0200145 if (e.target === null) return;
146 const checkbox = (e.target as HTMLElement).querySelector('input');
147 if (!checkbox) {
148 return;
149 }
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100150 checkbox.click();
151 }
152
153 /**
154 * Handle a click on the number checkbox and update the showNumber property
155 * accordingly.
156 */
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200157 private handleNumberCheckboxClick(e: MouseEvent) {
158 this.showNumber = (e.target as HTMLInputElement).checked;
159 fire(this, 'show-number-changed', {value: this.showNumber});
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100160 }
161
162 /**
163 * Handle a click on a displayed column checkboxes (excluding number) and
164 * update the displayedColumns property accordingly.
165 */
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200166 private handleTargetClick() {
167 this.displayedColumns = this.getDisplayedColumns();
168 fire(this, 'displayed-columns-changed', {value: this.displayedColumns});
Dmitrii Filippovdaf0ec92020-03-17 11:27:28 +0100169 }
170}
171
Milutin Kristofic65f35c12020-08-19 20:35:28 +0200172declare global {
Milutin Kristoficfb5b14c2022-04-05 22:27:29 +0200173 interface HTMLElementEventMap {
174 'show-number-changed': ValueChangedEvent<boolean>;
175 'displayed-columns-changed': ValueChangedEvent<string[]>;
176 }
Milutin Kristofic65f35c12020-08-19 20:35:28 +0200177 interface HTMLElementTagNameMap {
178 'gr-change-table-editor': GrChangeTableEditor;
179 }
180}