diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index c6bc36ef9..046c502d2 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -374,27 +374,31 @@ target: diagram: client: Client any-worker: Any worker - front-line-worker: Front line worker + frontline-worker: Frontline worker hcp-worker: HCP worker egress-worker: Egress worker ingress-worker: Ingress worker host: Host network: Private network filter-explainer: - any-worker: In this configuration, the client will attemt to connect through any client-accessible worker. - egress-worker: In this configuration, the client will attemt to connect through any filtered egress worker. - ingress-worker: In this configuration, the client will attempt to conect through any filtered ingress worker. + any-worker: In this configuration, the client will attempt to connect through any client-accessible worker. + egress-worker: In this configuration, the client will attempt to connect through any filtered egress worker. + ingress-worker: In this configuration, the client will attempt to connect through any filtered ingress worker. hcp-worker: In this configuration, the client will attempt to connect through any HCP-managed worker. - ent-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. - hcp-dual-egress-on: In this configuration, the client will attempt to connect through any HC-managed 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 house through any filtered egress worker. + 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 description: Specify workers that have access to the target (such as within a private network). - filter: - title: Filter - description: Boolean expression. - update_filter: Update Filter + ingress_worker_filter: + title: Ingress worker filter + description: Specify workers Boundary should use to start the route to this target. + actions: + update-filter: Update 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 76c78bb02..b509150e0 100644 --- a/ui/admin/app/components/form/target/details/index.hbs +++ b/ui/admin/app/components/form/target/details/index.hbs @@ -176,6 +176,7 @@ {{#if (feature-flag 'target-worker-filters-v2')}} + {{/if}} {{/if}} + + {{#if this.showTargetFilters}} + {{#if this.workerDiagramHCPDualFilter}} + + {{else if this.workerDiagramDualFilter}} + + {{else}} + + {{/if}} - {{#if this.showEgressFilter}} - - + {{#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}} - - {{#if @model.isNew}} - - - - - - {{#if @model.errors.egress_worker_filter}} - - {{#each @model.errors.egress_worker_filter as |error|}} - {{error.message}} - {{/each}} - - {{/if}} - - - {{/if}} - + {{/if}} + {{else}} @@ -326,4 +320,5 @@ @cancelText={{t 'actions.cancel'}} /> {{/if}} + \ No newline at end of file diff --git a/ui/admin/app/components/form/target/details/index.js b/ui/admin/app/components/form/target/details/index.js index 966ee18bc..aad39f007 100644 --- a/ui/admin/app/components/form/target/details/index.js +++ b/ui/admin/app/components/form/target/details/index.js @@ -2,6 +2,7 @@ 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. const types = [...TYPES_TARGET].reverse(); @@ -9,13 +10,13 @@ const icons = { ssh: 'terminal-screen', tcp: 'network', }; - export default class FormTargetComponent extends Component { // =properties - @tracked egressWorkerFilterEnabled = - this.args.model.egress_worker_filter?.length; + @tracked egressWorkerFilterEnabled = this.args.model.egress_worker_filter; + @tracked ingressWorkerFilterEnabled = this.args.model.ingress_worker_filter; - // =properties + // =services + @service features; /** * maps resource type with icon * @type {object} @@ -49,28 +50,56 @@ export default class FormTargetComponent extends Component { * @type {boolean} */ get showUpdateWorkerFilterButton() { - return this.args.model.worker_filter?.length; + return this.args.model.worker_filter; } - get showEgressFilter() { - return !this.args.model.worker_filter?.length && !this.args.model.isNew; + /** + * determines when the filters should be shown + * @type {boolean} + */ + get showTargetFilters() { + return !this.args.model.worker_filter; + } + + //note: these getters will go away when we refactor worker diagram + /** + * determines when the enterprise dual filter diagrams should be shown + * @type {boolean} + */ + get workerDiagramDualFilter() { + return this.features.isEnabled('target-worker-filters-v2-ingress'); + } + /** + * determines when the hcp dual filter diagrams should be shown + * @type {boolean} + */ + get workerDiagramHCPDualFilter() { + return this.features.isEnabled('target-worker-filters-v2-hcp'); } //actions @action - toggleEgressWorkerFilter() { + toggleEgressFilter() { this.egressWorkerFilterEnabled = !this.egressWorkerFilterEnabled; if (!this.egressWorkerFilterEnabled) { this.args.model.egress_worker_filter = ''; } } - // =actions + @action + toggleIngressFilter() { + this.ingressWorkerFilterEnabled = !this.ingressWorkerFilterEnabled; + if (!this.ingressWorkerFilterEnabled) { + this.args.model.ingress_worker_filter = ''; + } + } @action migrateWorkerFilters() { this.egressWorkerFilterEnabled = true; + this.ingressWorkerFilterEnabled = true; // When update is clicked, copy worker filter value into egress 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 = ''; } @@ -82,7 +111,9 @@ export default class FormTargetComponent extends Component { cancel() { this.args.cancel(); // Reset the tracked variable for toggles after rollback - this.egressWorkerFilterEnabled = - this.args.model.egress_worker_filter?.length; + + this.egressWorkerFilterEnabled = this.args.model.egress_worker_filter; + + this.ingressWorkerFilterEnabled = this.args.model.ingress_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 d10c67b0a..f1a7f5cb1 100644 --- a/ui/admin/app/components/form/target/worker-filter/index.hbs +++ b/ui/admin/app/components/form/target/worker-filter/index.hbs @@ -1,8 +1,8 @@ -
+
- {{t - (concat 'resources.target.workers.' @name '.filter.title') - }} - {{t - (concat 'resources.target.workers.' @name '.filter.description') - }} + {{t 'resources.target.workers.filter.title'}} + + {{t 'resources.target.workers.filter.description'}} {{t 'actions.learn-more'}} diff --git a/ui/admin/app/components/worker-diagram/dual-filter/hcp/index.hbs b/ui/admin/app/components/worker-diagram/dual-filter/hcp/index.hbs index e42afa1d1..456646ee4 100644 --- a/ui/admin/app/components/worker-diagram/dual-filter/hcp/index.hbs +++ b/ui/admin/app/components/worker-diagram/dual-filter/hcp/index.hbs @@ -21,7 +21,9 @@
- {{t 'resources.target.workers.filter-explainer.hcp-dual-egress-on'}} + {{t + 'resources.target.workers.filter-explainer.dual-egress-on-ingress-on' + }}
{{else if @ingressFilter}} @@ -56,7 +58,7 @@ {{#if (feature-flag 'target-worker-filters-v2-hcp')}} {{t 'resources.target.workers.diagram.hcp-worker'}} {{else}} - {{t 'resources.target.workers.diagram.front-line-worker'}} + {{t 'resources.target.workers.diagram.frontline-worker'}} {{/if}}
- {{t 'resources.target.workers.filter-explainer.egress-on'}} + {{t 'resources.target.workers.filter-explainer.hcp-dual-egress-on'}}
{{else}} diff --git a/ui/admin/app/components/worker-diagram/dual-filter/index.hbs b/ui/admin/app/components/worker-diagram/dual-filter/index.hbs index 16a51bde6..c3e8ada91 100644 --- a/ui/admin/app/components/worker-diagram/dual-filter/index.hbs +++ b/ui/admin/app/components/worker-diagram/dual-filter/index.hbs @@ -49,7 +49,7 @@ {{t 'resources.target.workers.diagram.client'}} - {{t 'resources.target.workers.diagram.front-line-worker'}} + {{t 'resources.target.workers.diagram.frontline-worker'}}
- {{t 'resources.target.workers.filter-explainer.egress-worker'}} + {{t 'resources.target.workers.filter-explainer.dual-egress-on'}}
{{else}} diff --git a/ui/admin/tests/acceptance/targets/create-test.js b/ui/admin/tests/acceptance/targets/create-test.js index d5136da91..652b1f485 100644 --- a/ui/admin/tests/acceptance/targets/create-test.js +++ b/ui/admin/tests/acceptance/targets/create-test.js @@ -136,6 +136,7 @@ module('Acceptance | targets | create', function (hooks) { 'random filter' ); }); + test('can create type `tcp` when `target-worker-filters-v2` is disabled', async function (assert) { featuresService.disable('target-worker-filters-v2'); assert.expect(4); @@ -161,6 +162,7 @@ module('Acceptance | targets | create', function (hooks) { 'random filter' ); }); + test('can create type `tcp` when `target-worker-filters-v2` is enabled', async function (assert) { featuresService.enable('target-worker-filters-v2'); assert.expect(4); @@ -188,6 +190,42 @@ module('Acceptance | targets | create', function (hooks) { '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('target-worker-filters-v2'); + featuresService.enable('target-worker-filters-v2-ingress'); + assert.expect(4); + 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('[type="submit"]'); + + 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) { assert.expect(1); await visit(urls.newTarget); diff --git a/ui/admin/tests/integration/components/form/target/details-test.js b/ui/admin/tests/integration/components/form/target/details-test.js new file mode 100644 index 000000000..599aeaab1 --- /dev/null +++ b/ui/admin/tests/integration/components/form/target/details-test.js @@ -0,0 +1,57 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, getContext } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; +import { setupIntl } from 'ember-intl/test-support'; + +module('Integration | Component | form/target/details', function (hooks) { + setupRenderingTest(hooks); + setupIntl(hooks); + + let featuresService; + + hooks.beforeEach(function () { + const { owner } = getContext(); + featuresService = owner.lookup('service:features'); + this.model = { type: 'ssh' }; + this.submit = () => {}; + this.cancel = () => {}; + this.changeType = () => {}; + }); + + test('shows the correct worker diagram when `target-worker-filters-v2` is enabled', async function (assert) { + featuresService.enable('target-worker-filters-v2'); + featuresService.disable('target-worker-filters-v2-ingress'); + featuresService.disable('target-worker-filters-v2-hcp'); + assert.expect(1); + await render( + hbs`` + ); + + assert.dom('[data-test-single-filter-egress-off]').isVisible(); + }); + + test('shows the correct worker diagram when `target-worker-filters-v2` and `target-worker-filters-v2-ingress` is enabled', async function (assert) { + featuresService.enable('target-worker-filters-v2'); + featuresService.enable('target-worker-filters-v2-ingress'); + featuresService.disable('target-worker-filters-v2-hcp'); + assert.expect(1); + await render( + hbs`` + ); + + assert.dom('[data-test-dual-filters]').isVisible(); + }); + + test('shows the correct worker diagram when `target-worker-filters-v2` and `target-worker-filters-v2-ingress` and `target-worker-filters-v2-hcp` is enabled', async function (assert) { + featuresService.enable('target-worker-filters-v2'); + featuresService.enable('target-worker-filters-v2-ingress'); + featuresService.enable('target-worker-filters-v2-hcp'); + assert.expect(1); + await render( + hbs`` + ); + + assert.dom('[data-test-dual-filters-hcp]').isVisible(); + }); +}); 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 new file mode 100644 index 000000000..1cd0f4652 --- /dev/null +++ b/ui/admin/tests/integration/components/form/target/worker-filter-test.js @@ -0,0 +1,34 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; +import { setupIntl } from 'ember-intl/test-support'; + +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) { + assert.expect(2); + this.onChange = () => {}; + this.toggleAction = () => {}; + await render( + hbs`` + ); + + assert.dom('.hds-form-toggle').isVisible(); + assert.dom('.hds-form-text-input').doesNotExist(); + }); + + test('it renders a toggle field and text input field when "toggleEnabled" is true', async function (assert) { + assert.expect(2); + this.onChange = () => {}; + this.toggleAction = () => {}; + await render( + hbs`` + ); + + assert.dom('.hds-form-toggle').isVisible(); + assert.dom('.hds-form-text-input').isVisible(); + }); +});