From 3740bb079a28c26af1f88353850db597519fa89a Mon Sep 17 00:00:00 2001 From: Lisbet Alvarez <107949262+lisbet-alvarez@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:52:14 -0700 Subject: [PATCH] Icu-11111 don't display empty modal when a target has no target address and no host sources (#1909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 disable connect buttons & add message ✅ Closes: ICU-11111 * test: 💍 add test cases * fix: 🐛 buttons on list view & add getter to target model * refactor: 💡 use can ability instead and remove Promise.all * test: 💍 fix expect number --- addons/core/translations/resources/en-us.yaml | 3 + ui/desktop/app/abilities/target.js | 16 +++++ .../scopes/scope/projects/targets/target.hbs | 61 ++++++++++++------- ui/desktop/tests/acceptance/targets-test.js | 35 ++++++++++- .../tests/unit/abilities/target-test.js | 30 +++++++++ 5 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 ui/desktop/app/abilities/target.js create mode 100644 ui/desktop/tests/unit/abilities/target-test.js diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index f12baf9a3..c0f94b306 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -551,6 +551,9 @@ target: connect-more-info: title: Connect for more info description: Additional information for this target will be provided here after your session is established. + cannot-connect: + title: Cannot connect to {targetDisplayName} + description: No host sources and no target address found. Please update target with address information to connect directly. Otherwise, add at least one host to connect using host sources. titles: new: New Target actions: diff --git a/ui/desktop/app/abilities/target.js b/ui/desktop/app/abilities/target.js new file mode 100644 index 000000000..40c420212 --- /dev/null +++ b/ui/desktop/app/abilities/target.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import TargetAbility from 'api/abilities/target'; + +export default class OverrideTargetAbility extends TargetAbility { + /** + * + * @type {boolean} + */ + get canInitiateConnection() { + return this.model.address || this.model.host_sources?.length; + } +} diff --git a/ui/desktop/app/templates/scopes/scope/projects/targets/target.hbs b/ui/desktop/app/templates/scopes/scope/projects/targets/target.hbs index 441cfced8..94bcd80bb 100644 --- a/ui/desktop/app/templates/scopes/scope/projects/targets/target.hbs +++ b/ui/desktop/app/templates/scopes/scope/projects/targets/target.hbs @@ -15,34 +15,51 @@ - + {{#if (can 'connect target' @model.target)}} + + {{/if}} - + {{#if (can 'initiateConnection target' @model.target)}} + + {{/if}} - - + {{#if (can 'initiateConnection target' @model.target)}} + + + {{else}} + + + {{/if}} diff --git a/ui/desktop/tests/acceptance/targets-test.js b/ui/desktop/tests/acceptance/targets-test.js index 2ea8a5678..3cca4e681 100644 --- a/ui/desktop/tests/acceptance/targets-test.js +++ b/ui/desktop/tests/acceptance/targets-test.js @@ -4,7 +4,7 @@ */ import { module, test } from 'qunit'; -import { visit, currentURL } from '@ember/test-helpers'; +import { visit, click, currentURL } from '@ember/test-helpers'; import { setupApplicationTest } from 'ember-qunit'; import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; import a11yAudit from 'ember-a11y-testing/test-support/audit'; @@ -19,6 +19,9 @@ module('Acceptance | targets', function (hooks) { setupApplicationTest(hooks); setupMirage(hooks); + const TARGET_CONNECT_BUTTON = '[data-test-target-detail-connect-button]'; + const APP_STATE_TITLE = '.hds-application-state__title'; + const instances = { scopes: { global: null, @@ -29,6 +32,7 @@ module('Acceptance | targets', function (hooks) { global: null, }, target: null, + emptyTarget: null, }; const stubs = { @@ -49,6 +53,8 @@ module('Acceptance | targets', function (hooks) { }, projects: null, targets: null, + target: null, + emptyTarget: null, }; const setDefaultClusterUrl = (test) => { @@ -85,9 +91,12 @@ module('Acceptance | targets', function (hooks) { ); instances.target = this.server.create( 'target', - { scope: instances.scopes.project }, + { scope: instances.scopes.project, address: '127.0.0.1' }, 'withAssociations' ); + instances.emptyTarget = this.server.create('target', { + scope: instances.scopes.project, + }); urls.scopes.global = `/scopes/${instances.scopes.global.id}`; urls.scopes.org = `/scopes/${instances.scopes.org.id}`; @@ -95,6 +104,8 @@ module('Acceptance | targets', function (hooks) { urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`; urls.projects = `${urls.scopes.org}/projects`; urls.targets = `${urls.projects}/targets`; + urls.target = `${urls.targets}/${instances.target.id}`; + urls.emptyTarget = `${urls.targets}/${instances.emptyTarget.id}`; // Mock the postMessage interface used by IPC. this.owner.register('service:browser/window', WindowMockIPC); @@ -115,4 +126,24 @@ module('Acceptance | targets', function (hooks) { await visit(urls.targets); assert.strictEqual(currentURL(), urls.targets); }); + + test('cannot connect to a target without an address and no host sources', async function (assert) { + assert.expect(2); + await visit(urls.targets); + + await click(`[href="${urls.emptyTarget}"]`); + + assert.dom(TARGET_CONNECT_BUTTON).isDisabled(); + assert.dom(APP_STATE_TITLE).includesText('Cannot connect'); + }); + + test('can connect to a target with an address', async function (assert) { + assert.expect(2); + await visit(urls.targets); + + await click(`[href="${urls.target}"]`); + + assert.dom(TARGET_CONNECT_BUTTON).isEnabled(); + assert.dom(APP_STATE_TITLE).includesText('Connect for more info'); + }); }); diff --git a/ui/desktop/tests/unit/abilities/target-test.js b/ui/desktop/tests/unit/abilities/target-test.js new file mode 100644 index 000000000..2299590ab --- /dev/null +++ b/ui/desktop/tests/unit/abilities/target-test.js @@ -0,0 +1,30 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Abilities | target', function (hooks) { + setupTest(hooks); + + test('it reflects when a target can initiate connection or not', function (assert) { + assert.expect(5); + const service = this.owner.lookup('service:can'); + const model = { + address: '', + }; + assert.false(service.can('initiateConnection target', model)); + model.host_sources = []; + assert.false(service.can('initiateConnection target', model)); + model.address = 'localhost'; + assert.true(service.can('initiateConnection target', model)); + model.address = ''; + model.host_sources = ['host_123']; + assert.true(service.can('initiateConnection target', model)); + model.address = 'localhost'; + model.host_sources = ['host_123']; + assert.true(service.can('initiateConnection target', model)); + }); +});