From 96b0ae3b067200bd9d1f2dbd2dedf008226f1bc5 Mon Sep 17 00:00:00 2001 From: Zhihe Li Date: Mon, 1 Aug 2022 16:04:41 -0400 Subject: [PATCH] Icu 5245 add workers tab to navigation and initial overview (#1229) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 Add initial workers UI navigation page ✅ Closes: ICU-5245 --- addons/api/addon/abilities/worker.js | 15 +++++ addons/api/app/abilities/worker.js | 1 + addons/api/mirage/factories/scope.js | 11 +++- addons/api/mirage/factories/worker.js | 2 +- .../api/mirage/generated/factories/worker.js | 8 +-- addons/api/mirage/scenarios/default.js | 3 + addons/core/translations/resources/en-us.yaml | 11 +++- ui/admin/app/abilities/worker.js | 12 ++++ .../app/controllers/scopes/scope/workers.js | 18 +++++ .../controllers/scopes/scope/workers/new.js | 18 +++++ ui/admin/app/router.js | 3 + ui/admin/app/routes/scopes/scope/workers.js | 31 +++++++++ .../app/routes/scopes/scope/workers/index.js | 11 ++++ .../app/routes/scopes/scope/workers/new.js | 3 + ui/admin/app/templates/scopes/scope.hbs | 11 ++++ .../app/templates/scopes/scope/workers.hbs | 2 + .../templates/scopes/scope/workers/index.hbs | 66 +++++++++++++++++++ .../templates/scopes/scope/workers/new.hbs | 2 + ui/admin/config/environment.js | 2 + .../controllers/scopes/scope/workers-test.js | 11 ++++ .../scopes/scope/workers/new-test.js | 12 ++++ .../unit/routes/scopes/scope/workers-test.js | 11 ++++ .../routes/scopes/scope/workers/index-test.js | 11 ++++ .../routes/scopes/scope/workers/new-test.js | 11 ++++ 24 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 addons/api/addon/abilities/worker.js create mode 100644 addons/api/app/abilities/worker.js create mode 100644 ui/admin/app/abilities/worker.js create mode 100644 ui/admin/app/controllers/scopes/scope/workers.js create mode 100644 ui/admin/app/controllers/scopes/scope/workers/new.js create mode 100644 ui/admin/app/routes/scopes/scope/workers.js create mode 100644 ui/admin/app/routes/scopes/scope/workers/index.js create mode 100644 ui/admin/app/routes/scopes/scope/workers/new.js create mode 100644 ui/admin/app/templates/scopes/scope/workers.hbs create mode 100644 ui/admin/app/templates/scopes/scope/workers/index.hbs create mode 100644 ui/admin/app/templates/scopes/scope/workers/new.hbs create mode 100644 ui/admin/tests/unit/controllers/scopes/scope/workers-test.js create mode 100644 ui/admin/tests/unit/controllers/scopes/scope/workers/new-test.js create mode 100644 ui/admin/tests/unit/routes/scopes/scope/workers-test.js create mode 100644 ui/admin/tests/unit/routes/scopes/scope/workers/index-test.js create mode 100644 ui/admin/tests/unit/routes/scopes/scope/workers/new-test.js diff --git a/addons/api/addon/abilities/worker.js b/addons/api/addon/abilities/worker.js new file mode 100644 index 000000000..3640bb83a --- /dev/null +++ b/addons/api/addon/abilities/worker.js @@ -0,0 +1,15 @@ +import ModelAbility from './model'; + +/** + * Provides abilities for workers. + */ +export default class WorkerAbility extends ModelAbility { + // =permissions + + /** + * @type {boolean} + */ + get canCreateWorkerLed() { + return this.hasAuthorizedCollectionAction('create:worker-led'); + } +} diff --git a/addons/api/app/abilities/worker.js b/addons/api/app/abilities/worker.js new file mode 100644 index 000000000..0d55e96fe --- /dev/null +++ b/addons/api/app/abilities/worker.js @@ -0,0 +1 @@ +export { default } from 'api/abilities/worker'; diff --git a/addons/api/mirage/factories/scope.js b/addons/api/mirage/factories/scope.js index c70e6dbf1..62624f6dd 100644 --- a/addons/api/mirage/factories/scope.js +++ b/addons/api/mirage/factories/scope.js @@ -14,8 +14,8 @@ export default factory.extend({ 'delete', ], - authorized_collection_actions: () => { - return { + authorized_collection_actions() { + const collectionActions = { scopes: ['create', 'list'], users: ['create', 'list'], sessions: ['list'], @@ -26,6 +26,13 @@ export default factory.extend({ 'auth-methods': ['create', 'list'], 'host-catalogs': ['create', 'list'], }; + + // Worker permissions only available on the global scope + if (this.type === 'global') { + collectionActions.workers = ['create:worker-led', 'list']; + } + + return collectionActions; }, id: () => generateId('s_'), diff --git a/addons/api/mirage/factories/worker.js b/addons/api/mirage/factories/worker.js index 816ade736..6344dbcd6 100644 --- a/addons/api/mirage/factories/worker.js +++ b/addons/api/mirage/factories/worker.js @@ -1,4 +1,4 @@ -import factory from '../generated/factories/user'; +import factory from '../generated/factories/worker'; import permissions from '../helpers/permissions'; import generateId from '../helpers/id'; import { faker } from '@faker-js/faker'; diff --git a/addons/api/mirage/generated/factories/worker.js b/addons/api/mirage/generated/factories/worker.js index b022ae882..d2bb534eb 100644 --- a/addons/api/mirage/generated/factories/worker.js +++ b/addons/api/mirage/generated/factories/worker.js @@ -2,8 +2,8 @@ import { Factory } from 'ember-cli-mirage'; import { faker } from '@faker-js/faker'; /** - * GeneratedUserModelFactory - * User contains all fields related to a User resource + * GeneratedWorkerModelFactory + * User contains all fields related to a Worker resource */ export default Factory.extend({ name: () => faker.random.words(), @@ -11,7 +11,7 @@ export default Factory.extend({ created_time: () => faker.date.recent(), updated_time: () => faker.date.recent(), version: () => faker.datatype.number(), - address: () => `${faker.internet.ipv6()}${faker.internet.port()}`, + address: () => `${faker.internet.ipv4()}:${faker.internet.port()}`, last_status_time: () => faker.date.recent(), - active_connection_count: () => faker.datatype.number(), + active_connection_count: () => faker.datatype.number({ max: 10 }), }); diff --git a/addons/api/mirage/scenarios/default.js b/addons/api/mirage/scenarios/default.js index b956aad19..113dd3194 100644 --- a/addons/api/mirage/scenarios/default.js +++ b/addons/api/mirage/scenarios/default.js @@ -65,4 +65,7 @@ export default function (server) { server.createList('group', 3, { scope }); server.createList('role', 3, { scope }); }); + + // Workers + server.createList('worker', 3, { scope: globalScope }); } diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index ac4dbc6a6..4901c02bc 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -108,7 +108,7 @@ host-set: create-and-add-host: Create and Add Host add-hosts: Add Existing Host form: - filter: + filter: label: Filter help: Create a filter to select resources using values such as tag name or tag value. Filter format is specific to each provider preferred_endpoints: @@ -278,7 +278,7 @@ target: types: tcp: TCP ssh: SSH - help: + help: tcp: Connections are made over TCP to support a broad range of protocols, including SSH, RDP, databases, and more. This is the most general-purpose type. ssh: Protocol-aware connections are made over SSH. Use when requiring SSH connections to remote hosts. host-source: @@ -412,3 +412,10 @@ managed-group: messages: title: Welcome to Members description: No members in this managed group. +worker: + title: Worker + title_plural: Workers + description: Workers are the server components that perform the session handling. + messages: + welcome: + title: Welcome to Workers diff --git a/ui/admin/app/abilities/worker.js b/ui/admin/app/abilities/worker.js new file mode 100644 index 000000000..395427a39 --- /dev/null +++ b/ui/admin/app/abilities/worker.js @@ -0,0 +1,12 @@ +import WorkerAbility from 'api/abilities/worker'; + +export default class OverrideWorkerAbility extends WorkerAbility { + /** + * Navigating to workers is allowed if either list or create grants + * are present. + * @type {boolean} + */ + get canNavigate() { + return this.canList || this.canCreateWorkerLed; + } +} diff --git a/ui/admin/app/controllers/scopes/scope/workers.js b/ui/admin/app/controllers/scopes/scope/workers.js new file mode 100644 index 000000000..7b7912d71 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/workers.js @@ -0,0 +1,18 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeWorkersController extends Controller { + // =services + + @service intl; + + // =attributes + + /** + * Translated workers breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('resources.worker.title_plural'); + } +} diff --git a/ui/admin/app/controllers/scopes/scope/workers/new.js b/ui/admin/app/controllers/scopes/scope/workers/new.js new file mode 100644 index 000000000..1c6200e43 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/workers/new.js @@ -0,0 +1,18 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeWorkersNewController extends Controller { + // =services + + @service intl; + + // =attributes + + /** + * Translated new worker breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('titles.new'); + } +} diff --git a/ui/admin/app/router.js b/ui/admin/app/router.js index dd32f9c13..ec9218e47 100644 --- a/ui/admin/app/router.js +++ b/ui/admin/app/router.js @@ -125,6 +125,9 @@ Router.map(function () { ); this.route('new'); }); + this.route('workers', function () { + this.route('new'); + }); }); }); diff --git a/ui/admin/app/routes/scopes/scope/workers.js b/ui/admin/app/routes/scopes/scope/workers.js new file mode 100644 index 000000000..0c8b821a3 --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/workers.js @@ -0,0 +1,31 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeWorkersRoute extends Route { + // =services + + @service can; + @service session; + @service router; + + // =methods + + /** + * If arriving here unauthenticated, redirect to index for further processing. + */ + beforeModel() { + if (!this.session.isAuthenticated) this.router.transitionTo('index'); + } + + /** + * Load all workers. + * @return {WorkerModel} + */ + model() { + const scope = this.modelFor('scopes.scope'); + const { id: scope_id } = scope; + if (this.can.can('list worker', scope, { collection: 'workers' })) { + return this.store.query('worker', { scope_id }); + } + } +} diff --git a/ui/admin/app/routes/scopes/scope/workers/index.js b/ui/admin/app/routes/scopes/scope/workers/index.js new file mode 100644 index 000000000..856802b1c --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/workers/index.js @@ -0,0 +1,11 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeWorkersIndexRoute extends Route { + // =methods + + setupController(controller) { + const scope = this.modelFor('scopes.scope'); + super.setupController(...arguments); + controller.setProperties({ scope }); + } +} diff --git a/ui/admin/app/routes/scopes/scope/workers/new.js b/ui/admin/app/routes/scopes/scope/workers/new.js new file mode 100644 index 000000000..876ce8a77 --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/workers/new.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeWorkersNewRoute extends Route {} diff --git a/ui/admin/app/templates/scopes/scope.hbs b/ui/admin/app/templates/scopes/scope.hbs index 81267ca84..4dfc2e2f6 100644 --- a/ui/admin/app/templates/scopes/scope.hbs +++ b/ui/admin/app/templates/scopes/scope.hbs @@ -22,6 +22,17 @@ {{t 'resources.org.title_plural'}} + {{#if (can 'navigate worker' @model collection='workers')}} + + + + {{t 'resources.worker.title_plural'}} + + + {{/if}} {{/if}} {{#if @model.isOrg}} diff --git a/ui/admin/app/templates/scopes/scope/workers.hbs b/ui/admin/app/templates/scopes/scope/workers.hbs new file mode 100644 index 000000000..5c48246ae --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/workers.hbs @@ -0,0 +1,2 @@ +{{page-title (t 'resources.worker.title_plural')}} +{{outlet}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/workers/index.hbs b/ui/admin/app/templates/scopes/scope/workers/index.hbs new file mode 100644 index 000000000..8b3168d9a --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/workers/index.hbs @@ -0,0 +1,66 @@ + + + + + + + +

+ {{t 'resources.worker.title_plural'}} + +

+
+ + + {{#if (can 'create worker led worker' this.scope collection='workers')}} + {{#if @model}} + {{t + 'titles.new' + }} + {{/if}} + {{/if}} + + + + {{#if @model}} + {{! TODO: List view }} + {{else}} + + + + {{#if (can 'list worker' this.scope collection='workers')}} + {{! can list (at least): show default welcome message}} + {{t 'resources.worker.description'}} + {{else if (can + 'create worker led worker' this.scope collection='workers' + )}} + {{! can create (only): show create-but-not-list welcome message}} + {{t + 'descriptions.create-but-not-list' + resource=(t 'resources.worker.title_plural') + }} + {{else}} + {{! can neither list nor create }} + {{t + 'descriptions.neither-list-nor-create' + resource=(t 'resources.worker.title_plural') + }} + {{/if}} + + {{#if + (can 'create worker led worker' this.scope collection='workers') + }} + + + {{t 'titles.new'}} + + {{/if}} + + + {{/if}} + + +
\ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/workers/new.hbs b/ui/admin/app/templates/scopes/scope/workers/new.hbs new file mode 100644 index 000000000..1110d4e5f --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/workers/new.hbs @@ -0,0 +1,2 @@ +{{page-title (t 'titles.new')}} +{{outlet}} \ No newline at end of file diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js index bb4396415..a5e0842ae 100644 --- a/ui/admin/config/environment.js +++ b/ui/admin/config/environment.js @@ -97,6 +97,8 @@ module.exports = function (environment) { 'getting-started.desktop': '/getting-started/desktop', 'api-client.cli': '/api-client/cli', 'api-client.api': '/api-client/api', + worker: '/workers', + 'worker.new': '/workers/new', }, }, diff --git a/ui/admin/tests/unit/controllers/scopes/scope/workers-test.js b/ui/admin/tests/unit/controllers/scopes/scope/workers-test.js new file mode 100644 index 000000000..7ceb2e774 --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/workers-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | scopes/scope/workers', function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let controller = this.owner.lookup('controller:scopes/scope/workers'); + assert.ok(controller); + }); +}); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/workers/new-test.js b/ui/admin/tests/unit/controllers/scopes/scope/workers/new-test.js new file mode 100644 index 000000000..b2268b8fa --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/workers/new-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | scopes/scope/workers/new', function (hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function (assert) { + let controller = this.owner.lookup('controller:scopes/scope/workers/new'); + assert.ok(controller); + }); +}); diff --git a/ui/admin/tests/unit/routes/scopes/scope/workers-test.js b/ui/admin/tests/unit/routes/scopes/scope/workers-test.js new file mode 100644 index 000000000..c5b9c0e85 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/workers-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/workers', function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup('route:scopes/scope/workers'); + assert.ok(route); + }); +}); diff --git a/ui/admin/tests/unit/routes/scopes/scope/workers/index-test.js b/ui/admin/tests/unit/routes/scopes/scope/workers/index-test.js new file mode 100644 index 000000000..6d6a9d803 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/workers/index-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/workers/index', function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup('route:scopes/scope/workers/index'); + assert.ok(route); + }); +}); diff --git a/ui/admin/tests/unit/routes/scopes/scope/workers/new-test.js b/ui/admin/tests/unit/routes/scopes/scope/workers/new-test.js new file mode 100644 index 000000000..85cdd041f --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/workers/new-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope/workers/new', function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup('route:scopes/scope/workers/new'); + assert.ok(route); + }); +});