Dan Rivera fbb446f974
UI: Custom login settings views (#30592)
* UI: Adding routes for custom login settings  (#30404)

* adding route block

* adding to side nav

* jk its diff

* adding TODO, adding empty files

* UI: Adding List view component for custom login settings (#30459)

* first pass setting up list view

* style fix

* messing with routes

* fix

* undo

* using mock data

* renaming

* [UI] API Service Error Parsing (#30454)

* adds error parsing method to api service

* replaces apiErrorMessage util instances with api service parseError

* removes apiErrorMessage util and tests

* removes ApiError type

* fixes issue in isLocalStorageSupported error handling

* remove cli folder (#30458)

* [DOCS] Add explicit links to older release notes (#30461)

* Add explicit links to older release notes

* remove domain from URLs

* add link to important changes as well

* bump timeout for single flaky test (#30460)

* adds list response parsing to api service (#30455)

* update versions, and replace summary in important changes section (#30471)

* Update CHANGELOG.md (#30456)

* UI: Update Enterprise Client Count Datepicker (#30349)

* date picker changes (mostly) for ent client counts

* Move edit modal button + padding

* only show start time in dropdown and add changelog

* remove unused variable and update toggle width

* remove unnecessary period end dates

* tidy

* update tests

* Update changelog/30349.txt

Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>

* improve date logic

* add export button back in, re-arrange header, update dropdown

* update when date is shown

* add default for retention months

* update tests and remove unnecessary tests

* account for retention months that are not whole periods

* update logic to show end date on export modal

* update exported file name

---------

Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>

* Prevent early-exit of plugin reload (#30329)

* update to use util, update to this.cap

---------

Co-authored-by: Jordan Reimer <zofskeez@gmail.com>
Co-authored-by: Sarah Chavis <62406755+schavis@users.noreply.github.com>
Co-authored-by: Angel Garbarino <Monkeychip@users.noreply.github.com>
Co-authored-by: Ellie <ellie.sterner@hashicorp.com>
Co-authored-by: Tony Wittinger <anwittin@users.noreply.github.com>
Co-authored-by: lane-wetmore <lane.wetmore@hashicorp.com>
Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
Co-authored-by: kpcraig <3031348+kpcraig@users.noreply.github.com>

* UI: Create details component for custom login rules (#30530)

* setup

* adding to view

* fixing table keys

* add breadcrumbs

* fixes

* removing default vals

* pr comments

* adding delete button to toolbar

* adding delete functionality

* reorder and fix error handling

* updating api call, adding error template, fixing selectors

* remove param

* UI: Updating visibility attr on auth config to be a toggle with direct login link (#30548)

* updating visibility attr to be a toggle, adding link placeholder

* update test

* test fix pt2

* updating to build link + copy button

* updates

* use the right word

* using hds text

* updating helper text, path

* use encode directly

* updating capabilities check, creating test files, empty state

* UI: Update custom login to use api instead of mirage (#30640)

* updating to use api, removing store

* temp test fix

* fixes on types, remove test funcs

* fix assertion

* adding tests

* updating test

* adding to tests

* stub delete?

* removing stubs, updating tests

* fixes

* moving cmd placement, updating inheritance

* adding changelog

* fix changelog

* pr comments

* update check & update test

* remove empty state block

* remove comment

* Revert "remove empty state block"

This reverts commit ce34d8c76fea3b43bb96c6acd342a5ba0471f441.

* remove the right empty state

---------

Co-authored-by: Jordan Reimer <zofskeez@gmail.com>
Co-authored-by: Sarah Chavis <62406755+schavis@users.noreply.github.com>
Co-authored-by: Angel Garbarino <Monkeychip@users.noreply.github.com>
Co-authored-by: Ellie <ellie.sterner@hashicorp.com>
Co-authored-by: Tony Wittinger <anwittin@users.noreply.github.com>
Co-authored-by: lane-wetmore <lane.wetmore@hashicorp.com>
Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
Co-authored-by: kpcraig <3031348+kpcraig@users.noreply.github.com>
2025-05-22 14:17:14 -04:00

202 lines
7.2 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { click, fillIn, render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { methods } from 'vault/helpers/mountable-auth-methods';
const userLockoutSupported = ['approle', 'ldap', 'userpass'];
const userLockoutUnsupported = methods()
.map((m) => m.type)
.filter((m) => !userLockoutSupported.includes(m));
module('Integration | Component | auth-config-form options', function (hooks) {
setupRenderingTest(hooks);
setupMirage(hooks);
hooks.beforeEach(function () {
this.owner.lookup('service:flash-messages').registerTypes(['success']);
this.router = this.owner.lookup('service:router');
this.store = this.owner.lookup('service:store');
this.createModel = (path, type) => {
this.model = this.store.createRecord('auth-method', { path, type });
this.model.set('config', this.store.createRecord('mount-config'));
};
});
for (const type of userLockoutSupported) {
test(`it submits data correctly for ${type} method (supports user_lockout_config)`, async function (assert) {
assert.expect(3);
const path = `my-${type}-auth/`;
this.createModel(path, type);
this.router.reopen({
transitionTo() {
return {
followRedirects() {
assert.ok(true, `saving ${type} calls transitionTo on save`);
},
};
},
});
this.server.post(`sys/mounts/auth/${path}/tune`, (schema, req) => {
const payload = JSON.parse(req.requestBody);
const expected = {
default_lease_ttl: '30s',
listing_visibility: 'unauth',
token_type: 'default-batch',
user_lockout_config: {
lockout_threshold: '7',
lockout_duration: '600s',
lockout_counter_reset: '5s',
lockout_disable: true,
},
};
assert.propEqual(payload, expected, `${type} method payload contains tune parameters`);
return { payload };
});
await render(hbs`<AuthConfigForm::Options @model={{this.model}} />`);
assert.dom('[data-test-user-lockout-section]').hasText('User lockout configuration');
await click(GENERAL.toggleInput('toggle-config.listingVisibility'));
await fillIn(GENERAL.inputByAttr('config.tokenType'), 'default-batch');
await click(GENERAL.ttl.toggle('Default Lease TTL'));
await fillIn(GENERAL.ttl.input('Default Lease TTL'), '30');
await fillIn(GENERAL.inputByAttr('config.lockoutThreshold'), '7');
await click(GENERAL.ttl.toggle('Lockout duration'));
await fillIn(GENERAL.ttl.input('Lockout duration'), '10');
await fillIn(
`${GENERAL.inputByAttr('config.lockoutDuration')} ${GENERAL.selectByAttr('ttl-unit')}`,
'm'
);
await click(GENERAL.ttl.toggle('Lockout counter reset'));
await fillIn(GENERAL.ttl.input('Lockout counter reset'), '5');
await click(GENERAL.inputByAttr('config.lockoutDisable'));
await click('[data-test-save-config]');
});
}
for (const type of userLockoutUnsupported) {
if (type === 'token') return; // separate test below because does not include tokenType field
test(`it submits data correctly for ${type} auth method`, async function (assert) {
assert.expect(7);
const path = `my-${type}-auth/`;
this.createModel(path, type);
this.router.reopen({
transitionTo() {
return {
followRedirects() {
assert.ok(true, `saving ${type} calls transitionTo on save`);
},
};
},
});
this.server.post(`sys/mounts/auth/${path}/tune`, (schema, req) => {
const payload = JSON.parse(req.requestBody);
const expected = {
default_lease_ttl: '30s',
listing_visibility: 'unauth',
token_type: 'default-batch',
};
assert.propEqual(payload, expected, `${type} method payload contains tune parameters`);
return { payload };
});
await render(hbs`<AuthConfigForm::Options @model={{this.model}} />`);
assert
.dom('[data-test-user-lockout-section]')
.doesNotExist(`${type} method does not render user lockout section`);
await click(GENERAL.toggleInput('toggle-config.listingVisibility'));
await fillIn(GENERAL.inputByAttr('config.tokenType'), 'default-batch');
await click(GENERAL.ttl.toggle('Default Lease TTL'));
await fillIn(GENERAL.ttl.input('Default Lease TTL'), '30');
assert
.dom(GENERAL.inputByAttr('config.lockoutThreshold'))
.doesNotExist(`${type} method does not render lockout threshold`);
assert
.dom(GENERAL.ttl.toggle('Lockout duration'))
.doesNotExist(`${type} method does not render lockout duration `);
assert
.dom(GENERAL.ttl.toggle('Lockout counter reset'))
.doesNotExist(`${type} method does not render lockout counter reset`);
assert
.dom(GENERAL.inputByAttr('config.lockoutDisable'))
.doesNotExist(`${type} method does not render lockout disable`);
await click('[data-test-save-config]');
});
}
test('it submits data correctly for token auth method', async function (assert) {
assert.expect(8);
const type = 'token';
const path = `my-${type}-auth/`;
this.createModel(path, type);
this.router.reopen({
transitionTo() {
return {
followRedirects() {
assert.ok(true, `saving token calls transitionTo on save`);
},
};
},
});
this.server.post(`sys/mounts/auth/${path}/tune`, (schema, req) => {
const payload = JSON.parse(req.requestBody);
const expected = {
default_lease_ttl: '30s',
listing_visibility: 'unauth',
};
assert.propEqual(payload, expected, `${type} method payload contains tune parameters`);
return { payload };
});
await render(hbs`<AuthConfigForm::Options @model={{this.model}} />`);
assert
.dom(GENERAL.inputByAttr('config.tokenType'))
.doesNotExist('does not render tokenType for token auth method');
await click(GENERAL.toggleInput('toggle-config.listingVisibility'));
await click(GENERAL.ttl.toggle('Default Lease TTL'));
await fillIn(GENERAL.ttl.input('Default Lease TTL'), '30');
assert.dom('[data-test-user-lockout-section]').doesNotExist('token does not render user lockout section');
assert
.dom(GENERAL.inputByAttr('config.lockoutThreshold'))
.doesNotExist('token method does not render lockout threshold');
assert
.dom(GENERAL.ttl.toggle('Lockout duration'))
.doesNotExist('token method does not render lockout duration ');
assert
.dom(GENERAL.ttl.toggle('Lockout counter reset'))
.doesNotExist('token method does not render lockout counter reset');
assert
.dom(GENERAL.inputByAttr('config.lockoutDisable'))
.doesNotExist('token method does not render lockout disable');
await click('[data-test-save-config]');
});
});