diff --git a/ui/app/components/keyboard-hooks.js b/ui/app/components/keyboard-hooks.js deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/ui/app/components/keyboard-shortcuts-modal.js b/ui/app/components/keyboard-shortcuts-modal.js index 7cd206469069..bb99eacda464 100644 --- a/ui/app/components/keyboard-shortcuts-modal.js +++ b/ui/app/components/keyboard-shortcuts-modal.js @@ -1,6 +1,5 @@ import Component from '@glimmer/component'; import { inject as service } from '@ember/service'; -import { htmlSafe } from '@ember/template'; import { computed } from '@ember/object'; import Tether from 'tether'; @@ -28,7 +27,7 @@ export default class KeyboardShortcutsModalComponent extends Component { * hints: filter keyCommands to those that have an element property, * and then compute a position on screen to place the hint. */ - @computed('keyboard.keyCommands.length', 'keyboard.displayHints') + @computed('keyboard.{keyCommands.length,displayHints}') get hints() { if (this.keyboard.displayHints) { return this.keyboard.keyCommands.filter((c) => c.element); @@ -47,7 +46,7 @@ export default class KeyboardShortcutsModalComponent extends Component { }); hint.binder = binder; } - untetherFromElement(self, _, { element, hint }) { + untetherFromElement(self, _, { hint }) { hint.binder.destroy(); } } diff --git a/ui/app/controllers/application.js b/ui/app/controllers/application.js index a688f4e4b44b..be1756c0ee8b 100644 --- a/ui/app/controllers/application.js +++ b/ui/app/controllers/application.js @@ -9,6 +9,7 @@ import codesForError from '../utils/codes-for-error'; import NoLeaderError from '../utils/no-leader-error'; import OTTExchangeError from '../utils/ott-exchange-error'; import classic from 'ember-classic-decorator'; +// eslint-disable-next-line no-unused-vars import KeyboardService from '../services/keyboard'; @classic export default class ApplicationController extends Controller { @@ -21,6 +22,7 @@ export default class ApplicationController extends Controller { */ @service keyboard; + // eslint-disable-next-line ember/classic-decorator-hooks constructor() { super(...arguments); this.keyboard.listenForKeypress(); diff --git a/ui/app/helpers/keyboard-commands.js b/ui/app/helpers/keyboard-commands.js index f048ebb658b6..f03fd4b92e75 100644 --- a/ui/app/helpers/keyboard-commands.js +++ b/ui/app/helpers/keyboard-commands.js @@ -10,12 +10,10 @@ export default class keyboardCommands extends Helper { @service keyboard; constructor() { - console.log('kc const', ...arguments); super(...arguments); } compute([commands]) { - console.log('computing', commands); if (commands) { this.commands = commands; this.keyboard.addCommands(commands); diff --git a/ui/app/modifiers/keyboard-shortcut.js b/ui/app/modifiers/keyboard-shortcut.js index 3fb552ac42cc..1ddcaaa65359 100644 --- a/ui/app/modifiers/keyboard-shortcut.js +++ b/ui/app/modifiers/keyboard-shortcut.js @@ -1,46 +1,33 @@ import { inject as service } from '@ember/service'; import Modifier from 'ember-modifier'; import { registerDestructor } from '@ember/destroyable'; -import { assert } from '@ember/debug'; export default class KeyboardShortcutModifier extends Modifier { @service keyboard; + @service router; - /** - * For Dynamic/iterative keyboard shortcuts, our patterns look like "Shift+0" by default - * Do a couple things to make them more human-friendly: - * 1. Make them 1-based, instead of 0-based - * 2. Prefix numbers 1-9 with "0" to make it so "Shift+10" doesn't trigger "Shift+1" then "0", etc. - * ^--- stops being a good solution with 100+ row lists/tables, but a better UX than waiting for shift key-up otherwise - * - * @param {string[]} pattern - */ - cleanPattern(pattern) { - let patternNumber = pattern.length === 1 && pattern[0].match(/\d+/g); - if (!patternNumber) { - return pattern; - } else { - patternNumber = +patternNumber[0]; // regex'd string[0] to num - patternNumber = patternNumber + 1; // first item should be Shift+1, not Shift+0 - assert( - 'Dynamic keyboard shortcuts only work up to 99 digits', - patternNumber < 100 - ); - pattern = [`Shift+${('0' + patternNumber).slice(-2)}`]; // Shift+01, not Shift+1 + modify( + element, + _positional, + { + label, + pattern = '', + action = () => {}, + menuLevel = false, + enumerated = false, } - return pattern; - } - - modify(element, [eventName], { label, pattern, action, menuLevel = false }) { + ) { let commands = [ { label, action, - pattern: this.cleanPattern(pattern), + pattern, element, menuLevel, + enumerated, }, ]; + this.keyboard.addCommands(commands); registerDestructor(this, () => { this.keyboard.removeCommands(commands); diff --git a/ui/app/services/keyboard.js b/ui/app/services/keyboard.js index 822a60780cac..a35619bee5ce 100644 --- a/ui/app/services/keyboard.js +++ b/ui/app/services/keyboard.js @@ -1,13 +1,18 @@ +// @ts-check import Service from '@ember/service'; import { inject as service } from '@ember/service'; import { timeout, restartableTask } from 'ember-concurrency'; import { tracked } from '@glimmer/tracking'; import { compare } from '@ember/utils'; import { A } from '@ember/array'; +// eslint-disable-next-line no-unused-vars import EmberRouter from '@ember/routing/router'; import { schedule } from '@ember/runloop'; import { action } from '@ember/object'; import { guidFor } from '@ember/object/internals'; +import { assert } from '@ember/debug'; +// eslint-disable-next-line no-unused-vars +import MutableArray from '@ember/array/mutable'; const DEBOUNCE_MS = 750; @@ -37,7 +42,10 @@ export default class KeyboardService extends Service { @tracked buffer = A([]); @tracked displayHints = false; - keyCommands = [ + /** + * @type {MutableArray} + */ + keyCommands = A([ { label: 'Go to Jobs', pattern: ['g', 'j'], @@ -144,26 +152,45 @@ export default class KeyboardService extends Service { console.log('Extra Lives +30'); }, }, - ]; + ]); - addCommands(commands) { - // Filter out those commands that don't have a label (they're only being added for at-a-glance hinting/highlights) - this.keyCommands.pushObjects(commands); + /** + * For Dynamic/iterative keyboard shortcuts, we want to do a couple things to make them more human-friendly: + * 1. Make them 1-based, instead of 0-based + * 2. Prefix numbers 1-9 with "0" to make it so "Shift+10" doesn't trigger "Shift+1" then "0", etc. + * ^--- stops being a good solution with 100+ row lists/tables, but a better UX than waiting for shift key-up otherwise + * + * @param {number} iter + * @returns {string[]} + */ + cleanPattern(iter) { + iter = iter + 1; // first item should be Shift+1, not Shift+0 + assert('Dynamic keyboard shortcuts only work up to 99 digits', iter < 100); + return [`Shift+${('0' + iter).slice(-2)}`]; // Shift+01, not Shift+1 } - removeCommands(commands) { - this.keyCommands.removeObjects(commands); + recomputeEnumeratedCommands() { + this.keyCommands.filterBy('enumerated').forEach((command, iter) => { + command.pattern = this.cleanPattern(iter); + }); } - @action - generateIteratorShortcut(element, [action, iter]) { - this.keyCommands.pushObject({ - label: `Hit up item ${iter}`, - pattern: [`Shift+${iter}`], - action, + addCommands(commands) { + schedule('afterRender', () => { + commands.forEach((command) => { + this.keyCommands.pushObject(command); + if (command.enumerated) { + // Recompute enumerated numbers to handle things like sort + this.recomputeEnumeratedCommands(); + } + }); }); } + removeCommands(commands = A([])) { + this.keyCommands.removeObjects(commands); + } + //#region Nav Traversal subnavLinks = []; diff --git a/ui/app/templates/allocations/allocation/index.hbs b/ui/app/templates/allocations/allocation/index.hbs index 6519c3629aa4..7ebec44e7c54 100644 --- a/ui/app/templates/allocations/allocation/index.hbs +++ b/ui/app/templates/allocations/allocation/index.hbs @@ -184,6 +184,10 @@ # Volumes # Allocs - + diff --git a/ui/app/templates/components/job-page/parts/children.hbs b/ui/app/templates/components/job-page/parts/children.hbs index c9a1553885f6..9df07ebeab62 100644 --- a/ui/app/templates/components/job-page/parts/children.hbs +++ b/ui/app/templates/components/job-page/parts/children.hbs @@ -65,8 +65,8 @@ Summary - - + +
diff --git a/ui/app/templates/components/job-page/parts/recent-allocations.hbs b/ui/app/templates/components/job-page/parts/recent-allocations.hbs index b28080c9d855..c08679f816c5 100644 --- a/ui/app/templates/components/job-page/parts/recent-allocations.hbs +++ b/ui/app/templates/components/job-page/parts/recent-allocations.hbs @@ -52,6 +52,10 @@ @allocation={{row.model}} @context="job" @onClick={{action "gotoAllocation" row.model}} + {{keyboard-shortcut + enumerated=true + action=(action "gotoAllocation" row.model) + }} /> diff --git a/ui/app/templates/components/job-page/parts/task-groups.hbs b/ui/app/templates/components/job-page/parts/task-groups.hbs index 0e419f88132f..fdc4839844f8 100644 --- a/ui/app/templates/components/job-page/parts/task-groups.hbs +++ b/ui/app/templates/components/job-page/parts/task-groups.hbs @@ -36,6 +36,10 @@ @data-test-task-group={{row.model.name}} @taskGroup={{row.model}} @onClick={{fn this.gotoTaskGroup row.model}} + {{keyboard-shortcut + enumerated=true + action=(fn this.gotoTaskGroup row.model) + }} /> diff --git a/ui/app/templates/components/job-row.hbs b/ui/app/templates/components/job-row.hbs index 983a7efa22f3..f2212ebdf7eb 100644 --- a/ui/app/templates/components/job-row.hbs +++ b/ui/app/templates/components/job-row.hbs @@ -1,6 +1,6 @@ diff --git a/ui/app/templates/components/server-agent-row.hbs b/ui/app/templates/components/server-agent-row.hbs index 2d04d5f9f112..b4ed53fb60ab 100644 --- a/ui/app/templates/components/server-agent-row.hbs +++ b/ui/app/templates/components/server-agent-row.hbs @@ -1,6 +1,6 @@ {{this.agent.name}} diff --git a/ui/app/templates/csi/volumes/index.hbs b/ui/app/templates/csi/volumes/index.hbs index 462c1dde84af..e7ec14190489 100644 --- a/ui/app/templates/csi/volumes/index.hbs +++ b/ui/app/templates/csi/volumes/index.hbs @@ -67,7 +67,7 @@ # Allocs - + diff --git a/ui/app/templates/csi/volumes/volume.hbs b/ui/app/templates/csi/volumes/volume.hbs index a15171d0258a..e1432596ced0 100644 --- a/ui/app/templates/csi/volumes/volume.hbs +++ b/ui/app/templates/csi/volumes/volume.hbs @@ -52,6 +52,10 @@ - + diff --git a/ui/app/templates/jobs/index.hbs b/ui/app/templates/jobs/index.hbs index ded9f0e48763..e08aa1335e7c 100644 --- a/ui/app/templates/jobs/index.hbs +++ b/ui/app/templates/jobs/index.hbs @@ -147,8 +147,8 @@ Summary - - + +
diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs index 2dff6a224fdd..d7d63e9b7d50 100644 --- a/ui/app/templates/jobs/job/allocations.hbs +++ b/ui/app/templates/jobs/job/allocations.hbs @@ -62,6 +62,10 @@ Datacenter Version - - + +
diff --git a/ui/tests/integration/components/keyboard-hooks-test.js b/ui/tests/integration/components/keyboard-hooks-test.js deleted file mode 100644 index 542c0caf2251..000000000000 --- a/ui/tests/integration/components/keyboard-hooks-test.js +++ /dev/null @@ -1,26 +0,0 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -module('Integration | Component | keyboard-hooks', function (hooks) { - setupRenderingTest(hooks); - - test('it renders', async function (assert) { - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.set('myAction', function(val) { ... }); - - await render(hbs``); - - assert.dom(this.element).hasText(''); - - // Template block usage: - await render(hbs` - - template block text - - `); - - assert.dom(this.element).hasText('template block text'); - }); -}); diff --git a/ui/tests/integration/components/keyboard-shortcuts-modal-test.js b/ui/tests/integration/components/keyboard-shortcuts-modal-test.js index 9f904652e5dc..c6ad8d9cec67 100644 --- a/ui/tests/integration/components/keyboard-shortcuts-modal-test.js +++ b/ui/tests/integration/components/keyboard-shortcuts-modal-test.js @@ -2,25 +2,19 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { render } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; +import { componentA11yAudit } from 'nomad-ui/tests/helpers/a11y-audit'; module('Integration | Component | keyboard-shortcuts-modal', function (hooks) { setupRenderingTest(hooks); test('it renders', async function (assert) { + assert.expect(2); // Set any properties with this.set('myProperty', 'value'); // Handle any actions with this.set('myAction', function(val) { ... }); await render(hbs``); assert.dom(this.element).hasText(''); - - // Template block usage: - await render(hbs` - - template block text - - `); - - assert.dom(this.element).hasText('template block text'); + await componentA11yAudit(this.element, assert); }); });