Merge changes I5333fbcd,I3ee10e8e * changes: Add keyboard shortcut for selecting the bulk action checkbox Move ShortcutsService from AppContext to DI
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts index 1f46530..ffa0dca 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts +++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
@@ -292,7 +292,7 @@ <input type="checkbox" .checked=${this.checked} - @click=${() => this.handleChangeSelectionClick()} + @click=${() => this.toggleCheckbox()} /> </td> `; @@ -607,15 +607,6 @@ `; } - private handleChangeSelectionClick() { - assertIsDefined(this.change, 'change'); - this.checked = !this.checked; - if (this.checked) - this.getBulkActionsModel().addSelectedChangeNum(this.change._number); - else - this.getBulkActionsModel().removeSelectedChangeNum(this.change._number); - } - private changeStatuses() { if (!this.change) return []; return changeStatuses(this.change); @@ -672,6 +663,15 @@ return str; } + toggleCheckbox() { + assertIsDefined(this.change, 'change'); + this.checked = !this.checked; + if (this.checked) + this.getBulkActionsModel().addSelectedChangeNum(this.change._number); + else + this.getBulkActionsModel().removeSelectedChangeNum(this.change._number); + } + // private but used in test computeTruncatedRepoDisplay() { if (!this.change?.project) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-section/gr-change-list-section.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-section/gr-change-list-section.ts index 657a458..068487c 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list-section/gr-change-list-section.ts +++ b/polygerrit-ui/app/elements/change-list/gr-change-list-section/gr-change-list-section.ts
@@ -27,6 +27,8 @@ BulkActionsModel, } from '../../../models/bulk-actions/bulk-actions-model'; import {subscribe} from '../../lit/subscription-controller'; +import {GrChangeListItem} from '../gr-change-list-item/gr-change-list-item'; +import {queryAll} from '../../../utils/common-util'; const NUMBER_FIXED_COLUMNS = 3; const LABEL_PREFIX_INVALID_PROLOG = 'Invalid-Prolog-Rules-Label-Name--'; @@ -320,6 +322,12 @@ return cols; } + toggleChange(index: number) { + const items = queryAll<GrChangeListItem>(this, 'gr-change-list-item'); + if (index >= items.length) throw new Error('invalid item index'); + items[index].toggleCheckbox(); + } + // private but used in test computeItemSelected(index: number) { return index === this.selectedIndex;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts index cd66fd4..4061ab0 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts +++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
@@ -23,7 +23,7 @@ import {ColumnNames, ScrollMode} from '../../../constants/constants'; import {getRequirements} from '../../../utils/label-util'; import {addGlobalShortcut, Key} from '../../../utils/dom-util'; -import {unique} from '../../../utils/common-util'; +import {assertIsDefined, unique} from '../../../utils/common-util'; import {changeListStyles} from '../../../styles/gr-change-list-styles'; import {fontStyles} from '../../../styles/gr-font-styles'; import {sharedStyles} from '../../../styles/shared-styles'; @@ -163,6 +163,9 @@ this.shortcuts.addAbstract(Shortcut.REFRESH_CHANGE_LIST, () => this.refreshChangeList() ); + this.shortcuts.addAbstract(Shortcut.TOGGLE_CHECKBOX, () => + this.toggleCheckbox() + ); addGlobalShortcut({key: Key.ENTER}, () => this.openChange()); } @@ -279,6 +282,25 @@ } } + private toggleCheckbox() { + assertIsDefined(this.selectedIndex, 'selectedIndex'); + let selectedIndex = this.selectedIndex; + assertIsDefined(this.sections, 'sections'); + const changeSections = queryAll<GrChangeListSection>( + this, + 'gr-change-list-section' + ); + for (let i = 0; i < this.sections.length; i++) { + if (selectedIndex >= this.sections[i].results.length) { + selectedIndex -= this.sections[i].results.length; + continue; + } + changeSections[i].toggleChange(selectedIndex); + return; + } + throw new Error('invalid selected index'); + } + private computeVisibleChangeTableColumns() { if (!this.config) return;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.ts index 0a019b9..b49c916 100644 --- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.ts +++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.ts
@@ -16,7 +16,11 @@ waitUntil, } from '../../../test/test-utils'; import {Key} from '../../../utils/dom-util'; -import {ColumnNames, TimeFormat} from '../../../constants/constants'; +import { + ColumnNames, + createDefaultPreferences, + TimeFormat, +} from '../../../constants/constants'; import {AccountId, NumericChangeId} from '../../../types/common'; import { createChange, @@ -25,6 +29,14 @@ } from '../../../test/test-data-generators'; import {GrChangeListItem} from '../gr-change-list-item/gr-change-list-item'; import {GrChangeListSection} from '../gr-change-list-section/gr-change-list-section'; +import {getAppContext} from '../../../services/app-context'; +import {fixture} from '@open-wc/testing-helpers'; +import {wrapInProvider} from '../../../models/di-provider-element'; +import { + ShortcutsService, + shortcutsServiceToken, +} from '../../../services/shortcuts/shortcuts-service'; +import {html} from 'lit'; const basicFixture = fixtureFromElement('gr-change-list'); @@ -197,22 +209,7 @@ sinon.stub(element, 'computeLabelNames'); element.sections = [{results: new Array(1)}, {results: new Array(2)}]; element.selectedIndex = 0; - element.preferences = { - legacycid_in_change_table: true, - time_format: TimeFormat.HHMM_12, - change_table: [ - 'Subject', - 'Status', - 'Owner', - 'Reviewers', - 'Comments', - 'Repo', - 'Branch', - 'Updated', - 'Size', - ColumnNames.STATUS2, - ], - }; + element.preferences = createDefaultPreferences(); element.config = createServerInfo(); element.changes = [ {...createChange(), _number: 0 as NumericChangeId}, @@ -280,6 +277,90 @@ assert.equal(element.selectedIndex, 0); }); + test('toggle checkbox keyboard shortcut', async () => { + const flagsService = getAppContext().flagsService; + sinon.stub(flagsService, 'isEnabled').returns(true); + element = ( + await fixture( + wrapInProvider( + html`<gr-change-list></gr-change-list>`, + shortcutsServiceToken, + new ShortcutsService(getAppContext().userModel, flagsService) + ) + ) + ).querySelector('gr-change-list')!; + await element.updateComplete; + + const getCheckbox = (item: GrChangeListItem) => + queryAndAssert<HTMLInputElement>(query(item, '.selection'), 'input'); + + sinon.stub(element, 'computeLabelNames'); + element.sections = [{results: new Array(1)}, {results: new Array(2)}]; + element.selectedIndex = 0; + element.preferences = createDefaultPreferences(); + element.config = createServerInfo(); + element.changes = [ + {...createChange(), _number: 0 as NumericChangeId}, + {...createChange(), _number: 1 as NumericChangeId}, + {...createChange(), _number: 2 as NumericChangeId}, + ]; + // explicitly trigger sectionsChanged so that cursor stops are properly + // updated + await element.sectionsChanged(); + await element.updateComplete; + const section = queryAndAssert<GrChangeListSection>( + element, + 'gr-change-list-section' + ); + await section.updateComplete; + const elementItems = queryAll<GrChangeListItem>( + section, + 'gr-change-list-item' + ); + assert.equal(elementItems.length, 3); + + assert.isTrue(elementItems[0].hasAttribute('selected')); + await element.updateComplete; + + pressKey(element, 'x'); + await element.updateComplete; + + assert.isTrue(getCheckbox(elementItems[0]).checked); + + pressKey(element, 'x'); + await element.updateComplete; + assert.isFalse(getCheckbox(elementItems[0]).checked); + + pressKey(element, 'j'); + await element.updateComplete; + + assert.equal(element.selectedIndex, 1); + assert.isTrue(elementItems[1].hasAttribute('selected')); + + pressKey(element, 'x'); + await element.updateComplete; + + assert.isTrue(getCheckbox(elementItems[1]).checked); + + pressKey(element, 'x'); + await element.updateComplete; + assert.isFalse(getCheckbox(elementItems[1]).checked); + + pressKey(element, 'j'); + await element.updateComplete; + assert.equal(element.selectedIndex, 2); + assert.isTrue(elementItems[2].hasAttribute('selected')); + + pressKey(element, 'x'); + await element.updateComplete; + + assert.isTrue(getCheckbox(elementItems[2]).checked); + + pressKey(element, 'x'); + await element.updateComplete; + assert.isFalse(getCheckbox(elementItems[2]).checked); + }); + test('no changes', async () => { element.changes = []; await element.updateComplete;
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts index b8cbd26..1aa5334 100644 --- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts +++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -183,7 +183,10 @@ getRemovedByReason, hasAttention, } from '../../../utils/attention-set-util'; -import {listen} from '../../../services/shortcuts/shortcuts-service'; +import { + listen, + shortcutsServiceToken, +} from '../../../services/shortcuts/shortcuts-service'; import {LoadingStatus} from '../../../models/change/change-model'; import {commentsModelToken} from '../../../models/comments/comments-model'; import {resolve, DIPolymerElement} from '../../../models/dependency'; @@ -600,7 +603,7 @@ // Private but used in tests. readonly getCommentsModel = resolve(this, commentsModelToken); - private readonly shortcuts = getAppContext().shortcutsService; + private readonly getShortcutsService = resolve(this, shortcutsServiceToken); private subscriptions: Subscription[] = []; @@ -2654,7 +2657,7 @@ } createTitle(shortcutName: Shortcut, section: ShortcutSection) { - return this.shortcuts.createTitle(shortcutName, section); + return this.getShortcutsService().createTitle(shortcutName, section); } _handleRevisionActionsChanged(
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts index e5fe8b6..de6ea8e 100644 --- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts +++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -32,11 +32,12 @@ Shortcut, ShortcutSection, } from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin'; -import {getAppContext} from '../../../services/app-context'; import {css, html, LitElement} from 'lit'; import {sharedStyles} from '../../../styles/shared-styles'; import {when} from 'lit/directives/when'; import {ifDefined} from 'lit/directives/if-defined'; +import {shortcutsServiceToken} from '../../../services/shortcuts/shortcuts-service'; +import {resolve} from '../../../models/dependency'; @customElement('gr-file-list-header') export class GrFileListHeader extends LitElement { @@ -110,7 +111,7 @@ @query('#collapseBtn') collapseBtn?: GrButton; - private readonly shortcuts = getAppContext().shortcutsService; + private readonly getShortcutsService = resolve(this, shortcutsServiceToken); // Caps the number of files that can be shown and have the 'show diffs' / // 'hide diffs' buttons still be functional. @@ -427,7 +428,7 @@ } private createTitle(shortcutName: Shortcut, section: ShortcutSection) { - return this.shortcuts.createTitle(shortcutName, section); + return this.getShortcutsService().createTitle(shortcutName, section); } }
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts index a1d80aa..a0bb383 100644 --- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts +++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
@@ -43,6 +43,7 @@ import {paperStyles} from '../../../styles/gr-paper-styles'; import {when} from 'lit/directives/when'; import {ifDefined} from 'lit/directives/if-defined'; +import {shortcutsServiceToken} from '../../../services/shortcuts/shortcuts-service'; /** * The content of the enum is also used in the UI for the button text. @@ -319,7 +320,7 @@ private readonly reporting = getAppContext().reportingService; - private readonly shortcuts = getAppContext().shortcutsService; + private readonly getShortcutsService = resolve(this, shortcutsServiceToken); constructor() { super(); @@ -468,13 +469,13 @@ private computeExpandAllTitle() { if (this.expandAllState === ExpandAllState.COLLAPSE_ALL) { - return this.shortcuts.createTitle( + return this.getShortcutsService().createTitle( Shortcut.COLLAPSE_ALL_MESSAGES, ShortcutSection.ACTIONS ); } if (this.expandAllState === ExpandAllState.EXPAND_ALL) { - return this.shortcuts.createTitle( + return this.getShortcutsService().createTitle( Shortcut.EXPAND_ALL_MESSAGES, ShortcutSection.ACTIONS );
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts index f53a342..73e5da3 100644 --- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts +++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
@@ -13,8 +13,11 @@ ShortcutSection, SectionView, } from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin'; -import {getAppContext} from '../../../services/app-context'; -import {ShortcutViewListener} from '../../../services/shortcuts/shortcuts-service'; +import { + shortcutsServiceToken, + ShortcutViewListener, +} from '../../../services/shortcuts/shortcuts-service'; +import {resolve} from '../../../models/dependency'; declare global { interface HTMLElementTagNameMap { @@ -43,7 +46,7 @@ private readonly shortcutListener: ShortcutViewListener; - private readonly shortcuts = getAppContext().shortcutsService; + private readonly getShortcutsService = resolve(this, shortcutsServiceToken); constructor() { super(); @@ -151,11 +154,11 @@ override connectedCallback() { super.connectedCallback(); - this.shortcuts.addListener(this.shortcutListener); + this.getShortcutsService().addListener(this.shortcutListener); } override disconnectedCallback() { - this.shortcuts.removeListener(this.shortcutListener); + this.getShortcutsService().removeListener(this.shortcutListener); super.disconnectedCallback(); }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts index 1fa2413..4e99065 100644 --- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts +++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -112,7 +112,10 @@ import {isFalse, throttleWrap, until} from '../../../utils/async-util'; import {filter, take, switchMap} from 'rxjs/operators'; import {combineLatest, Subscription} from 'rxjs'; -import {listen} from '../../../services/shortcuts/shortcuts-service'; +import { + listen, + shortcutsServiceToken, +} from '../../../services/shortcuts/shortcuts-service'; import {LoadingStatus} from '../../../models/change/change-model'; import {DisplayLine} from '../../../api/diff'; import {GrDownloadDialog} from '../../change/gr-download-dialog/gr-download-dialog'; @@ -371,7 +374,7 @@ // Private but used in tests. readonly getCommentsModel = resolve(this, commentsModelToken); - private readonly shortcuts = getAppContext().shortcutsService; + private readonly getShortcutsService = resolve(this, shortcutsServiceToken); _throttledToggleFileReviewed?: (e: KeyboardEvent) => void; @@ -1816,7 +1819,7 @@ } createTitle(shortcutName: Shortcut, section: ShortcutSection) { - return this.shortcuts.createTitle(shortcutName, section); + return this.getShortcutsService().createTitle(shortcutName, section); } }
diff --git a/polygerrit-ui/app/elements/lit/shortcut-controller.ts b/polygerrit-ui/app/elements/lit/shortcut-controller.ts index 5755557..9d39cd7 100644 --- a/polygerrit-ui/app/elements/lit/shortcut-controller.ts +++ b/polygerrit-ui/app/elements/lit/shortcut-controller.ts
@@ -5,9 +5,9 @@ */ import {ReactiveController, ReactiveControllerHost} from 'lit'; import {Binding} from '../../utils/dom-util'; -import {ShortcutsService} from '../../services/shortcuts/shortcuts-service'; -import {getAppContext} from '../../services/app-context'; +import {shortcutsServiceToken} from '../../services/shortcuts/shortcuts-service'; import {Shortcut} from '../../services/shortcuts/shortcuts-config'; +import {resolve} from '../../models/dependency'; interface ShortcutListener { binding: Binding; @@ -22,7 +22,10 @@ type Cleanup = () => void; export class ShortcutController implements ReactiveController { - private readonly service: ShortcutsService = getAppContext().shortcutsService; + private readonly getShortcutsService = resolve( + this.host, + shortcutsServiceToken + ); private readonly listenersLocal: ShortcutListener[] = []; @@ -61,18 +64,24 @@ } hostConnected() { + const shortcutsService = this.getShortcutsService(); for (const {binding, listener} of this.listenersLocal) { - const cleanup = this.service.addShortcut(this.host, binding, listener, { - shouldSuppress: false, - }); + const cleanup = shortcutsService.addShortcut( + this.host, + binding, + listener, + { + shouldSuppress: false, + } + ); this.cleanups.push(cleanup); } for (const {shortcut, listener} of this.listenersAbstract) { - const cleanup = this.service.addShortcutListener(shortcut, listener); + const cleanup = shortcutsService.addShortcutListener(shortcut, listener); this.cleanups.push(cleanup); } for (const {binding, listener} of this.listenersGlobal) { - const cleanup = this.service.addShortcut( + const cleanup = shortcutsService.addShortcut( document.body, binding, listener
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts index 817ec5c..dfebb8d 100644 --- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts +++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.ts
@@ -10,10 +10,11 @@ Shortcut, ShortcutSection, } from '../../../services/shortcuts/shortcuts-config'; -import {getAppContext} from '../../../services/app-context'; import {sharedStyles} from '../../../styles/shared-styles'; import {LitElement, css, html} from 'lit'; import {customElement, property} from 'lit/decorators'; +import {resolve} from '../../../models/dependency'; +import {shortcutsServiceToken} from '../../../services/shortcuts/shortcuts-service'; declare global { interface HTMLElementTagNameMap { @@ -37,7 +38,7 @@ @property({type: Object}) change?: ChangeInfo; - private readonly shortcuts = getAppContext().shortcutsService; + private readonly getShortcutsService = resolve(this, shortcutsServiceToken); static override get styles() { return [ @@ -73,7 +74,7 @@ return html` <button role="checkbox" - title=${this.shortcuts.createTitle( + title=${this.getShortcutsService().createTitle( Shortcut.TOGGLE_CHANGE_STAR, ShortcutSection.ACTIONS )}
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts index 77150be..7596804 100644 --- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts +++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
@@ -4,9 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ import {property} from '@polymer/decorators'; -import {PolymerElement} from '@polymer/polymer'; import {check, Constructor} from '../../utils/common-util'; -import {getAppContext} from '../../services/app-context'; import { Shortcut, ShortcutSection, @@ -15,7 +13,9 @@ import { SectionView, ShortcutListener, + shortcutsServiceToken, } from '../../services/shortcuts/shortcuts-service'; +import {DIPolymerElement, resolve} from '../../models/dependency'; export { Shortcut, @@ -25,7 +25,7 @@ SectionView, }; -export const KeyboardShortcutMixin = <T extends Constructor<PolymerElement>>( +export const KeyboardShortcutMixin = <T extends Constructor<DIPolymerElement>>( superClass: T ) => { /** @@ -39,7 +39,7 @@ // This enables `ShortcutSection` to be used in the html template. ShortcutSection = ShortcutSection; - private readonly shortcuts = getAppContext().shortcutsService; + private readonly getShortcutsService = resolve(this, shortcutsServiceToken); /** Used to disable shortcuts when the element is not visible. */ private observer?: IntersectionObserver; @@ -103,7 +103,7 @@ if (this.bindingsEnabled) return; this.bindingsEnabled = true; - this.shortcuts.attachHost(this, this.keyboardShortcuts()); + this.getShortcutsService().attachHost(this, this.keyboardShortcuts()); } /** @@ -114,7 +114,7 @@ private disableBindings() { if (!this.bindingsEnabled) return; this.bindingsEnabled = false; - this.shortcuts.detachHost(this); + this.getShortcutsService().detachHost(this); } private hasKeyboardShortcuts() {
diff --git a/polygerrit-ui/app/services/app-context-init.ts b/polygerrit-ui/app/services/app-context-init.ts index 9e3ca9b..6904529 100644 --- a/polygerrit-ui/app/services/app-context-init.ts +++ b/polygerrit-ui/app/services/app-context-init.ts
@@ -21,7 +21,10 @@ commentsModelToken, } from '../models/comments/comments-model'; import {RouterModel} from './router/router-model'; -import {ShortcutsService} from './shortcuts/shortcuts-service'; +import { + ShortcutsService, + shortcutsServiceToken, +} from './shortcuts/shortcuts-service'; import {assertIsDefined} from '../utils/common-util'; import {ConfigModel, configModelToken} from '../models/config/config-model'; import {BrowserModel, browserModelToken} from '../models/browser/browser-model'; @@ -59,16 +62,6 @@ assertIsDefined(ctx.restApiService, 'restApiService'); return new UserModel(ctx.restApiService); }, - shortcutsService: (ctx: Partial<AppContext>) => { - assertIsDefined(ctx.userModel, 'userModel'); - assertIsDefined(ctx.reportingService, 'reportingService'); - assertIsDefined(ctx.flagsService, 'flagsService'); - return new ShortcutsService( - ctx.userModel, - ctx.flagsService, - ctx.reportingService - ); - }, pluginsModel: (_ctx: Partial<AppContext>) => new PluginsModel(), highlightService: (ctx: Partial<AppContext>) => { assertIsDefined(ctx.reportingService, 'reportingService'); @@ -112,5 +105,12 @@ dependencies.set(checksModelToken, checksModel); + const shortcutsService = new ShortcutsService( + appContext.userModel, + appContext.flagsService, + appContext.reportingService + ); + dependencies.set(shortcutsServiceToken, shortcutsService); + return dependencies; }
diff --git a/polygerrit-ui/app/services/app-context.ts b/polygerrit-ui/app/services/app-context.ts index cab34ba..3e1017d 100644 --- a/polygerrit-ui/app/services/app-context.ts +++ b/polygerrit-ui/app/services/app-context.ts
@@ -13,7 +13,6 @@ import {StorageService} from './storage/gr-storage'; import {UserModel} from '../models/user/user-model'; import {RouterModel} from './router/router-model'; -import {ShortcutsService} from './shortcuts/shortcuts-service'; import {PluginsModel} from '../models/plugins/plugins-model'; import {HighlightService} from './highlight/highlight-service'; @@ -27,7 +26,6 @@ jsApiService: JsApiService; storageService: StorageService; userModel: UserModel; - shortcutsService: ShortcutsService; pluginsModel: PluginsModel; highlightService: HighlightService; }
diff --git a/polygerrit-ui/app/services/shortcuts/shortcuts-config.ts b/polygerrit-ui/app/services/shortcuts/shortcuts-config.ts index 6f13117..2996e99 100644 --- a/polygerrit-ui/app/services/shortcuts/shortcuts-config.ts +++ b/polygerrit-ui/app/services/shortcuts/shortcuts-config.ts
@@ -6,7 +6,7 @@ /** Enum for all special shortcuts */ import {ComboKey, Key, Modifier, Binding} from '../../utils/dom-util'; -import {FlagsService} from '../flags/flags'; +import {FlagsService, KnownExperimentId} from '../flags/flags'; export enum SPECIAL_SHORTCUT { DOC_ONLY = 'DOC_ONLY', @@ -101,6 +101,8 @@ SEND_REPLY = 'SEND_REPLY', EMOJI_DROPDOWN = 'EMOJI_DROPDOWN', TOGGLE_BLAME = 'TOGGLE_BLAME', + + TOGGLE_CHECKBOX = 'TOGGLE_CHECKBOX', } export interface ShortcutHelpItem { @@ -109,7 +111,7 @@ bindings: Binding[]; } -export function createShortCutConfig(_flagsService: FlagsService) { +export function createShortCutConfig(flagsService: FlagsService) { const config = new Map<ShortcutSection, ShortcutHelpItem[]>(); function describe( shortcut: Shortcut, @@ -165,6 +167,16 @@ {key: 'w', combo: ComboKey.G} ); + if (flagsService.isEnabled(KnownExperimentId.BULK_ACTIONS)) { + describe( + Shortcut.TOGGLE_CHECKBOX, + ShortcutSection.ACTIONS, + 'Toggle checkbox', + { + key: 'x', + } + ); + } describe( Shortcut.CURSOR_NEXT_CHANGE, ShortcutSection.ACTIONS,
diff --git a/polygerrit-ui/app/services/shortcuts/shortcuts-service.ts b/polygerrit-ui/app/services/shortcuts/shortcuts-service.ts index 4232699..c27da15 100644 --- a/polygerrit-ui/app/services/shortcuts/shortcuts-service.ts +++ b/polygerrit-ui/app/services/shortcuts/shortcuts-service.ts
@@ -24,6 +24,7 @@ import {Finalizable} from '../registry'; import {UserModel} from '../../models/user/user-model'; import {FlagsService} from '../flags/flags'; +import {define} from '../../models/dependency'; export type SectionView = Array<{binding: string[][]; text: string}>; @@ -52,6 +53,9 @@ export const COMBO_TIMEOUT_MS = 1000; +export const shortcutsServiceToken = + define<ShortcutsService>('shortcuts-service'); + /** * Shortcuts service, holds all hosts, bindings and listeners. */
diff --git a/polygerrit-ui/app/test/common-test-setup.ts b/polygerrit-ui/app/test/common-test-setup.ts index 1492262..fb6b482 100644 --- a/polygerrit-ui/app/test/common-test-setup.ts +++ b/polygerrit-ui/app/test/common-test-setup.ts
@@ -148,8 +148,6 @@ // tests. initGlobalVariables(appContext); - const shortcuts = appContext.shortcutsService; - assert.isTrue(shortcuts._testOnly_isEmpty()); const selection = document.getSelection(); if (selection) { selection.removeAllRanges();
diff --git a/polygerrit-ui/app/test/test-app-context-init.ts b/polygerrit-ui/app/test/test-app-context-init.ts index ed5d5be..8c8e46b 100644 --- a/polygerrit-ui/app/test/test-app-context-init.ts +++ b/polygerrit-ui/app/test/test-app-context-init.ts
@@ -24,7 +24,10 @@ commentsModelToken, } from '../models/comments/comments-model'; import {RouterModel} from '../services/router/router-model'; -import {ShortcutsService} from '../services/shortcuts/shortcuts-service'; +import { + ShortcutsService, + shortcutsServiceToken, +} from '../services/shortcuts/shortcuts-service'; import {ConfigModel, configModelToken} from '../models/config/config-model'; import {BrowserModel, browserModelToken} from '../models/browser/browser-model'; import {PluginsModel} from '../models/plugins/plugins-model'; @@ -115,5 +118,13 @@ dependencies.set(checksModelToken, checksModelCreator); + const shortcutServiceCreator = () => + new ShortcutsService( + appContext.userModel, + appContext.flagsService, + appContext.reportingService + ); + dependencies.set(shortcutsServiceToken, shortcutServiceCreator); + return dependencies; }
diff --git a/polygerrit-ui/app/test/test-utils.ts b/polygerrit-ui/app/test/test-utils.ts index 82b3c00..b53d767 100644 --- a/polygerrit-ui/app/test/test-utils.ts +++ b/polygerrit-ui/app/test/test-utils.ts
@@ -13,7 +13,6 @@ import {AuthService} from '../services/gr-auth/gr-auth'; import {ReportingService} from '../services/gr-reporting/gr-reporting'; import {UserModel} from '../models/user/user-model'; -import {ShortcutsService} from '../services/shortcuts/shortcuts-service'; import {queryAndAssert, query} from '../utils/common-util'; import {FlagsService} from '../services/flags/flags'; import {Key, Modifier} from '../utils/dom-util'; @@ -113,10 +112,6 @@ return sinon.stub(getAppContext().userModel, method); } -export function stubShortcuts<K extends keyof ShortcutsService>(method: K) { - return sinon.stub(getAppContext().shortcutsService, method); -} - export function stubHighlightService<K extends keyof HighlightService>( method: K ) {