From f74f4d4a20267065bf85ea75a46330044c5d67f2 Mon Sep 17 00:00:00 2001 From: Dharini Jeeva Date: Thu, 11 Apr 2024 14:18:38 -0700 Subject: [PATCH] Target aliases list view (#2225) target aliases list view --- addons/api/addon/generated/models/target.js | 7 + addons/api/mirage/factories/target.js | 8 + addons/api/mirage/scenarios/default.js | 12 +- addons/core/translations/resources/en-us.yaml | 5 + .../components/form/target/details/index.hbs | 20 +- .../scopes/scope/targets/target/index.js | 60 +++ ui/admin/app/styles/app.scss | 18 + .../scopes/scope/targets/target/index.hbs | 79 +++- .../enable-session-recording/index-test.js | 395 +++++++++--------- .../tests/acceptance/targets/read-test.js | 45 +- 10 files changed, 431 insertions(+), 218 deletions(-) create mode 100644 ui/admin/app/controllers/scopes/scope/targets/target/index.js diff --git a/addons/api/addon/generated/models/target.js b/addons/api/addon/generated/models/target.js index 86605800c..e00e1c80c 100644 --- a/addons/api/addon/generated/models/target.js +++ b/addons/api/addon/generated/models/target.js @@ -114,4 +114,11 @@ export default class GeneratedTargetModel extends BaseModel { 'with_aliases specify the aliases that should be created when the target is created. ', }) with_aliases; + + @attr('array', { + readOnly: true, + description: + 'with_aliases specify the aliases that should be created when the target is created. ', + }) + aliases; } diff --git a/addons/api/mirage/factories/target.js b/addons/api/mirage/factories/target.js index 50707c1c4..2deb0b466 100644 --- a/addons/api/mirage/factories/target.js +++ b/addons/api/mirage/factories/target.js @@ -82,6 +82,14 @@ export default factory.extend({ }); } + const aliases = server.schema.aliases.all().models; + const randomlySelectedAliases = + aliases.length === 0 ? undefined : faker.helpers.arrayElement(aliases); + if (randomlySelectedAliases) { + target.update({ + aliases: randomlySelectedAliases.aliases, + }); + } target.update({ hostSets: randomlySelectedHostSets, brokeredCredentialSourceIds: [ diff --git a/addons/api/mirage/scenarios/default.js b/addons/api/mirage/scenarios/default.js index 042a20851..4053bca6b 100644 --- a/addons/api/mirage/scenarios/default.js +++ b/addons/api/mirage/scenarios/default.js @@ -125,8 +125,16 @@ export default function (server) { }); // Aliases - const destination_id = server.schema.targets.all().models[0].id; - server.createList('alias', 3, { scope: globalScope, destination_id }); + const aliasDestinationTarget = server.schema.targets.all().models[0]; + const { id: destination_id } = aliasDestinationTarget; + const aliases = server.createList('alias', 4, { + scope: globalScope, + destination_id, + }); + + aliasDestinationTarget.update({ + aliases: aliases.map((alias) => ({ id: alias.id, value: alias.value })), + }); // 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 a897f54e5..14747bbe5 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -576,6 +576,7 @@ target: new: New Target active-sessions: Active sessions sessions-flyout: Active sessions for {targetDisplayName} + aliases-flyout: Aliases for {targetDisplayName} actions: create: New Target delete: Delete Target @@ -586,6 +587,8 @@ target: enable-session-recording: Enable Session Recording enable-recording: Enable recording view-more-sessions: View more sessions + add-an-alias: Add an alias + view-more-aliases: View more aliases types: tcp: Generic TCP ssh: SSH @@ -1027,6 +1030,8 @@ alias: authorize_session_arguments: label: Host ID help: Always use this host when connecting using this alias + sidebar: + help: Use a domain name as a shortcut for anyone with access to this target. alias: label: Aliases help: You can create aliases for this target that will make it easier to reach. Users must have access to this project to use aliases. diff --git a/ui/admin/app/components/form/target/details/index.hbs b/ui/admin/app/components/form/target/details/index.hbs index 29f0d99b3..3f7dba989 100644 --- a/ui/admin/app/components/form/target/details/index.hbs +++ b/ui/admin/app/components/form/target/details/index.hbs @@ -238,16 +238,17 @@ {{t 'resources.target.form.worker_filter.help'}} + + {{#if form.isEditable}} + + {{/if}} - {{#if form.isEditable}} - - {{/if}} {{else}} @@ -328,7 +329,6 @@ {{#if (and @model.isNew (can 'create model' @globalScope collection='aliases')) }} - 3; + } + + /** + * Returns only the first three items in the aliases array if there are more than 3 + * @returns {array} + */ + get aliases() { + if (this.model.aliases.length > 3) { + const arrWithThreeItems = this.model.aliases.slice(0, 3); + return arrWithThreeItems; + } else { + return this.model.aliases; + } + } + + /** + * Returns remaining items in the aliases array if there are more than 3 + * @returns {array} + */ + get remainingAliases() { + return this.model.aliases.slice(3); + } +} diff --git a/ui/admin/app/styles/app.scss b/ui/admin/app/styles/app.scss index 8e4f354f3..6908e71ff 100644 --- a/ui/admin/app/styles/app.scss +++ b/ui/admin/app/styles/app.scss @@ -623,6 +623,24 @@ } } +.target-sidebar-aliases { + margin-bottom: 3rem; + + .description { + color: var(--token-form-helper-text-color); + font-weight: var(--token-typography-font-weight-normal); + font-size: var(--token-typography-body-200-font-size); + } + + .hds-link-standalone { + margin-top: 1rem; + } + + .link-list-item { + margin-bottom: 0.5rem; + } +} + .link-list-item { display: flex; align-items: center; diff --git a/ui/admin/app/templates/scopes/scope/targets/target/index.hbs b/ui/admin/app/templates/scopes/scope/targets/target/index.hbs index 9bb29e01f..d3c8a17aa 100644 --- a/ui/admin/app/templates/scopes/scope/targets/target/index.hbs +++ b/ui/admin/app/templates/scopes/scope/targets/target/index.hbs @@ -30,9 +30,74 @@ @cancel={{route-action 'cancel' @model}} /> - {{#if (and @model.isSSH (feature-flag 'ssh-session-recording'))}} - -
+ + +
+

{{t 'resources.alias.title_plural'}}

+

+ {{t 'resources.alias.form.sidebar.help'}} +

+ {{#if @model.aliases}} + + {{#each this.aliases as |alias|}} + + + + {{/each}} + + {{#if this.showFlyoutBtn}} + + {{/if}} + {{#if this.showFlyout}} + + + {{t + 'resources.target.titles.aliases-flyout' + targetDisplayName=@model.displayName + }} + + + + {{#each this.remainingAliases as |alias|}} + + + + {{/each}} + + + {{/if}} + {{else}} + + {{/if}} +
+
+ {{#if (and @model.isSSH (feature-flag 'ssh-session-recording'))}}

{{t 'resources.target.form.sidebar.label'}}

{{t 'resources.target.form.sidebar.help'}} @@ -65,11 +130,9 @@ @route='scopes.scope.targets.target.enable-session-recording' /> {{/if}} -

-
- {{/if}} + {{/if}} +
+
- - \ No newline at end of file diff --git a/ui/admin/tests/acceptance/targets/enable-session-recording/index-test.js b/ui/admin/tests/acceptance/targets/enable-session-recording/index-test.js index bc21c8d87..97cd63dde 100644 --- a/ui/admin/tests/acceptance/targets/enable-session-recording/index-test.js +++ b/ui/admin/tests/acceptance/targets/enable-session-recording/index-test.js @@ -12,215 +12,218 @@ import { authenticateSession } from 'ember-simple-auth/test-support'; import { TYPE_TARGET_SSH } from 'api/models/target'; import select from '@ember/test-helpers/dom/select'; -module('Acceptance | targets | enable session recording', function (hooks) { - setupApplicationTest(hooks); - setupMirage(hooks); +module( + 'Acceptance | targets | enable session recording | index', + function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); - let featuresService; - let storageBucketOne; - let storageBucketTwo; + let featuresService; + let storageBucketOne; + let storageBucketTwo; - const SETTINGS_LINK_SELECTOR = '.target-sidebar .hds-link-standalone'; - const ENABLE_BUTTON_SELECTOR = '.target-sidebar .hds-button'; - const DROPDOWN_SELECTOR = '[name=storage_bucket_id]'; - const LINK_LIST_SELECTOR = '.link-list-item > a'; - const LINK_LIST_SELECTOR_ITEM_TEXT = '.link-list-item__text'; - const TOGGLE_SELECTOR = '[name=target-enable-session-recording]'; - const LINK_TO_NEW_STORAGE_BUCKET = - '.enable-session-recording-toggle .hds-link-standalone'; - const SAVE_BTN_SELECTOR = '.rose-form-actions [type="submit"]'; - const CANCEL_BTN_SELECTOR = '.rose-form-actions [type="button"]'; + const SETTINGS_LINK_SELECTOR = '.target-sidebar .hds-link-standalone'; + const ENABLE_BUTTON_SELECTOR = '.target-sidebar .hds-button'; + const DROPDOWN_SELECTOR = '[name=storage_bucket_id]'; + const LINK_LIST_SELECTOR = '.link-list-item > a'; + const LINK_LIST_SELECTOR_ITEM_TEXT = '.link-list-item__text'; + const TOGGLE_SELECTOR = '[name=target-enable-session-recording]'; + const LINK_TO_NEW_STORAGE_BUCKET = + '.enable-session-recording-toggle .hds-link-standalone'; + const SAVE_BTN_SELECTOR = '.rose-form-actions [type="submit"]'; + const CANCEL_BTN_SELECTOR = '.rose-form-actions [type="button"]'; - // Instances - const instances = { - scopes: { - global: null, - org: null, - }, - sessionRecording: null, - }; + // Instances + const instances = { + scopes: { + global: null, + org: null, + }, + sessionRecording: null, + }; - //URLs - const urls = { - globalScope: null, - orgScope: null, - projectScope: null, - targets: null, - target: null, - enableSessionRecording: null, - storageBuckets: null, - storageBucket: null, - newStorageBucket: null, - }; + //URLs + const urls = { + globalScope: null, + orgScope: null, + projectScope: null, + targets: null, + target: null, + enableSessionRecording: null, + storageBuckets: null, + storageBucket: null, + newStorageBucket: null, + }; - hooks.beforeEach(function () { - featuresService = this.owner.lookup('service:features'); - // Generate resources - instances.scopes.global = this.server.create('scope', { id: 'global' }); - instances.scopes.org = this.server.create('scope', { - type: 'org', - scope: { id: 'global', type: 'global' }, - }); - instances.scopes.project = this.server.create('scope', { - type: 'project', - scope: { id: instances.scopes.org.id, type: 'org' }, + hooks.beforeEach(function () { + featuresService = this.owner.lookup('service:features'); + // Generate resources + instances.scopes.global = this.server.create('scope', { id: 'global' }); + instances.scopes.org = this.server.create('scope', { + type: 'org', + scope: { id: 'global', type: 'global' }, + }); + instances.scopes.project = this.server.create('scope', { + type: 'project', + scope: { id: instances.scopes.org.id, type: 'org' }, + }); + + instances.target = this.server.create('target', { + scope: instances.scopes.project, + type: TYPE_TARGET_SSH, + }); + + instances.storageBucket = this.server.createList('storage-bucket', 2, { + scope: instances.scopes.global, + }); + + storageBucketOne = instances.storageBucket[0]; + storageBucketTwo = instances.storageBucket[1]; + + // Generate route URLs for resources + urls.globalScope = `/scopes/global`; + urls.orgScope = `/scopes/${instances.scopes.org.id}/scopes`; + urls.projectScope = `/scopes/${instances.scopes.project.id}`; + urls.targets = `${urls.projectScope}/targets`; + urls.target = `${urls.targets}/${instances.target.id}`; + urls.enableSessionRecording = `${urls.target}/enable-session-recording`; + urls.storageBuckets = `${urls.globalScope}/storage-buckets`; + urls.newStorageBucket = `${urls.enableSessionRecording}/create-storage-bucket`; + urls.storageBucket = `${urls.storageBuckets}/${storageBucketOne.id}`; + + authenticateSession({}); }); - instances.target = this.server.create('target', { - scope: instances.scopes.project, - type: TYPE_TARGET_SSH, + test('cannot enable session recording for a target without proper authorization', async function (assert) { + assert.false(featuresService.isEnabled('ssh-session-recording')); + await visit(urls.target); + await a11yAudit(); + assert.dom('.target-sidebar a').doesNotExist(); }); - instances.storageBucket = this.server.createList('storage-bucket', 2, { - scope: instances.scopes.global, + test('users can click on enable-recording button in target session-recording sidebar and it takes them to enable session recording', async function (assert) { + featuresService.enable('ssh-session-recording'); + await visit(urls.target); + assert.dom(SETTINGS_LINK_SELECTOR).doesNotExist(); + await click(ENABLE_BUTTON_SELECTOR); + assert.strictEqual(currentURL(), urls.enableSessionRecording); }); - storageBucketOne = instances.storageBucket[0]; - storageBucketTwo = instances.storageBucket[1]; - - // Generate route URLs for resources - urls.globalScope = `/scopes/global`; - urls.orgScope = `/scopes/${instances.scopes.org.id}/scopes`; - urls.projectScope = `/scopes/${instances.scopes.project.id}`; - urls.targets = `${urls.projectScope}/targets`; - urls.target = `${urls.targets}/${instances.target.id}`; - urls.enableSessionRecording = `${urls.target}/enable-session-recording`; - urls.storageBuckets = `${urls.globalScope}/storage-buckets`; - urls.newStorageBucket = `${urls.enableSessionRecording}/create-storage-bucket`; - urls.storageBucket = `${urls.storageBuckets}/${storageBucketOne.id}`; - - authenticateSession({}); - }); - - test('cannot enable session recording for a target without proper authorization', async function (assert) { - assert.false(featuresService.isEnabled('ssh-session-recording')); - await visit(urls.target); - await a11yAudit(); - assert.dom('.target-sidebar a').doesNotExist(); - }); - - test('users can click on enable-recording button in target session-recording sidebar and it takes them to enable session recording', async function (assert) { - featuresService.enable('ssh-session-recording'); - await visit(urls.target); - assert.dom(SETTINGS_LINK_SELECTOR).doesNotExist(); - await click(ENABLE_BUTTON_SELECTOR); - assert.strictEqual(currentURL(), urls.enableSessionRecording); - }); - - test('users can click on settings link in target session-recording sidebar and it takes them to enable session recording', async function (assert) { - featuresService.enable('ssh-session-recording'); - instances.target.update({ - storageBucketId: storageBucketOne.id, - enableSessionRecording: true, - }); - await visit(urls.target); - await click(SETTINGS_LINK_SELECTOR); - assert.strictEqual(currentURL(), urls.enableSessionRecording); - }); - - test('users can click on associated storage bucket card on an ssh target', async function (assert) { - featuresService.enable('ssh-session-recording'); - instances.target.update({ - storageBucketId: storageBucketOne.id, - enableSessionRecording: true, - }); - await visit(urls.target); - await click(LINK_LIST_SELECTOR); - assert.strictEqual(currentURL(), urls.storageBucket); - }); - - test('toggle should be disabled and storage buckets list should be shown when enable session recording button is clicked', async function (assert) { - featuresService.enable('ssh-session-recording'); - await visit(urls.target); - await click(ENABLE_BUTTON_SELECTOR); - assert.strictEqual(currentURL(), urls.enableSessionRecording); - assert.dom(TOGGLE_SELECTOR).isVisible(); - assert.dom(DROPDOWN_SELECTOR).isNotVisible(); - }); - - test('storage buckets list is hidden when toggle is disabled', async function (assert) { - featuresService.enable('ssh-session-recording'); - await visit(urls.target); - await click(ENABLE_BUTTON_SELECTOR); - assert.strictEqual(currentURL(), urls.enableSessionRecording); - assert.dom(TOGGLE_SELECTOR).isVisible(); - assert.dom(DROPDOWN_SELECTOR).isNotVisible(); - await click(TOGGLE_SELECTOR); - assert.dom(DROPDOWN_SELECTOR).isVisible(); - }); - - test('link to add new storage bucket should be displayed and redirect to new storage buckets form', async function (assert) { - featuresService.enable('ssh-session-recording'); - await visit(urls.target); - await click(ENABLE_BUTTON_SELECTOR); - assert.strictEqual(currentURL(), urls.enableSessionRecording); - assert.dom(LINK_TO_NEW_STORAGE_BUCKET).isVisible(); - await click(LINK_TO_NEW_STORAGE_BUCKET); - assert.strictEqual(currentURL(), urls.newStorageBucket); - }); - - test('retain last selected dropdown list value when the toggle is off', async function (assert) { - featuresService.enable('ssh-session-recording'); - instances.target.update({ - storageBucketId: storageBucketOne.id, - enable_session_recording: true, - }); - await visit(urls.target); - await click(SETTINGS_LINK_SELECTOR); - assert.strictEqual(currentURL(), urls.enableSessionRecording); - - const existingStorageBucketId = find(DROPDOWN_SELECTOR).value; - - //disable the toggle, dropdown should be hidden - await click(TOGGLE_SELECTOR); - assert.dom(DROPDOWN_SELECTOR).isNotVisible(); - - //enable the toggle now, - //it should have the previously selected storage_bucket_id - await click(TOGGLE_SELECTOR); - assert.dom(DROPDOWN_SELECTOR).hasValue(existingStorageBucketId); - }); - - test('can assign a storage bucket for the target', async function (assert) { - featuresService.enable('ssh-session-recording'); - await visit(urls.target); - await click(ENABLE_BUTTON_SELECTOR); - - assert.strictEqual(currentURL(), urls.enableSessionRecording); - await click(TOGGLE_SELECTOR); - assert.dom(DROPDOWN_SELECTOR).hasNoValue(); - await select(DROPDOWN_SELECTOR, storageBucketTwo.id); - assert.dom(DROPDOWN_SELECTOR).hasValue(); - await click(SAVE_BTN_SELECTOR); - - assert.strictEqual(currentURL(), urls.target); - - assert.strictEqual( - find(LINK_LIST_SELECTOR_ITEM_TEXT).textContent.trim(), - storageBucketTwo.name, - ); - }); - - test('can cancel changes to an existing storage bucket selection', async function (assert) { - featuresService.enable('ssh-session-recording'); - instances.target.update({ - storageBucketId: storageBucketOne.id, - enable_session_recording: true, + test('users can click on settings link in target session-recording sidebar and it takes them to enable session recording', async function (assert) { + featuresService.enable('ssh-session-recording'); + instances.target.update({ + storageBucketId: storageBucketOne.id, + enableSessionRecording: true, + }); + await visit(urls.target); + await click(SETTINGS_LINK_SELECTOR); + assert.strictEqual(currentURL(), urls.enableSessionRecording); }); - await visit(urls.target); - await click(SETTINGS_LINK_SELECTOR); - assert.strictEqual(currentURL(), urls.enableSessionRecording); + test('users can click on associated storage bucket card on an ssh target', async function (assert) { + featuresService.enable('ssh-session-recording'); + instances.target.update({ + storageBucketId: storageBucketOne.id, + enableSessionRecording: true, + }); + await visit(urls.target); + await click(LINK_LIST_SELECTOR); + assert.strictEqual(currentURL(), urls.storageBucket); + }); - //update the storage bucket selection - await select(DROPDOWN_SELECTOR, storageBucketTwo); + test('toggle should be disabled and storage buckets list should be shown when enable session recording button is clicked', async function (assert) { + featuresService.enable('ssh-session-recording'); + await visit(urls.target); + await click(ENABLE_BUTTON_SELECTOR); + assert.strictEqual(currentURL(), urls.enableSessionRecording); + assert.dom(TOGGLE_SELECTOR).isVisible(); + assert.dom(DROPDOWN_SELECTOR).isNotVisible(); + }); - await click(CANCEL_BTN_SELECTOR); - assert.strictEqual(currentURL(), urls.target); + test('storage buckets list is hidden when toggle is disabled', async function (assert) { + featuresService.enable('ssh-session-recording'); + await visit(urls.target); + await click(ENABLE_BUTTON_SELECTOR); + assert.strictEqual(currentURL(), urls.enableSessionRecording); + assert.dom(TOGGLE_SELECTOR).isVisible(); + assert.dom(DROPDOWN_SELECTOR).isNotVisible(); + await click(TOGGLE_SELECTOR); + assert.dom(DROPDOWN_SELECTOR).isVisible(); + }); - assert.strictEqual( - find(LINK_LIST_SELECTOR_ITEM_TEXT).textContent.trim(), - storageBucketOne.name, - ); - }); -}); + test('link to add new storage bucket should be displayed and redirect to new storage buckets form', async function (assert) { + featuresService.enable('ssh-session-recording'); + await visit(urls.target); + await click(ENABLE_BUTTON_SELECTOR); + assert.strictEqual(currentURL(), urls.enableSessionRecording); + assert.dom(LINK_TO_NEW_STORAGE_BUCKET).isVisible(); + await click(LINK_TO_NEW_STORAGE_BUCKET); + assert.strictEqual(currentURL(), urls.newStorageBucket); + }); + + test('retain last selected dropdown list value when the toggle is off', async function (assert) { + featuresService.enable('ssh-session-recording'); + instances.target.update({ + storageBucketId: storageBucketOne.id, + enable_session_recording: true, + }); + await visit(urls.target); + await click(SETTINGS_LINK_SELECTOR); + assert.strictEqual(currentURL(), urls.enableSessionRecording); + + const existingStorageBucketId = find(DROPDOWN_SELECTOR).value; + + //disable the toggle, dropdown should be hidden + await click(TOGGLE_SELECTOR); + assert.dom(DROPDOWN_SELECTOR).isNotVisible(); + + //enable the toggle now, + //it should have the previously selected storage_bucket_id + await click(TOGGLE_SELECTOR); + assert.dom(DROPDOWN_SELECTOR).hasValue(existingStorageBucketId); + }); + + test('can assign a storage bucket for the target', async function (assert) { + featuresService.enable('ssh-session-recording'); + await visit(urls.target); + await click(ENABLE_BUTTON_SELECTOR); + + assert.strictEqual(currentURL(), urls.enableSessionRecording); + await click(TOGGLE_SELECTOR); + assert.dom(DROPDOWN_SELECTOR).hasNoValue(); + await select(DROPDOWN_SELECTOR, storageBucketTwo.id); + assert.dom(DROPDOWN_SELECTOR).hasValue(); + await click(SAVE_BTN_SELECTOR); + + assert.strictEqual(currentURL(), urls.target); + + assert.strictEqual( + find(LINK_LIST_SELECTOR_ITEM_TEXT).textContent.trim(), + storageBucketTwo.name, + ); + }); + + test('can cancel changes to an existing storage bucket selection', async function (assert) { + featuresService.enable('ssh-session-recording'); + instances.target.update({ + storageBucketId: storageBucketOne.id, + enable_session_recording: true, + }); + + await visit(urls.target); + await click(SETTINGS_LINK_SELECTOR); + assert.strictEqual(currentURL(), urls.enableSessionRecording); + + //update the storage bucket selection + await select(DROPDOWN_SELECTOR, storageBucketTwo); + + await click(CANCEL_BTN_SELECTOR); + assert.strictEqual(currentURL(), urls.target); + + assert.strictEqual( + find(LINK_LIST_SELECTOR_ITEM_TEXT).textContent.trim(), + storageBucketOne.name, + ); + }); + }, +); diff --git a/ui/admin/tests/acceptance/targets/read-test.js b/ui/admin/tests/acceptance/targets/read-test.js index 4931c91ad..09e012516 100644 --- a/ui/admin/tests/acceptance/targets/read-test.js +++ b/ui/admin/tests/acceptance/targets/read-test.js @@ -4,7 +4,7 @@ */ import { module, test } from 'qunit'; -import { visit, currentURL, click } from '@ember/test-helpers'; +import { visit, currentURL, click, find } 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'; @@ -21,7 +21,11 @@ module('Acceptance | targets | read', function (hooks) { setupMirage(hooks); let featuresService; - + const ALIASES_SIDEBAR = '.target-sidebar-aliases'; + const ALIASES_SIDEBAR_LIST = '.target-sidebar-aliases .link-list-item'; + const LINK_TO_NEW_ALIAS = '.target-sidebar-aliases button'; + const VIEW_MORE_BTN = '[data-test-view-more]'; + const FLYOUT_COMPONENT = '[data-test-flyout]'; const instances = { scopes: { global: null, @@ -189,4 +193,41 @@ module('Acceptance | targets | read', function (hooks) { assert.notEqual(currentURL(), incorrectUrl); assert.strictEqual(currentURL(), urls.sshTarget); }); + + test('can view aliases on the right sidebar', async function (assert) { + instances.tcpTarget.update({ + aliases: [{ id: 'alt_123', value: 'alias 1' }], + }); + await visit(urls.tcpTarget); + assert.dom(ALIASES_SIDEBAR).exists(); + assert.dom(ALIASES_SIDEBAR_LIST).exists(); + assert.strictEqual( + find(ALIASES_SIDEBAR_LIST).textContent.trim(), + 'alias 1', + ); + }); + + test('cannot view aliases list on the right sidebar if there is no alias associated with the target', async function (assert) { + await visit(urls.tcpTarget); + assert.dom(ALIASES_SIDEBAR).exists(); + assert.dom(LINK_TO_NEW_ALIAS).hasText('Add an alias'); + assert.dom(ALIASES_SIDEBAR_LIST).doesNotExist(); + }); + + test('can click `view more aliases` to see the remaining associated aliases if there are more than 3', async function (assert) { + instances.tcpTarget.update({ + aliases: [ + { id: 'alt_123', value: 'alias 1' }, + { id: 'alt_125', value: 'alias 5' }, + { id: 'alt_122', value: 'alias 2' }, + { id: 'alt_124', value: 'alias 4' }, + ], + }); + await visit(urls.tcpTarget); + + assert.dom(ALIASES_SIDEBAR).exists(); + assert.dom(VIEW_MORE_BTN).exists(); + await click(VIEW_MORE_BTN); + assert.dom(FLYOUT_COMPONENT).exists(); + }); });