refactor: 💡 move workers section in a target to be in a tab (#2379)

* refactor: 💡 move workers section in a target to be in a tab

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14332
This commit is contained in:
Lisbet Alvarez authored and cameronperera committed 2024-07-16 15:49:23 -05:00
1 parent 825c9556b6
commit 723101b779
34 files changed
+879 -713

No files matched your search

@@ -38,12 +38,6 @@ export default class GeneratedTargetModel extends BaseModel {
})
session_connection_limit;
@attr('string', {
description:
'Optional boolean expression to filter the workers that are allowed to satisfy this request.',
})
worker_filter;
@attr('string', {
description:
'Optional boolean expressions to filter the egress workers that are allowed to satisfy this request.',
-1
View File
@@ -36,7 +36,6 @@ export default factory.extend({
*/
session_connection_limit: () =>
faker.helpers.arrayElement([-1, faker.number.int()]),
worker_filter: (i) => (i % 2 === 0 ? randomFilter() : null),
egress_worker_filter: (i) => (i % 2 !== 0 ? randomFilter() : null),
ingress_worker_filter: (i) => (i % 2 !== 0 ? randomFilter() : null),
type: (i) => types[i % types.length],
@@ -49,7 +49,6 @@ module('Unit | Serializer | target', function (hooks) {
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: null,
worker_filter: null,
egress_worker_filter: null,
ingress_worker_filter: null,
with_aliases: [{ value: 'a', scope_id: 'global' }],
@@ -100,7 +99,6 @@ module('Unit | Serializer | target', function (hooks) {
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: null,
worker_filter: null,
egress_worker_filter: null,
ingress_worker_filter: null,
with_aliases: [{ value: 'www.test.com', scope_id: 'global' }],
@@ -208,7 +206,6 @@ module('Unit | Serializer | target', function (hooks) {
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: null,
worker_filter: null,
egress_worker_filter: null,
ingress_worker_filter: null,
with_aliases: [],
@@ -222,45 +219,6 @@ module('Unit | Serializer | target', function (hooks) {
});
});
test('it serializes the worker_filter attribute if present', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('target');
const record = store.createRecord('target', {
name: 'User',
description: 'Description',
version: 1,
type: TYPE_TARGET_SSH,
worker_filter: 'worker',
default_port: 1234,
with_aliases: [],
scope: {
scope_id: 'org_1',
},
});
const snapshot = record._createSnapshot();
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
name: 'User',
description: 'Description',
version: 1,
type: TYPE_TARGET_SSH,
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: null,
worker_filter: 'worker',
egress_worker_filter: null,
ingress_worker_filter: null,
with_aliases: [],
attributes: {
default_port: 1234,
default_client_port: null,
enable_session_recording: false,
storage_bucket_id: null,
},
address: null,
});
});
test('it serializes the egress_worker_filter attribute if present', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('target');
@@ -286,7 +244,6 @@ module('Unit | Serializer | target', function (hooks) {
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: null,
worker_filter: null,
egress_worker_filter: 'egress worker',
ingress_worker_filter: null,
with_aliases: [],
@@ -325,7 +282,6 @@ module('Unit | Serializer | target', function (hooks) {
scope_id: 'org_1',
session_max_seconds: 28800,
session_connection_limit: null,
worker_filter: null,
egress_worker_filter: null,
ingress_worker_filter: 'ingress worker',
with_aliases: [],
@@ -447,39 +403,6 @@ module('Unit | Serializer | target', function (hooks) {
});
});
test('it normalizes the worker_filter attribute if present', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('target');
const target = store.createRecord('target').constructor;
const payload = {
id: '1',
name: 'Target 1',
worker_filter: 'worker',
};
const normalized = serializer.normalizeSingleResponse(
store,
target,
payload,
);
assert.deepEqual(normalized, {
included: [],
data: {
id: '1',
type: 'target',
attributes: {
aliases: [],
authorized_actions: [],
name: 'Target 1',
host_sources: [],
brokered_credential_source_ids: [],
injected_application_credential_source_ids: [],
worker_filter: 'worker',
},
relationships: {},
},
});
});
test('it normalizes the egress_worker_filter attribute if present', function (assert) {
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('target');
+16 -14
View File
@@ -681,9 +681,6 @@ target:
target-address:
label: Target Address
help: Must be a valid IP address or DNS name. We recommend leaving this blank and using host catalogs and host sets instead if you want to use this target on multiple hosts.
worker_filter:
label: Worker Filter
help: Deprecated. Boolean expression to filter the workers that are allowed to satisfy this request.
default_port:
label: Default Port
help: The default port on which to connect.
@@ -755,9 +752,10 @@ target:
workers:
title: Workers
description: You can customize how your workers route traffic to this target by setting up a filter that matches specific worker tags. If your target is in a private network, we recommend setting up an egress filter to specify a worker inside the network so that Boundary can access the host. Ingress and egress filters are allowed to select the same worker.
deprecation_message:
title: Worker filters have been updated
description: This target is configured using an older version of worker filters. You can update to the new filters but this will also update this field in the Boundary API. We will continue to use this filter until you update.
messages:
none:
title: No worker filter added
description: You haven't added an {type} worker filter yet.
diagram:
client: Client
any-worker: Any worker
@@ -775,17 +773,21 @@ target:
dual-egress-on: In this configuration, the client will attempt to connect through any client-accessible "frontline" worker and reach the host through any filtered egress worker.
dual-egress-on-ingress-on: In this configuration, the client will attempt to connect through any filtered ingress worker and reach the host through any filtered egress worker.
hcp-dual-egress-on: In this configuration, the client will attempt to connect through any HCP-managed worker and reach the host through any filtered egress worker.
filter:
title: Filter
description: Boolean expression.
egress_worker_filter:
title: Egress worker filter
add-egress-worker-filter:
title: Add Egress Worker Filter
description: Specify workers that have access to the target (such as within a private network).
ingress_worker_filter:
title: Ingress worker filter
add-ingress-worker-filter:
title: Add Ingress Worker Filter
description: Specify workers Boundary should use to start the route to this target.
worker-filter:
title: Worker filter
description: The worker filter format for this target.
accordion-label:
egress-workers: Egress workers
ingress-workers: Ingress workers
actions:
update-filter: Update Filter
add-worker-filter: Add worker filter
add-filter: Add filter
credential-store:
title: Credential Store
title_plural: Credential Stores
@@ -6,7 +6,7 @@
<Rose::Form
class={{unless @model.isNew 'full-width'}}
@onSubmit={{@submit}}
@cancel={{this.cancel}}
@cancel={{@cancel}}
@disabled={{@model.isSaving}}
@showEditToggle={{if @model.isNew false true}}
as |form|
@@ -200,132 +200,6 @@
{{/if}}
</Hds::Form::TextInput::Field>
{{#if (feature-flag 'target-worker-filters-v2')}}
<Hds::Form::Fieldset
class='target-workers'
@layout='horizontal'
@isOptional={{true}}
as |F|
>
<F.Legend>{{t 'resources.target.workers.title'}}</F.Legend>
<F.HelperText>{{t 'resources.target.workers.description'}}</F.HelperText>
{{#if this.showDeprecationMessage}}
<F.Control>
<div class='migration-wrapper'>
<Hds::Alert @color='highlight' @type='inline' as |A|>
<A.Title>{{t
'resources.target.workers.deprecation_message.title'
}}</A.Title>
<A.Description>{{t
'resources.target.workers.deprecation_message.description'
}}</A.Description>
</Hds::Alert>
<Hds::Form::TextInput::Field
@value={{@model.worker_filter}}
@isInvalid={{@model.errors.worker_filter}}
@type='text'
name='worker_filter'
disabled={{true}}
{{on 'input' (set-from-event @model 'worker_filter')}}
as |F|
>
<F.Label>
{{t 'resources.target.form.worker_filter.label'}}
</F.Label>
<F.HelperText>
{{t 'resources.target.form.worker_filter.help'}}
</F.HelperText>
</Hds::Form::TextInput::Field>
{{#if form.isEditable}}
<Hds::Button
class='update-filter-button'
@text={{t 'resources.target.workers.actions.update-filter'}}
@color='secondary'
disabled={{form.disabled}}
{{on 'click' this.migrateWorkerFilters}}
/>
{{/if}}
</div>
</F.Control>
{{else}}
<F.Control>
<WorkerDiagram
@egressWorkerFilterEnabled={{this.egressWorkerFilterEnabled}}
@ingressWorkerFilterEnabled={{this.ingressWorkerFilterEnabled}}
/>
{{#if (feature-flag 'target-worker-filters-v2-ingress')}}
<Form::Target::WorkerFilter
@name='ingress_worker_filter'
@disabled={{form.disabled}}
@value={{@model.ingress_worker_filter}}
@toggleAction={{this.toggleIngressFilter}}
@toggleEnabled={{this.ingressWorkerFilterEnabled}}
@onChange={{set-from-event @model 'ingress_worker_filter'}}
@isInvalid={{@model.errors.ingress_worker_filter}}
as |F|
>
{{#if @model.errors.ingress_worker_filter}}
<F.Error as |E|>
{{#each @model.errors.ingress_worker_filter as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
{{/if}}
</Form::Target::WorkerFilter>
{{/if}}
<Form::Target::WorkerFilter
@name='egress_worker_filter'
@disabled={{form.disabled}}
@value={{@model.egress_worker_filter}}
@toggleAction={{this.toggleEgressFilter}}
@toggleEnabled={{this.egressWorkerFilterEnabled}}
@onChange={{set-from-event @model 'egress_worker_filter'}}
@isInvalid={{@model.errors.egress_worker_filter}}
as |F|
>
{{#if @model.errors.egress_worker_filter}}
<F.Error as |E|>
{{#each @model.errors.egress_worker_filter as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
{{/if}}
</Form::Target::WorkerFilter>
</F.Control>
{{/if}}
</Hds::Form::Fieldset>
{{else}}
<Hds::Form::TextInput::Field
@isOptional={{true}}
@value={{@model.worker_filter}}
@isInvalid={{@model.errors.worker_filter}}
@type='text'
name='worker_filter'
disabled={{form.disabled}}
{{on 'input' (set-from-event @model 'worker_filter')}}
as |F|
>
<F.Label>{{t 'resources.target.form.worker_filter.label'}}</F.Label>
<F.HelperText>
{{t 'resources.target.form.worker_filter.help'}}
</F.HelperText>
{{#if @model.errors.worker_filter}}
<F.Error as |E|>
{{#each @model.errors.worker_filter as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
{{/if}}
</Hds::Form::TextInput::Field>
{{/if}}
{{#if
(and @model.isNew (can 'create model' @globalScope collection='aliases'))
}}
@@ -5,8 +5,6 @@
import Component from '@glimmer/component';
import { TYPES_TARGET } from 'api/models/target';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
// NOTE: this is all a temporary solution till we have a resource type helper.
@@ -16,12 +14,10 @@ const icons = {
tcp: 'network',
};
export default class FormTargetComponent extends Component {
// =properties
@tracked egressWorkerFilterEnabled = this.args.model.egress_worker_filter;
@tracked ingressWorkerFilterEnabled = this.args.model.ingress_worker_filter;
// =services
@service features;
/**
* maps resource type with icon
* @type {object}
@@ -41,57 +37,4 @@ export default class FormTargetComponent extends Component {
get icon() {
return icons[this.args.model.type];
}
//actions
@action
toggleEgressFilter() {
this.egressWorkerFilterEnabled = !this.egressWorkerFilterEnabled;
if (!this.egressWorkerFilterEnabled) {
this.args.model.egress_worker_filter = '';
}
}
@action
toggleIngressFilter() {
this.ingressWorkerFilterEnabled = !this.ingressWorkerFilterEnabled;
if (!this.ingressWorkerFilterEnabled) {
this.args.model.ingress_worker_filter = '';
}
}
/**
* Call passed cancel function.
* Unset selected filters.
*/
@action
cancel() {
this.args.cancel();
// Reset the tracked variable for toggles after rollback
this.egressWorkerFilterEnabled = this.args.model.egress_worker_filter;
this.ingressWorkerFilterEnabled = this.args.model.ingress_worker_filter;
}
// These methods may be removed after the `worker_filter` field is removed from the API.
/**
* Evaluates to `true` if the worker filter deprecation message should be shown.
* @type {boolean}
*/
get showDeprecationMessage() {
return !this.args.model.isNew && this.args.model.worker_filter;
}
/**
* Copies the value from `worker_filter` into `egress_worker_filter` and `ingress_worker_filter`
* and unsets `worker_filter`.
*/
@action
migrateWorkerFilters() {
this.egressWorkerFilterEnabled = true;
this.ingressWorkerFilterEnabled = true;
// When update is clicked, copy worker filter value into egress and ingress filter and clear the worker_filter
this.args.model.egress_worker_filter = this.args.model.worker_filter;
this.args.model.ingress_worker_filter = this.args.model.worker_filter;
this.args.model.worker_filter = '';
}
}
@@ -3,41 +3,39 @@
SPDX-License-Identifier: BUSL-1.1
}}
<div class='target-worker-filter' data-test-filter={{@name}}>
<Rose::Form
class='full-width'
@onSubmit={{@submit}}
@cancel={{@cancel}}
@disabled={{@model.isSaving}}
as |form|
>
<Hds::Form::Field as |F|>
<F.Control>
<Rose::CodeEditor as |c|>
<c.toolbar @copyText={{get @model @name}} />
<c.fieldEditor
@onInput={{fn this.setWorkerFilter @model @name}}
@value={{or (get @model @name) ''}}
@options={{hash
mode='text/x-sh'
gutters=(array 'CodeMirror-lint-markers')
lint='true'
}}
/>
</Rose::CodeEditor>
</F.Control>
{{#if (get @model.errors @name)}}
<F.Error as |E|>
{{#each (get @model.errors @name) as |error|}}
<E.Message>{{error.message}}</E.Message>
{{/each}}
</F.Error>
{{/if}}
</Hds::Form::Field>
<Hds::Form::Toggle::Field
name={{concat 'target-worker-filter-toggle-' @name}}
checked={{@toggleEnabled}}
disabled={{@disabled}}
@isOptional={{true}}
{{on 'change' @toggleAction}}
as |F|
>
<F.Label>{{t (concat 'resources.target.workers.' @name '.title')}}</F.Label>
<F.HelperText>{{t
(concat 'resources.target.workers.' @name '.description')
}}</F.HelperText>
</Hds::Form::Toggle::Field>
{{#if @toggleEnabled}}
<Hds::Form::TextInput::Field
@isOptional={{true}}
@value={{@value}}
@isInvalid={{@isInvalid}}
@type={{@type}}
name={{@name}}
disabled={{@disabled}}
{{on 'input' @onChange}}
as |F|
>
<F.Label>{{t 'resources.target.workers.filter.title'}}</F.Label>
<F.HelperText>
{{t 'resources.target.workers.filter.description'}}
<Hds::Link::Inline @href={{doc-url 'target.worker-filters'}}>
{{t 'actions.learn-more'}}
</Hds::Link::Inline>
</F.HelperText>
{{yield F}}
</Hds::Form::TextInput::Field>
{{/if}}
</div>
<form.actions
@submitText={{t 'resources.target.workers.actions.add-filter'}}
@cancelText={{t 'actions.cancel'}}
/>
</Rose::Form>
@@ -0,0 +1,22 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { action } from '@ember/object';
export default class FormTargetWorkerFilterIndexComponent extends Component {
// =actions
/**
* Sets the target model filter to the passed in value.
* @param {TargetModel} model
* @param {string} filter
* @param {string} value
*/
@action
setWorkerFilter(model, filter, value) {
model[filter] = value;
}
}
@@ -7,6 +7,9 @@
<nav.link @route='scopes.scope.targets.target.index'>
{{t 'titles.details'}}
</nav.link>
<nav.link @route='scopes.scope.targets.target.workers'>
{{t 'resources.target.workers.title'}}
</nav.link>
<nav.link @route='scopes.scope.targets.target.host-sources'>
{{t 'resources.target.host-source.title_plural'}}
</nav.link>
@@ -316,4 +316,27 @@ export default class ScopesScopeTargetsIndexController extends Controller {
alias.rollbackAttributes();
await this.router.transitionTo('scopes.scope.targets.target');
}
/**
* Handle save
* @param {TargetModel} target
*/
@action
@loading
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.add-success')
async saveWorkerFilter(target) {
await target.save();
await this.router.replaceWith('scopes.scope.targets.target.workers');
}
/**
* Rollback changes on target.
* @param {TargetModel} target
*/
@action
async cancelWorkerFilter(target) {
target.rollbackAttributes();
await this.router.replaceWith('scopes.scope.targets.target.workers');
}
}
@@ -0,0 +1,10 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Controller, { inject as controller } from '@ember/controller';
export default class ScopesScopeTargetsTargetAddEgressWorkerFilterController extends Controller {
@controller('scopes/scope/targets/index') targets;
}
@@ -0,0 +1,10 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Controller, { inject as controller } from '@ember/controller';
export default class ScopesScopeTargetsTargetAddIngressWorkerFilterController extends Controller {
@controller('scopes/scope/targets/index') targets;
}
@@ -0,0 +1,10 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Controller, { inject as controller } from '@ember/controller';
export default class ScopesScopeTargetsTargetWorkersController extends Controller {
@controller('scopes/scope/targets/index') targets;
}
+3
View File
@@ -98,6 +98,9 @@ Router.map(function () {
this.route('enable-session-recording', function () {
this.route('create-storage-bucket');
});
this.route('workers');
this.route('add-ingress-worker-filter');
this.route('add-egress-worker-filter');
});
this.route('new');
});
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Route from '@ember/routing/route';
export default class ScopesScopeTargetsTargetAddEgressWorkerFilterRoute extends Route {}
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Route from '@ember/routing/route';
export default class ScopesScopeTargetsTargetAddIngressWorkerFilterRoute extends Route {}
@@ -0,0 +1,8 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Route from '@ember/routing/route';
export default class ScopesScopeTargetsTargetWorkersRoute extends Route {}
+8 -31
View File
@@ -551,43 +551,20 @@
// target worker filters
.target-workers {
margin-top: sizing.rems(xxl);
margin-bottom: sizing.rems(xl);
.hds-form-legend {
font-size: sizing.rems(l) - sizing.rems(xxs); // 20
+ .hds-form-helper-text {
margin-bottom: 1rem;
}
.accordion-item-toggle-content {
display: flex;
gap: 0.5rem;
align-items: center;
justify-content: space-between;
}
.hds-alert {
margin-bottom: sizing.rems(l); // 16
}
.migration-wrapper {
margin: sizing.rems(m) 0 sizing.rems(m) 0;
}
// note re Button margin: this is a temp solution,
// when we migrate buttons to HDS, we will analyze the spacing
// issue in all scenarios to come up with an efficient solution
.target-worker-filter {
width: 100%;
.hds-form-field--layout-vertical {
margin-left: 2.5rem;
width: 50%;
}
.hds-form-field--layout-flag {
margin-bottom: 1rem;
}
.rose-form-actions {
margin-top: 2rem;
}
.worker-diagram {
min-height: 15rem;
margin-top: 1rem;
.ordered-series-diagram {
min-height: 10rem;
@@ -0,0 +1,34 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
{{page-title (t 'resources.target.workers.add-egress-worker-filter.title')}}
<Breadcrumbs::Item
@text={{t 'resources.target.workers.add-egress-worker-filter.title'}}
@route='scopes.scope.targets.target.add-egress-worker-filter'
/>
<Rose::Layout::Page as |page|>
<page.breadcrumbs>
<Breadcrumbs::Container />
</page.breadcrumbs>
<page.header>
<h2>
{{t 'resources.target.workers.add-egress-worker-filter.title'}}
<DocLink @doc='target.worker-filters' @iconSize='large' />
</h2>
<p>{{t 'resources.target.workers.add-egress-worker-filter.description'}}</p>
</page.header>
<page.body class='target-workers'>
<Form::Target::WorkerFilter
@name='egress_worker_filter'
@model={{@model}}
@submit={{fn this.targets.saveWorkerFilter @model}}
@cancel={{fn this.targets.cancelWorkerFilter @model}}
/>
</page.body>
</Rose::Layout::Page>
@@ -0,0 +1,37 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
{{page-title (t 'resources.target.workers.add-ingress-worker-filter.title')}}
<Breadcrumbs::Item
@text={{t 'resources.target.workers.add-ingress-worker-filter.title'}}
@route='scopes.scope.targets.target.add-ingress-worker-filter'
/>
<Rose::Layout::Page as |page|>
<page.breadcrumbs>
<Breadcrumbs::Container />
</page.breadcrumbs>
<page.header>
<h2>
{{t 'resources.target.workers.add-ingress-worker-filter.title'}}
<DocLink @doc='target.worker-filters' @iconSize='large' />
</h2>
<p>{{t
'resources.target.workers.add-ingress-worker-filter.description'
}}</p>
</page.header>
<page.body class='target-workers'>
<Form::Target::WorkerFilter
@name='ingress_worker_filter'
@model={{@model}}
@submit={{fn this.targets.saveWorkerFilter @model}}
@cancel={{fn this.targets.cancelWorkerFilter @model}}
/>
</page.body>
</Rose::Layout::Page>
@@ -0,0 +1,139 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
{{page-title (t 'resources.target.workers.title')}}
<Breadcrumbs::Item
@text={{t 'resources.target.workers.title'}}
@route='scopes.scope.targets.target.workers'
/>
<Rose::Layout::Page as |page|>
<page.breadcrumbs>
<Breadcrumbs::Container />
</page.breadcrumbs>
<page.header>
<Targets::Target::Header @model={{@model}} />
</page.header>
<page.navigation>
<Targets::Target::Nav @model={{@model}} />
</page.navigation>
<page.actions>
<Targets::Target::Actions
@model={{@model}}
@delete={{this.targets.delete}}
/>
</page.actions>
<page.body class='target-workers'>
<Hds::Text::Body @tag='p' @size='100' @color='faint'>
{{t 'resources.target.workers.description'}}
</Hds::Text::Body>
<WorkerDiagram
@egressWorkerFilterEnabled={{@model.egress_worker_filter}}
@ingressWorkerFilterEnabled={{@model.ingress_worker_filter}}
/>
<Hds::Accordion as |A|>
{{#if (feature-flag 'target-worker-filters-v2-ingress')}}
<A.Item
@containsInteractive={{true}}
data-test-target-ingress-workers-accordion-item
>
<:toggle>
<div class='accordion-item-toggle-content'>
<span>{{t
'resources.target.workers.accordion-label.ingress-workers'
}}</span>
<Hds::Link::Standalone
@icon='plus'
@text={{t 'resources.target.workers.actions.add-worker-filter'}}
@route='scopes.scope.targets.target.add-ingress-worker-filter'
/>
</div>
</:toggle>
<:content>
{{#if @model.ingress_worker_filter}}
<Hds::CodeBlock
@language='bash'
@hasCopyButton={{true}}
@value={{@model.ingress_worker_filter}}
as |CB|
>
<CB.Title>{{t
'resources.target.workers.worker-filter.title'
}}</CB.Title>
<CB.Description>{{t
'resources.target.workers.worker-filter.description'
}}</CB.Description>
</Hds::CodeBlock>
{{else}}
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.target.workers.messages.none.title'}}
/>
<A.Body
@text={{t
'resources.target.workers.messages.none.description'
type='ingress'
}}
/>
</Hds::ApplicationState>
{{/if}}
</:content>
</A.Item>
{{/if}}
<A.Item
@containsInteractive={{true}}
data-test-target-egress-workers-accordion-item
>
<:toggle>
<div class='accordion-item-toggle-content'>
<span>{{t
'resources.target.workers.accordion-label.egress-workers'
}}</span>
<Hds::Link::Standalone
@icon='plus'
@text={{t 'resources.target.workers.actions.add-worker-filter'}}
@route='scopes.scope.targets.target.add-egress-worker-filter'
/>
</div>
</:toggle>
<:content>
{{#if @model.egress_worker_filter}}
<Hds::CodeBlock
@language='bash'
@hasCopyButton={{true}}
@value={{@model.egress_worker_filter}}
as |CB|
>
<CB.Title>{{t
'resources.target.workers.worker-filter.title'
}}</CB.Title>
<CB.Description>{{t
'resources.target.workers.worker-filter.description'
}}</CB.Description>
</Hds::CodeBlock>
{{else}}
<Hds::ApplicationState as |A|>
<A.Header
@title={{t 'resources.target.workers.messages.none.title'}}
/>
<A.Body
@text={{t
'resources.target.workers.messages.none.description'
type='egress'
}}
/>
</Hds::ApplicationState>
{{/if}}
</:content>
</A.Item>
</Hds::Accordion>
</page.body>
</Rose::Layout::Page>
-2
View File
@@ -23,7 +23,6 @@ const baseEdition = {
'byow-pki-hcp-cluster-id': false,
'json-credentials': false,
'static-credentials': false,
'target-worker-filters-v2': false,
'target-worker-filters-v2-ingress': false,
'target-worker-filters-v2-hcp': false,
'target-network-address': false,
@@ -37,7 +36,6 @@ featureEditions.oss = {
byow: true,
'json-credentials': true,
'static-credentials': true,
'target-worker-filters-v2': true,
'target-network-address': true,
'ldap-auth-methods': true,
};
@@ -93,11 +93,9 @@ module('Acceptance | targets | create', function (hooks) {
assert.strictEqual(find('[name="type"]:checked').value, TYPE_TARGET_SSH);
});
test('can create type `ssh` when `target-worker-filters-v2` is disabled', async function (assert) {
test('can create a type `ssh` target', async function (assert) {
featuresService.enable('ssh-target');
assert.false(featuresService.isEnabled('target-worker-filters-v2'));
const targetCount = getTargetCount();
const sshTargetCount = getSSHTargetCount();
await visit(urls.targets);
@@ -105,7 +103,6 @@ module('Acceptance | targets | create', function (hooks) {
await click(`[href="${urls.newTarget}"]`);
await click('[value="ssh"]');
await fillIn('[name="name"]', 'random string');
await fillIn('[name="worker_filter"]', 'random filter');
await click(SAVE_BTN_SELECTOR);
assert.strictEqual(getSSHTargetCount(), sshTargetCount + 1);
@@ -114,48 +111,10 @@ module('Acceptance | targets | create', function (hooks) {
this.server.schema.targets.all().models[getTargetCount() - 1].name,
'random string',
);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1]
.workerFilter,
'random filter',
);
});
test('can create type `ssh` when `target-worker-filters-v2` is enabled', async function (assert) {
test('can create a type `tcp` target', async function (assert) {
featuresService.enable('ssh-target');
featuresService.enable('target-worker-filters-v2');
const targetCount = getTargetCount();
const sshTargetCount = getSSHTargetCount();
await visit(urls.targets);
await click(`[href="${urls.newTarget}"]`);
await click('[value="ssh"]');
await fillIn('[name="name"]', 'random string');
await click(
'[name="target-worker-filter-toggle-egress_worker_filter"]',
'Egress toggle',
);
await fillIn('[name="egress_worker_filter"]', 'random filter');
await click(SAVE_BTN_SELECTOR);
assert.strictEqual(getSSHTargetCount(), sshTargetCount + 1);
assert.strictEqual(getTargetCount(), targetCount + 1);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1].name,
'random string',
);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1]
.egressWorkerFilter,
'random filter',
);
});
test('can create type `tcp` when `target-worker-filters-v2` is disabled', async function (assert) {
featuresService.enable('ssh-target');
assert.false(featuresService.isEnabled('target-worker-filters-v2'));
const targetCount = getTargetCount();
const tcpTargetCount = getTCPTargetCount();
@@ -164,7 +123,6 @@ module('Acceptance | targets | create', function (hooks) {
await click(`[href="${urls.newTarget}"]`);
await click('[value="tcp"]');
await fillIn('[name="name"]', 'random string');
await fillIn('[name="worker_filter"]', 'random filter');
await click(SAVE_BTN_SELECTOR);
assert.strictEqual(getTargetCount(), targetCount + 1);
@@ -173,79 +131,6 @@ module('Acceptance | targets | create', function (hooks) {
this.server.schema.targets.all().models[getTargetCount() - 1].name,
'random string',
);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1]
.workerFilter,
'random filter',
);
});
test('can create type `tcp` when `target-worker-filters-v2` is enabled', async function (assert) {
featuresService.enable('ssh-target');
featuresService.enable('target-worker-filters-v2');
const targetCount = getTargetCount();
const tcpTargetCount = getTCPTargetCount();
await visit(urls.targets);
await click(`[href="${urls.newTarget}"]`);
await click('[value="tcp"]');
await fillIn('[name="name"]', 'random string');
await click(
'[name="target-worker-filter-toggle-egress_worker_filter"]',
'Egress toggle',
);
await fillIn('[name="egress_worker_filter"]', 'random filter');
await click(SAVE_BTN_SELECTOR);
assert.strictEqual(getTargetCount(), targetCount + 1);
assert.strictEqual(getTCPTargetCount(), tcpTargetCount + 1);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1].name,
'random string',
);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1]
.egressWorkerFilter,
'random filter',
);
});
test('can create type `tcp` when `target-worker-filters-v2` and `target-worker-filters-v2-ingress` is enabled', async function (assert) {
featuresService.enable('ssh-target');
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
const targetCount = getTargetCount();
const tcpTargetCount = getTCPTargetCount();
await visit(urls.targets);
await click(`[href="${urls.newTarget}"]`);
await click('[value="tcp"]');
await fillIn('[name="name"]', 'random string');
await click(
'[data-test-filter="egress_worker_filter"] .hds-form-toggle__control',
);
await fillIn('[name="egress_worker_filter"]', 'random filter');
await click(
'[data-test-filter="ingress_worker_filter"] .hds-form-toggle__control',
);
await fillIn('[name="ingress_worker_filter"]', 'random filter');
await click(SAVE_BTN_SELECTOR);
assert.strictEqual(getTargetCount(), targetCount + 1);
assert.strictEqual(getTCPTargetCount(), tcpTargetCount + 1);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1].name,
'random string',
);
assert.strictEqual(
this.server.schema.targets.all().models[getTargetCount() - 1]
.egressWorkerFilter,
'random filter',
);
});
test('default port is not marked required for SSH targets', async function (assert) {
@@ -306,20 +191,12 @@ module('Acceptance | targets | create', function (hooks) {
});
test('can cancel create new TCP target', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
const targetCount = getTargetCount();
const tcpTargetCount = getTCPTargetCount();
await visit(urls.targets);
await click(`[href="${urls.newTarget}"]`);
await fillIn('[name="name"]', 'random string');
await click(
'[name="target-worker-filter-toggle-egress_worker_filter"]',
'Egress toggle',
);
await fillIn('[name="egress_worker_filter"]', 'random filter');
await click('.rose-form-actions [type="button"]');
assert.strictEqual(currentURL(), urls.targets);
@@ -366,8 +243,6 @@ module('Acceptance | targets | create', function (hooks) {
test('can cancel create new SSH target', async function (assert) {
featuresService.enable('ssh-target');
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
const targetCount = getTargetCount();
const sshTargetCount = getSSHTargetCount();
@@ -375,11 +250,6 @@ module('Acceptance | targets | create', function (hooks) {
await click(`[href="${urls.newTarget}"]`);
await fillIn('[name="name"]', 'random string');
await click('[value="ssh"]');
await click(
'[name="target-worker-filter-toggle-egress_worker_filter"]',
'Egress toggle',
);
await fillIn('[name="egress_worker_filter"]', 'random filter');
await click('.rose-form-actions [type="button"]');
assert.strictEqual(currentURL(), urls.targets);
@@ -117,50 +117,6 @@ module('Acceptance | targets | read', function (hooks) {
assert.strictEqual(currentURL(), urls.tcpTarget);
});
test('visiting an ssh target shows the worker_filter deprecation message when worker_filter has value and "target-worker-filters-v2" is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
instances.sshTarget.worker_filter = 'worker filter present';
await visit(urls.sshTarget);
assert.dom('.hds-alert').isVisible();
});
test('visiting a tcp target shows the worker_filter deprecation message when worker_filter has value and "target-worker-filters-v2" is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
instances.tcpTarget.worker_filter = 'worker filter present';
await visit(urls.tcpTarget);
assert.dom('.hds-alert').isVisible();
});
test('visiting an ssh target does not show the worker_filter deprecation message when worker_filter has no value and "target-worker-filters-v2" is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
instances.sshTarget.worker_filter = null;
await visit(urls.sshTarget);
assert.dom('.hds-alert').doesNotExist();
});
test('visiting a tcp target does not show the worker_filter deprecation message when worker_filter has no value and "target-worker-filters-v2" is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
instances.tcpTarget.worker_filter = null;
await visit(urls.tcpTarget);
assert.dom('.hds-alert').doesNotExist();
});
test('visiting an ssh target does not show the worker_filter deprecation message when "target-worker-filters-v2" is disabled', async function (assert) {
await visit(urls.sshTarget);
assert.false(featuresService.isEnabled('target-worker-filters-v2'));
assert.dom('.hds-alert').doesNotExist();
});
test('visiting a tcp target does not show the worker_filter deprecation message when "target-worker-filters-v2" is disabled', async function (assert) {
await visit(urls.tcpTarget);
assert.false(featuresService.isEnabled('target-worker-filters-v2'));
assert.dom('.hds-alert').doesNotExist();
});
test('cannot navigate to an ssh target form without proper authorization', async function (assert) {
featuresService.enable('ssh-target');
await visit(urls.projectScope);
@@ -73,7 +73,6 @@ module('Acceptance | targets | update', function (hooks) {
await click(`[href="${urls.target}"]`);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await fillIn('[name="name"]', 'random string');
await fillIn('[name="worker_filter"]', 'random filter');
await click('.rose-form-actions [type="submit"]');
assert.strictEqual(currentURL(), urls.target);
@@ -81,162 +80,6 @@ module('Acceptance | targets | update', function (hooks) {
this.server.schema.targets.first().name,
'random string',
);
assert.strictEqual(
this.server.schema.targets.first().workerFilter,
'random filter',
);
});
test('updating a target shows the worker_filter deprecation message when "target-worker-filters-v2" is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
await visit(urls.target);
assert.dom('.hds-alert').isVisible();
});
test('updating a target does not show the worker_filter deprecation message when "target-worker-filters-v2" is disabled', async function (assert) {
await visit(urls.target);
assert.false(featuresService.isEnabled('target-worker-filters-v2'));
assert.dom('.hds-alert').doesNotExist();
});
test('cannot edit worker_filter when "target-worker-filters-v2" is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2');
await visit(urls.target);
assert.dom('[name=worker_filter]').isDisabled();
});
test('show update filter button when the old worker filter field is has value', async function (assert) {
featuresService.enable('target-worker-filters-v2');
await visit(urls.target);
assert.dom('[name=worker_filter]').isVisible();
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
assert.dom('.hds-button').hasText('Update Filter');
});
test('onClick update filter should select the egress toggle and the worker_filter value is copied into egress_worker_filter', async function (assert) {
featuresService.enable('target-worker-filters-v2');
await visit(urls.target);
assert.dom('[name=worker_filter]').isVisible();
const worker_filter_value = this.server.schema.targets.first().workerFilter;
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-button[type="button"]', 'Update Filter');
assert.strictEqual(
this.server.schema.targets.first().egressWorkerFilter,
worker_filter_value,
);
});
test('onClick update filter should select the egress and ingress toggle and the worker_filter value is copied into egress_worker_filter and ingress_worker_filter', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
await visit(urls.target);
assert.dom('[name=worker_filter]').isVisible();
const worker_filter_value = this.server.schema.targets.first().workerFilter;
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-button[type="button"]', 'Update Filter');
assert.strictEqual(
this.server.schema.targets.first().egressWorkerFilter,
worker_filter_value,
);
assert.strictEqual(
this.server.schema.targets.first().ingressWorkerFilter,
worker_filter_value,
);
});
test('show filter input field when the `egress_worker_filter` toggle is on', async function (assert) {
featuresService.enable('target-worker-filters-v2');
await visit(urls.target);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-button[type="button"]', 'Update Filter');
assert.dom('[name=egress_worker_filter]').isVisible();
});
test('hide filter input field when the `egress_worker_filter` toggled is off', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
await visit(urls.target);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-button[type="button"]', 'Update Filter');
await click(
'[name="target-worker-filter-toggle-egress_worker_filter"]',
'Egress toggle',
);
assert.dom('[name=egress_worker_filter]').isNotVisible();
});
test('clear `egress_worker_field` value from a target when the toggle is off and form is saved', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
await visit(urls.target);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-button[type="button"]', 'Update Filter');
await fillIn('[name=egress_worker_filter]', 'random filter string');
await click('.rose-form-actions [type="submit"]');
assert.strictEqual(currentURL(), urls.target);
assert.strictEqual(
this.server.schema.targets.first().egressWorkerFilter,
'random filter string',
);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click(
'[name="target-worker-filter-toggle-egress_worker_filter"]',
'Egress toggle',
);
await click('.rose-form-actions [type="submit"]');
//clear egress_worker_filter when the toggle is off
assert.strictEqual(currentURL(), urls.target);
assert.dom('[name=egress_worker_filter]').doesNotExist();
assert.strictEqual(
this.server.schema.targets.first().egressWorkerFilter,
null,
);
});
test('show filter input field when the `ingress_worker_filter` toggle is on', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
await visit(urls.target);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-button[type="button"]', 'Update Filter');
assert.dom('[name=ingress_worker_filter]').isVisible();
});
test('hide filter input field when the `ingress_worker_filter` toggled is off', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
await visit(urls.target);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-button[type="button"]', 'Update Filter');
await click('.hds-form-toggle__control', 'Ingress worker filter');
assert.dom('[name=ingress_worker_filter]').isNotVisible();
});
test('clear `ingress_worker_field` value from a target when the toggle is off and form is saved', async function (assert) {
featuresService.enable('target-worker-filters-v2');
featuresService.enable('target-worker-filters-v2-ingress');
await visit(urls.target);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-button[type="button"]', 'Update Filter');
await fillIn('[name=ingress_worker_filter]', 'random filter string');
await click('.rose-form-actions [type="submit"]');
assert.strictEqual(currentURL(), urls.target);
assert.strictEqual(
this.server.schema.targets.first().ingressWorkerFilter,
'random filter string',
);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await click('.hds-form-toggle__control', 'Ingress worker filter');
await click('.rose-form-actions [type="submit"]');
//clear egress_worker_filter when the toggle is off
assert.strictEqual(currentURL(), urls.target);
assert.dom('[name=ingress_worker_filter]').doesNotExist();
assert.strictEqual(
this.server.schema.targets.first().ingressWorkerFilter,
null,
);
});
test('can cancel changes to existing target', async function (assert) {
@@ -282,36 +125,28 @@ module('Acceptance | targets | update', function (hooks) {
});
test('can discard unsaved target changes via dialog', async function (assert) {
featuresService.enable('target-worker-filters-v2');
const confirmService = this.owner.lookup('service:confirm');
confirmService.enabled = true;
assert.notEqual(instances.target.name, 'random string');
assert.notEqual(
instances.target.egressWorkerFilter,
'random worker string',
);
await visit(urls.targets);
await click(`[href="${urls.target}"]`);
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await fillIn('[name="name"]', 'random string');
await click('.hds-button[type="button"]', 'Update Filter');
await fillIn('[name="egress_worker_filter"]', 'random worker string');
assert.strictEqual(currentURL(), urls.target);
await click(`[href="${urls.targets}"]`);
assert.dom('.rose-dialog').exists();
await click('.rose-dialog-footer button:first-child', 'Click Discard');
assert.strictEqual(currentURL(), urls.targets);
assert.notEqual(this.server.schema.targets.first().name, 'random string');
assert.notEqual(
this.server.schema.targets.first().egressWorkerFilter,
'random worker string',
);
});
test('can click cancel on discard dialog box for unsaved target changes', async function (assert) {
featuresService.enable('target-worker-filters-v2');
const confirmService = this.owner.lookup('service:confirm');
confirmService.enabled = true;
assert.notEqual(instances.target.name, 'random string');
@@ -321,8 +156,6 @@ module('Acceptance | targets | update', function (hooks) {
await click('.rose-form-actions [type="button"]', 'Activate edit mode');
await fillIn('[name="name"]', 'random string');
await click('.hds-button[type="button"]', 'Update Filter');
await fillIn('[name="egress_worker_filter"]', 'random filter');
assert.strictEqual(currentURL(), urls.target);
await click(`[href="${urls.targets}"]`);
assert.dom('.rose-dialog').exists();
@@ -0,0 +1,333 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { visit, currentURL, click, fillIn } 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';
import { authenticateSession } from 'ember-simple-auth/test-support';
module('Acceptance | targets | workers', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
let featuresService;
let featureEdition;
const ACCORDION_DROPDOWN_SELECTOR = (name) =>
`[data-test-target-${name}-workers-accordion-item] .hds-accordion-item__button`;
const CODE_BLOCK_SELECTOR = (name) =>
`[data-test-target-${name}-workers-accordion-item] .hds-code-block__body`;
const CODE_EDITOR_CONTENT_SELECTOR =
'[data-test-code-editor-field-editor] textarea';
const SAVE_BUTTON_SELECTOR = '[type="submit"]';
const CANCEL_BUTTON_SELECTOR = '.rose-form-actions [type="button"]';
const MODAL_DISCARD_BUTTON_SELECTOR =
'.rose-dialog-footer button:first-child';
const MODAL_CANCEL_BUTTON_SELECTOR = '.rose-dialog-footer button:last-child';
const CONFIRM_MODAL_SELECTOR = '.rose-dialog';
const instances = {
scopes: {
global: null,
org: null,
project: null,
},
target: null,
};
const urls = {
orgScope: null,
projectScope: null,
targets: null,
target: null,
targetWorkers: null,
targetAddEgressFilter: null,
targetAddIngressFilter: null,
};
hooks.beforeEach(function () {
featuresService = this.owner.lookup('service:features');
featureEdition = this.owner.lookup('service:featureEdition');
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,
egress_worker_filter: '"egress" in "/worker/filter"',
ingress_worker_filter: '"ingress" in "/worker/filter"',
});
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.targetWorkers = `${urls.target}/workers`;
urls.targetAddEgressFilter = `${urls.target}/add-egress-worker-filter`;
urls.targetAddIngressFilter = `${urls.target}/add-ingress-worker-filter`;
authenticateSession({});
});
test('visiting target workers', async function (assert) {
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await a11yAudit();
assert.strictEqual(currentURL(), urls.targetWorkers);
});
test('user can view egress and ingress filters in enterprise edition', async function (assert) {
featureEdition.setEdition('enterprise');
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(ACCORDION_DROPDOWN_SELECTOR('ingress'));
await click(ACCORDION_DROPDOWN_SELECTOR('egress'));
assert
.dom(CODE_BLOCK_SELECTOR('ingress'))
.hasText(instances.target.ingress_worker_filter);
assert
.dom(CODE_BLOCK_SELECTOR('egress'))
.hasText(instances.target.egress_worker_filter);
});
test('user can view egress and ingress filters in hcp edition', async function (assert) {
featureEdition.setEdition('hcp');
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(ACCORDION_DROPDOWN_SELECTOR('ingress'));
await click(ACCORDION_DROPDOWN_SELECTOR('egress'));
assert
.dom(CODE_BLOCK_SELECTOR('ingress'))
.hasText(instances.target.ingress_worker_filter);
assert
.dom(CODE_BLOCK_SELECTOR('egress'))
.hasText(instances.target.egress_worker_filter);
});
test('user can only view egress filter in oss edition', async function (assert) {
featureEdition.setEdition('oss');
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(ACCORDION_DROPDOWN_SELECTOR('egress'));
assert.dom(ACCORDION_DROPDOWN_SELECTOR('ingress')).doesNotExist();
assert
.dom(CODE_BLOCK_SELECTOR('egress'))
.hasText(instances.target.egress_worker_filter);
});
test('user can view egress and ingress filters when `target-worker-filters-v2-ingress` is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2-ingress');
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(ACCORDION_DROPDOWN_SELECTOR('ingress'));
await click(ACCORDION_DROPDOWN_SELECTOR('egress'));
assert
.dom(CODE_BLOCK_SELECTOR('ingress'))
.hasText(instances.target.ingress_worker_filter);
assert
.dom(CODE_BLOCK_SELECTOR('egress'))
.hasText(instances.target.egress_worker_filter);
});
test('user can only view egress filter when `target-worker-filters-v2-ingress` is disabled', async function (assert) {
featuresService.disable('target-worker-filters-v2-ingress');
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(ACCORDION_DROPDOWN_SELECTOR('egress'));
assert.dom(ACCORDION_DROPDOWN_SELECTOR('ingress')).doesNotExist();
assert
.dom(CODE_BLOCK_SELECTOR('egress'))
.hasText(instances.target.egress_worker_filter);
});
test('user can save ingress worker filter to a target when `target-worker-filters-v2-ingress` is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2-ingress');
instances.target.update({ ingress_worker_filter: '' });
const ingressWorkerFilter = '"random" in "/worker/filters"';
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(`[href="${urls.targetAddIngressFilter}"]`);
assert.strictEqual(currentURL(), urls.targetAddIngressFilter);
await fillIn(CODE_EDITOR_CONTENT_SELECTOR, ingressWorkerFilter);
await click(SAVE_BUTTON_SELECTOR);
await click(ACCORDION_DROPDOWN_SELECTOR('ingress'));
assert.strictEqual(currentURL(), urls.targetWorkers);
assert.dom(CODE_BLOCK_SELECTOR('ingress')).hasText(ingressWorkerFilter);
});
test('user can cancel changes to ingress worker filter in a target when `target-worker-filters-v2-ingress` is enabled', async function (assert) {
featuresService.enable('target-worker-filters-v2-ingress');
const ingressWorkerFilter = '"random" in "/worker/filters"';
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(`[href="${urls.targetAddIngressFilter}"]`);
assert.strictEqual(currentURL(), urls.targetAddIngressFilter);
await fillIn(CODE_EDITOR_CONTENT_SELECTOR, ingressWorkerFilter);
await click(CANCEL_BUTTON_SELECTOR);
await click(ACCORDION_DROPDOWN_SELECTOR('ingress'));
assert.strictEqual(currentURL(), urls.targetWorkers);
assert.notEqual(instances.target.inress_worker_filter, ingressWorkerFilter);
assert
.dom(CODE_BLOCK_SELECTOR('ingress'))
.hasText(instances.target.ingress_worker_filter);
});
test('user can save egress worker filter to a target', async function (assert) {
instances.target.update({ egress_worker_filter: '' });
const egressWorkerFilter = '"random" in "/worker/filters"';
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(`[href="${urls.targetAddEgressFilter}"]`);
assert.strictEqual(currentURL(), urls.targetAddEgressFilter);
await fillIn(CODE_EDITOR_CONTENT_SELECTOR, egressWorkerFilter);
await click(SAVE_BUTTON_SELECTOR);
await click(ACCORDION_DROPDOWN_SELECTOR('egress'));
assert.strictEqual(currentURL(), urls.targetWorkers);
assert.dom(CODE_BLOCK_SELECTOR('egress')).hasText(egressWorkerFilter);
});
test('user can cancel changes to egress worker filter in a target', async function (assert) {
const egressWorkerFilter = '"random" in "/worker/filters"';
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(`[href="${urls.targetAddEgressFilter}"]`);
assert.strictEqual(currentURL(), urls.targetAddEgressFilter);
await fillIn(CODE_EDITOR_CONTENT_SELECTOR, egressWorkerFilter);
await click(CANCEL_BUTTON_SELECTOR);
await click(ACCORDION_DROPDOWN_SELECTOR('egress'));
assert.strictEqual(currentURL(), urls.targetWorkers);
assert.notEqual(instances.target.egress_worker_filter, egressWorkerFilter);
assert
.dom(CODE_BLOCK_SELECTOR('egress'))
.hasText(instances.target.egress_worker_filter);
});
test('can discard unsaved ingress worker filter changes in a target via dialog', async function (assert) {
featuresService.enable('target-worker-filters-v2-ingress');
const confirmService = this.owner.lookup('service:confirm');
confirmService.enabled = true;
const ingressWorkerFilter = '"random" in "/worker/filters"';
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(`[href="${urls.targetAddIngressFilter}"]`);
assert.strictEqual(currentURL(), urls.targetAddIngressFilter);
await fillIn(CODE_EDITOR_CONTENT_SELECTOR, ingressWorkerFilter);
await click(`[href="${urls.target}"]`);
assert.dom(CONFIRM_MODAL_SELECTOR).isVisible();
await click(MODAL_DISCARD_BUTTON_SELECTOR, 'Click Discard');
assert.strictEqual(currentURL(), urls.target);
assert.notEqual(
instances.target.ingress_worker_filter,
ingressWorkerFilter,
);
});
test('can click cancel on discard dialog box for unsaved ingress worker filter changes', async function (assert) {
featuresService.enable('target-worker-filters-v2-ingress');
const confirmService = this.owner.lookup('service:confirm');
confirmService.enabled = true;
const ingressWorkerFilter = '"random" in "/worker/filters"';
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(`[href="${urls.targetAddIngressFilter}"]`);
assert.strictEqual(currentURL(), urls.targetAddIngressFilter);
await fillIn(CODE_EDITOR_CONTENT_SELECTOR, ingressWorkerFilter);
await click(`[href="${urls.target}"]`);
assert.dom(CONFIRM_MODAL_SELECTOR).isVisible();
await click(MODAL_CANCEL_BUTTON_SELECTOR, 'Click Cancel');
assert.strictEqual(currentURL(), urls.targetAddIngressFilter);
assert.notEqual(
instances.target.ingress_worker_filter,
ingressWorkerFilter,
);
});
test('can discard unsaved egress worker filter changes in a target via dialog', async function (assert) {
const confirmService = this.owner.lookup('service:confirm');
confirmService.enabled = true;
const egressWorkerFilter = '"random" in "/worker/filters"';
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(`[href="${urls.targetAddEgressFilter}"]`);
assert.strictEqual(currentURL(), urls.targetAddEgressFilter);
await fillIn(CODE_EDITOR_CONTENT_SELECTOR, egressWorkerFilter);
await click(`[href="${urls.target}"]`);
assert.dom(CONFIRM_MODAL_SELECTOR).isVisible();
await click(MODAL_DISCARD_BUTTON_SELECTOR, 'Click Discard');
assert.strictEqual(currentURL(), urls.target);
assert.notEqual(instances.target.egress_worker_filter, egressWorkerFilter);
});
test('can click cancel on discard dialog box for unsaved egress worker filter changes', async function (assert) {
const confirmService = this.owner.lookup('service:confirm');
confirmService.enabled = true;
const egressWorkerFilter = '"random" in "/worker/filters"';
await visit(urls.target);
await click(`[href="${urls.targetWorkers}"]`);
await click(`[href="${urls.targetAddEgressFilter}"]`);
assert.strictEqual(currentURL(), urls.targetAddEgressFilter);
await fillIn(CODE_EDITOR_CONTENT_SELECTOR, egressWorkerFilter);
await click(`[href="${urls.target}"]`);
assert.dom(CONFIRM_MODAL_SELECTOR).isVisible();
await click(MODAL_CANCEL_BUTTON_SELECTOR, 'Click Cancel');
assert.strictEqual(currentURL(), urls.targetAddEgressFilter);
assert.notEqual(instances.target.egress_worker_filter, egressWorkerFilter);
});
});
@@ -13,25 +13,33 @@ module('Integration | Component | form/target/worker-filter', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
test('it only renders a toggle field when "toggleEnabled" is false', async function (assert) {
this.onChange = () => {};
this.toggleAction = () => {};
test('it renders correct content when egress_worker_filter is passed in', async function (assert) {
this.onInput = () => {};
this.submit = () => {};
this.cancel = () => {};
this.model = { egress_worker_filter: 'egress filter' };
await render(
hbs`<Form::Target::WorkerFilter @name='egress_worker_filter' @toggleEnabled={{false}} @toggleAction={{this.toggleAction}} @onChange={{this.onChange}}/>`,
hbs`<Form::Target::WorkerFilter @name='egress_worker_filter' @model={{this.model}} @onInput={{this.onInput}} @submit={{this.submit}} @cancel={{this.cancel}} />`,
);
assert.dom('.hds-form-toggle').isVisible();
assert.dom('.hds-form-text-input').doesNotExist();
assert.dom('[data-test-code-editor-field-editor]').isVisible();
assert
.dom('[data-test-code-editor-field-editor] .CodeMirror-line')
.hasText(this.model.egress_worker_filter);
});
test('it renders a toggle field and text input field when "toggleEnabled" is true', async function (assert) {
this.onChange = () => {};
this.toggleAction = () => {};
test('it renders correct content when ingress_worker_filter is passed in', async function (assert) {
this.onInput = () => {};
this.submit = () => {};
this.cancel = () => {};
this.model = { ingress_worker_filter: 'ingress filter' };
await render(
hbs`<Form::Target::WorkerFilter @name='egress_worker_filter' @toggleEnabled={{true}} @toggleAction={{this.toggleAction}} @onChange={{this.onChange}}/>`,
hbs`<Form::Target::WorkerFilter @name='ingress_worker_filter' @model={{this.model}} @onInput={{this.onInput}} @submit={{this.submit}} @cancel={{this.cancel}}/>`,
);
assert.dom('.hds-form-toggle').isVisible();
assert.dom('.hds-form-text-input').isVisible();
assert.dom('[data-test-code-editor-field-editor]').isVisible();
assert
.dom('[data-test-code-editor-field-editor] .CodeMirror-line')
.hasText(this.model.ingress_worker_filter);
});
});
@@ -262,4 +262,26 @@ module('Unit | Controller | scopes/scope/targets/index', function (hooks) {
assert.notEqual(alias.name, 'test');
});
test('cancelWorkerFilter action rolls-back changes on the specified model', async function (assert) {
await visit(urls.target);
const target = await store.findRecord('target', instances.target.id);
target.egress_worker_filter = 'test';
assert.strictEqual(target.egress_worker_filter, 'test');
await controller.cancelWorkerFilter(target);
assert.notEqual(target.egress_worker_filter, 'test');
});
test('saveWorkerFilter action saves changes on the specified model', async function (assert) {
await visit(urls.target);
const target = await store.findRecord('target', instances.target.id);
target.egress_worker_filter = 'test';
await controller.saveWorkerFilter(target);
assert.strictEqual(target.egress_worker_filter, 'test');
});
});
@@ -0,0 +1,21 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Controller | scopes/scope/targets/target/add-egress-worker-filter',
function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let controller = this.owner.lookup(
'controller:scopes/scope/targets/target/add-egress-worker-filter',
);
assert.ok(controller);
});
},
);
@@ -0,0 +1,21 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Controller | scopes/scope/targets/target/add-ingress-worker-filter',
function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let controller = this.owner.lookup(
'controller:scopes/scope/targets/target/add-ingress-worker-filter',
);
assert.ok(controller);
});
},
);
@@ -0,0 +1,21 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Controller | scopes/scope/targets/target/workers',
function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let controller = this.owner.lookup(
'controller:scopes/scope/targets/target/workers',
);
assert.ok(controller);
});
},
);
@@ -0,0 +1,21 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Route | scopes/scope/targets/target/add-egress-worker-filter',
function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup(
'route:scopes/scope/targets/target/add-egress-worker-filter',
);
assert.ok(route);
});
},
);
@@ -0,0 +1,21 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module(
'Unit | Route | scopes/scope/targets/target/add-ingress-worker-filter',
function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup(
'route:scopes/scope/targets/target/add-ingress-worker-filter',
);
assert.ok(route);
});
},
);
@@ -0,0 +1,16 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Route | scopes/scope/targets/target/workers', function (hooks) {
setupTest(hooks);
test('it exists', function (assert) {
let route = this.owner.lookup('route:scopes/scope/targets/target/workers');
assert.ok(route);
});
});