summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
diff options
context:
space:
mode:
Diffstat (limited to 'polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts')
-rw-r--r--polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts275
1 files changed, 206 insertions, 69 deletions
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
index c392a135d0..845b30cf41 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
@@ -1,98 +1,235 @@
/**
* @license
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Copyright 2016 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
*/
import '@polymer/iron-input/iron-input';
import '../../shared/gr-button/gr-button';
-import '../../../styles/shared-styles';
-import '../../../styles/gr-form-styles';
-import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-menu-editor_html';
-import {customElement, property} from '@polymer/decorators';
-import {TopMenuItemInfo} from '../../../types/common';
+import {PreferencesInfo, TopMenuItemInfo} from '../../../types/common';
+import {css, html, LitElement} from 'lit';
+import {sharedStyles} from '../../../styles/shared-styles';
+import {formStyles} from '../../../styles/gr-form-styles';
+import {state, customElement} from 'lit/decorators';
+import {BindValueChangeEvent} from '../../../types/events';
+import {subscribe} from '../../lit/subscription-controller';
+import {getAppContext} from '../../../services/app-context';
+import {deepEqual} from '../../../utils/deep-util';
+import {createDefaultPreferences} from '../../../constants/constants';
+import {fontStyles} from '../../../styles/gr-font-styles';
+import {classMap} from 'lit/directives/class-map';
+import {menuPageStyles} from '../../../styles/gr-menu-page-styles';
@customElement('gr-menu-editor')
-export class GrMenuEditor extends PolymerElement {
- static get template() {
- return htmlTemplate;
- }
+export class GrMenuEditor extends LitElement {
+ @state()
+ menuItems: TopMenuItemInfo[] = [];
- @property({type: Array})
- menuItems!: TopMenuItemInfo[];
+ @state()
+ originalPrefs: PreferencesInfo = createDefaultPreferences();
- @property({type: String})
- _newName?: string;
+ @state()
+ newName = '';
- @property({type: String})
- _newUrl?: string;
+ @state()
+ newUrl = '';
- _handleMoveUpButton(e: Event) {
- const target = (dom(e) as EventApi).localTarget;
- if (!(target instanceof HTMLElement)) return;
- const index = Number(target.dataset['index']);
- if (index === 0) {
- return;
- }
- const row = this.menuItems[index];
- const prev = this.menuItems[index - 1];
- this.splice('menuItems', index - 1, 2, row, prev);
+ private readonly userModel = getAppContext().userModel;
+
+ override connectedCallback() {
+ super.connectedCallback();
+ subscribe(this, this.userModel.preferences$, prefs => {
+ this.originalPrefs = prefs;
+ this.menuItems = [...prefs.my];
+ });
}
- _handleMoveDownButton(e: Event) {
- const target = (dom(e) as EventApi).localTarget;
- if (!(target instanceof HTMLElement)) return;
- const index = Number(target.dataset['index']);
- if (index === this.menuItems.length - 1) {
- return;
- }
- const row = this.menuItems[index];
- const next = this.menuItems[index + 1];
- this.splice('menuItems', index, 2, next, row);
+ static override styles = [
+ formStyles,
+ sharedStyles,
+ fontStyles,
+ menuPageStyles,
+ css`
+ .buttonColumn {
+ width: 2em;
+ }
+ .moveUpButton,
+ .moveDownButton {
+ width: 100%;
+ }
+ tbody tr:first-of-type td .moveUpButton,
+ tbody tr:last-of-type td .moveDownButton {
+ display: none;
+ }
+ td.urlCell {
+ word-break: break-word;
+ }
+ .newUrlInput {
+ min-width: 23em;
+ }
+ `,
+ ];
+
+ override render() {
+ const unchanged = deepEqual(this.menuItems, this.originalPrefs.my);
+ const classes = {
+ 'heading-2': true,
+ edited: !unchanged,
+ };
+ return html`
+ <div class="gr-form-styles">
+ <h2 id="Menu" class=${classMap(classes)}>Menu</h2>
+ <fieldset id="menu">
+ <table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>URL</th>
+ </tr>
+ </thead>
+ <tbody>
+ ${this.menuItems.map((item, index) =>
+ this.renderMenuItemRow(item, index)
+ )}
+ </tbody>
+ <tfoot>
+ ${this.renderFooterRow()}
+ </tfoot>
+ </table>
+ <gr-button id="save" @click=${this.handleSave} ?disabled=${unchanged}
+ >Save changes</gr-button
+ >
+ <gr-button id="reset" link @click=${this.handleReset}
+ >Reset</gr-button
+ >
+ </fieldset>
+ </div>
+ `;
}
- _handleDeleteButton(e: Event) {
- const target = (dom(e) as EventApi).localTarget;
- if (!(target instanceof HTMLElement)) return;
- const index = Number(target.dataset['index']);
- this.splice('menuItems', index, 1);
+ private renderMenuItemRow(item: TopMenuItemInfo, index: number) {
+ return html`
+ <tr>
+ <td>${item.name}</td>
+ <td class="urlCell">${item.url}</td>
+ <td class="buttonColumn">
+ <gr-button
+ link
+ data-index=${index}
+ @click=${() => this.swapItems(index, index - 1)}
+ class="moveUpButton"
+ >↑</gr-button
+ >
+ </td>
+ <td class="buttonColumn">
+ <gr-button
+ link
+ data-index=${index}
+ @click=${() => this.swapItems(index, index + 1)}
+ class="moveDownButton"
+ >↓</gr-button
+ >
+ </td>
+ <td>
+ <gr-button
+ link
+ data-index=${index}
+ @click=${() => {
+ this.menuItems.splice(index, 1);
+ this.requestUpdate('menuItems');
+ }}
+ class="remove-button"
+ >Delete</gr-button
+ >
+ </td>
+ </tr>
+ `;
}
- _handleAddButton() {
- if (this._computeAddDisabled(this._newName, this._newUrl)) {
- return;
- }
+ private renderFooterRow() {
+ return html`
+ <tr>
+ <th>
+ <iron-input
+ .bindValue=${this.newName}
+ @bind-value-changed=${(e: BindValueChangeEvent) => {
+ this.newName = e.detail.value ?? '';
+ }}
+ >
+ <input
+ is="iron-input"
+ placeholder="New Title"
+ @keydown=${this.handleInputKeydown}
+ />
+ </iron-input>
+ </th>
+ <th>
+ <iron-input
+ .bindValue=${this.newUrl}
+ @bind-value-changed=${(e: BindValueChangeEvent) => {
+ this.newUrl = e.detail.value ?? '';
+ }}
+ >
+ <input
+ class="newUrlInput"
+ placeholder="New URL"
+ @keydown=${this.handleInputKeydown}
+ />
+ </iron-input>
+ </th>
+ <th></th>
+ <th></th>
+ <th>
+ <gr-button
+ id="add"
+ link
+ ?disabled=${this.newName.length === 0 || this.newUrl.length === 0}
+ @click=${this.handleAddButton}
+ >Add</gr-button
+ >
+ </th>
+ </tr>
+ `;
+ }
- this.splice('menuItems', this.menuItems.length, 0, {
- name: this._newName,
- url: this._newUrl,
- target: '_blank',
+ private handleSave() {
+ this.userModel.updatePreferences({
+ ...this.originalPrefs,
+ my: this.menuItems,
});
+ }
+
+ private handleReset() {
+ this.menuItems = [...this.originalPrefs.my];
+ }
- this._newName = '';
- this._newUrl = '';
+ private swapItems(i: number, j: number) {
+ const max = this.menuItems.length - 1;
+ if (i < 0 || j < 0) return;
+ if (i > max || j > max) return;
+ const x = this.menuItems[i];
+ this.menuItems[i] = this.menuItems[j];
+ this.menuItems[j] = x;
+ this.requestUpdate('menuItems');
}
- _computeAddDisabled(newName?: string, newUrl?: string) {
- return !newName?.length || !newUrl?.length;
+ // visible for testing
+ handleAddButton() {
+ if (this.newName.length === 0 || this.newUrl.length === 0) return;
+
+ this.menuItems.push({
+ name: this.newName,
+ url: this.newUrl,
+ target: '_blank',
+ });
+ this.newName = '';
+ this.newUrl = '';
+ this.requestUpdate('menuItems');
}
- _handleInputKeydown(e: KeyboardEvent) {
+ private handleInputKeydown(e: KeyboardEvent) {
if (e.keyCode === 13) {
e.stopPropagation();
- this._handleAddButton();
+ this.handleAddButton();
}
}
}