diff --git a/addons/api/addon/generated/models/target.js b/addons/api/addon/generated/models/target.js index 1b649e2b2..ba08747d6 100644 --- a/addons/api/addon/generated/models/target.js +++ b/addons/api/addon/generated/models/target.js @@ -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.', diff --git a/addons/api/mirage/factories/target.js b/addons/api/mirage/factories/target.js index 2a0eff78b..fb61cda74 100644 --- a/addons/api/mirage/factories/target.js +++ b/addons/api/mirage/factories/target.js @@ -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], diff --git a/addons/api/tests/unit/serializers/target-test.js b/addons/api/tests/unit/serializers/target-test.js index 2c34a0181..62f8f07c7 100644 --- a/addons/api/tests/unit/serializers/target-test.js +++ b/addons/api/tests/unit/serializers/target-test.js @@ -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'); diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index e5e9296a7..db18b2531 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -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 diff --git a/ui/admin/app/components/form/target/details/index.hbs b/ui/admin/app/components/form/target/details/index.hbs index 4ed702031..c9d934dc7 100644 --- a/ui/admin/app/components/form/target/details/index.hbs +++ b/ui/admin/app/components/form/target/details/index.hbs @@ -6,7 +6,7 @@ - {{#if (feature-flag 'target-worker-filters-v2')}} - - - {{t 'resources.target.workers.title'}} - {{t 'resources.target.workers.description'}} - - {{#if this.showDeprecationMessage}} - -
- - {{t - 'resources.target.workers.deprecation_message.title' - }} - {{t - 'resources.target.workers.deprecation_message.description' - }} - - - - {{t 'resources.target.form.worker_filter.label'}} - - - {{t 'resources.target.form.worker_filter.help'}} - - - - {{#if form.isEditable}} - - {{/if}} -
-
- {{else}} - - - {{#if (feature-flag 'target-worker-filters-v2-ingress')}} - - {{#if @model.errors.ingress_worker_filter}} - - {{#each @model.errors.ingress_worker_filter as |error|}} - {{error.message}} - {{/each}} - - {{/if}} - - {{/if}} - - - {{#if @model.errors.egress_worker_filter}} - - {{#each @model.errors.egress_worker_filter as |error|}} - {{error.message}} - {{/each}} - - {{/if}} - - - - {{/if}} - -
- - {{else}} - - {{t 'resources.target.form.worker_filter.label'}} - - {{t 'resources.target.form.worker_filter.help'}} - - {{#if @model.errors.worker_filter}} - - {{#each @model.errors.worker_filter as |error|}} - {{error.message}} - {{/each}} - - {{/if}} - - {{/if}} - {{#if (and @model.isNew (can 'create model' @globalScope collection='aliases')) }} diff --git a/ui/admin/app/components/form/target/details/index.js b/ui/admin/app/components/form/target/details/index.js index 2bf52c9c7..f80de1392 100644 --- a/ui/admin/app/components/form/target/details/index.js +++ b/ui/admin/app/components/form/target/details/index.js @@ -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 = ''; - } } diff --git a/ui/admin/app/components/form/target/worker-filter/index.hbs b/ui/admin/app/components/form/target/worker-filter/index.hbs index e512ea122..7b8bcdc44 100644 --- a/ui/admin/app/components/form/target/worker-filter/index.hbs +++ b/ui/admin/app/components/form/target/worker-filter/index.hbs @@ -3,41 +3,39 @@ SPDX-License-Identifier: BUSL-1.1 }} -
+ + + + + + + + + {{#if (get @model.errors @name)}} + + {{#each (get @model.errors @name) as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + - - {{t (concat 'resources.target.workers.' @name '.title')}} - {{t - (concat 'resources.target.workers.' @name '.description') - }} - - - {{#if @toggleEnabled}} - - {{t 'resources.target.workers.filter.title'}} - - {{t 'resources.target.workers.filter.description'}} - - {{t 'actions.learn-more'}} - - - {{yield F}} - - {{/if}} -
\ No newline at end of file + +
\ No newline at end of file diff --git a/ui/admin/app/components/form/target/worker-filter/index.js b/ui/admin/app/components/form/target/worker-filter/index.js new file mode 100644 index 000000000..818fc2998 --- /dev/null +++ b/ui/admin/app/components/form/target/worker-filter/index.js @@ -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; + } +} diff --git a/ui/admin/app/components/targets/target/nav/index.hbs b/ui/admin/app/components/targets/target/nav/index.hbs index 72a08361b..6f5ed5e3e 100644 --- a/ui/admin/app/components/targets/target/nav/index.hbs +++ b/ui/admin/app/components/targets/target/nav/index.hbs @@ -7,6 +7,9 @@ {{t 'titles.details'}} + + {{t 'resources.target.workers.title'}} + {{t 'resources.target.host-source.title_plural'}} diff --git a/ui/admin/app/controllers/scopes/scope/targets/index.js b/ui/admin/app/controllers/scopes/scope/targets/index.js index 25923c3e7..194b3202b 100644 --- a/ui/admin/app/controllers/scopes/scope/targets/index.js +++ b/ui/admin/app/controllers/scopes/scope/targets/index.js @@ -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'); + } } diff --git a/ui/admin/app/controllers/scopes/scope/targets/target/add-egress-worker-filter.js b/ui/admin/app/controllers/scopes/scope/targets/target/add-egress-worker-filter.js new file mode 100644 index 000000000..bd8407ea0 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/targets/target/add-egress-worker-filter.js @@ -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; +} diff --git a/ui/admin/app/controllers/scopes/scope/targets/target/add-ingress-worker-filter.js b/ui/admin/app/controllers/scopes/scope/targets/target/add-ingress-worker-filter.js new file mode 100644 index 000000000..e5ded4ee3 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/targets/target/add-ingress-worker-filter.js @@ -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; +} diff --git a/ui/admin/app/controllers/scopes/scope/targets/target/workers.js b/ui/admin/app/controllers/scopes/scope/targets/target/workers.js new file mode 100644 index 000000000..4a4cfac27 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/targets/target/workers.js @@ -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; +} diff --git a/ui/admin/app/router.js b/ui/admin/app/router.js index 3de395831..b165230f3 100644 --- a/ui/admin/app/router.js +++ b/ui/admin/app/router.js @@ -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'); }); diff --git a/ui/admin/app/routes/scopes/scope/targets/target/add-egress-worker-filter.js b/ui/admin/app/routes/scopes/scope/targets/target/add-egress-worker-filter.js new file mode 100644 index 000000000..fe8d1c108 --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/targets/target/add-egress-worker-filter.js @@ -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 {} diff --git a/ui/admin/app/routes/scopes/scope/targets/target/add-ingress-worker-filter.js b/ui/admin/app/routes/scopes/scope/targets/target/add-ingress-worker-filter.js new file mode 100644 index 000000000..92c8af20f --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/targets/target/add-ingress-worker-filter.js @@ -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 {} diff --git a/ui/admin/app/routes/scopes/scope/targets/target/workers.js b/ui/admin/app/routes/scopes/scope/targets/target/workers.js new file mode 100644 index 000000000..adc93f9a9 --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/targets/target/workers.js @@ -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 {} diff --git a/ui/admin/app/styles/app.scss b/ui/admin/app/styles/app.scss index b4492e557..616fae50b 100644 --- a/ui/admin/app/styles/app.scss +++ b/ui/admin/app/styles/app.scss @@ -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; diff --git a/ui/admin/app/templates/scopes/scope/targets/target/add-egress-worker-filter.hbs b/ui/admin/app/templates/scopes/scope/targets/target/add-egress-worker-filter.hbs new file mode 100644 index 000000000..6520bb7ed --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/targets/target/add-egress-worker-filter.hbs @@ -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')}} + + + + + + + + +

+ {{t 'resources.target.workers.add-egress-worker-filter.title'}} + +

+

{{t 'resources.target.workers.add-egress-worker-filter.description'}}

+
+ + + + + +
\ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/targets/target/add-ingress-worker-filter.hbs b/ui/admin/app/templates/scopes/scope/targets/target/add-ingress-worker-filter.hbs new file mode 100644 index 000000000..9e032fcc0 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/targets/target/add-ingress-worker-filter.hbs @@ -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')}} + + + + + + + + + +

+ {{t 'resources.target.workers.add-ingress-worker-filter.title'}} + +

+

{{t + 'resources.target.workers.add-ingress-worker-filter.description' + }}

+
+ + + + + +
\ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/targets/target/workers.hbs b/ui/admin/app/templates/scopes/scope/targets/target/workers.hbs new file mode 100644 index 000000000..2072dc4d9 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/targets/target/workers.hbs @@ -0,0 +1,139 @@ +{{! + Copyright (c) HashiCorp, Inc. + SPDX-License-Identifier: BUSL-1.1 +}} + +{{page-title (t 'resources.target.workers.title')}} + + + + + + + + + + + + + + + + + + + + + + + {{t 'resources.target.workers.description'}} + + + + {{#if (feature-flag 'target-worker-filters-v2-ingress')}} + + <:toggle> +
+ {{t + 'resources.target.workers.accordion-label.ingress-workers' + }} + +
+ + <:content> + {{#if @model.ingress_worker_filter}} + + {{t + 'resources.target.workers.worker-filter.title' + }} + {{t + 'resources.target.workers.worker-filter.description' + }} + + {{else}} + + + + + {{/if}} + +
+ {{/if}} + + <:toggle> +
+ {{t + 'resources.target.workers.accordion-label.egress-workers' + }} + +
+ + <:content> + {{#if @model.egress_worker_filter}} + + {{t + 'resources.target.workers.worker-filter.title' + }} + {{t + 'resources.target.workers.worker-filter.description' + }} + + {{else}} + + + + + {{/if}} + +
+
+
+ +
\ No newline at end of file diff --git a/ui/admin/config/features.js b/ui/admin/config/features.js index 9fd625616..84a2d8d13 100644 --- a/ui/admin/config/features.js +++ b/ui/admin/config/features.js @@ -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, }; diff --git a/ui/admin/tests/acceptance/targets/create-test.js b/ui/admin/tests/acceptance/targets/create-test.js index f5d00c14e..e1be34268 100644 --- a/ui/admin/tests/acceptance/targets/create-test.js +++ b/ui/admin/tests/acceptance/targets/create-test.js @@ -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); diff --git a/ui/admin/tests/acceptance/targets/read-test.js b/ui/admin/tests/acceptance/targets/read-test.js index 8510e69cd..1918d8114 100644 --- a/ui/admin/tests/acceptance/targets/read-test.js +++ b/ui/admin/tests/acceptance/targets/read-test.js @@ -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); diff --git a/ui/admin/tests/acceptance/targets/update-test.js b/ui/admin/tests/acceptance/targets/update-test.js index d8ad53327..fec64216c 100644 --- a/ui/admin/tests/acceptance/targets/update-test.js +++ b/ui/admin/tests/acceptance/targets/update-test.js @@ -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(); diff --git a/ui/admin/tests/acceptance/targets/workers-test.js b/ui/admin/tests/acceptance/targets/workers-test.js new file mode 100644 index 000000000..d792d401d --- /dev/null +++ b/ui/admin/tests/acceptance/targets/workers-test.js @@ -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); + }); +}); diff --git a/ui/admin/tests/integration/components/form/target/worker-filter-test.js b/ui/admin/tests/integration/components/form/target/worker-filter-test.js index a7f9333b1..fe686c3a1 100644 --- a/ui/admin/tests/integration/components/form/target/worker-filter-test.js +++ b/ui/admin/tests/integration/components/form/target/worker-filter-test.js @@ -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``, + hbs``, ); - 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``, + hbs``, ); - 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); }); }); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/targets/index-test.js b/ui/admin/tests/unit/controllers/scopes/scope/targets/index-test.js index 33e273c2e..18d2e277f 100644 --- a/ui/admin/tests/unit/controllers/scopes/scope/targets/index-test.js +++ b/ui/admin/tests/unit/controllers/scopes/scope/targets/index-test.js @@ -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'); + }); }); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/targets/target/add-egress-worker-filter-test.js b/ui/admin/tests/unit/controllers/scopes/scope/targets/target/add-egress-worker-filter-test.js new file mode 100644 index 000000000..0d53aa340 --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/targets/target/add-egress-worker-filter-test.js @@ -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); + }); + }, +); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/targets/target/add-ingress-worker-filter-test.js b/ui/admin/tests/unit/controllers/scopes/scope/targets/target/add-ingress-worker-filter-test.js new file mode 100644 index 000000000..18b2bcfc3 --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/targets/target/add-ingress-worker-filter-test.js @@ -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); + }); + }, +); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/targets/target/workers-test.js b/ui/admin/tests/unit/controllers/scopes/scope/targets/target/workers-test.js new file mode 100644 index 000000000..1735ecc8b --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/targets/target/workers-test.js @@ -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); + }); + }, +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-egress-worker-filter-test.js b/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-egress-worker-filter-test.js new file mode 100644 index 000000000..a04afdca3 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-egress-worker-filter-test.js @@ -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); + }); + }, +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-ingress-worker-filter-test.js b/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-ingress-worker-filter-test.js new file mode 100644 index 000000000..fa2d220a6 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/targets/target/add-ingress-worker-filter-test.js @@ -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); + }); + }, +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/targets/target/workers-test.js b/ui/admin/tests/unit/routes/scopes/scope/targets/target/workers-test.js new file mode 100644 index 000000000..a49b0c693 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/targets/target/workers-test.js @@ -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); + }); +});