vault/ui/app/components/page/methods.ts
Vault Automation 16f98c11ce
[UI] Dismiss Wizards in Playwright Tests (#12699) (#12728)
* adds constants util for wizards and updates service to use WizardId type

* updates wizards to use WIZARD_ID_MAP values

* updates wizard tests to use the service for dismissal

* updates playwright setup to add all wizard ids as dismissed in localStorage

* removes wizard dismissal step from existing playwright tests

* fixes issues accessing owner in beforeEach hooks of namespaces acceptance tests

Co-authored-by: Jordan Reimer <zofskeez@gmail.com>
2026-03-20 15:51:44 -04:00

157 lines
5.1 KiB
TypeScript

/**
* Copyright IBM Corp. 2016, 2025
* SPDX-License-Identifier: BUSL-1.1
*/
import { service } from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import Component from '@glimmer/component';
import { dropTask } from 'ember-concurrency';
import sortObjects from 'vault/utils/sort-objects';
import { WIZARD_ID_MAP } from 'vault/utils/constants/wizard';
import type ApiService from 'vault/services/api';
import type FlashMessageService from 'vault/services/flash-messages';
import type RouterService from '@ember/routing/router-service';
import type WizardService from 'vault/services/wizard';
import type { Breadcrumb } from 'vault/vault/app-types';
import type AuthMethodResource from 'vault/resources/auth/method';
/**
* @module PageAuthMethods
* PageAuthMethods component handles the display and management of authentication methods.
*
* @param {object} model - contains methods array and capabilities
* @param {array} breadcrumbs - breadcrumb navigation items
*/
interface Args {
model: {
methods: AuthMethodResource[];
capabilities: unknown;
};
breadcrumbs: Breadcrumb[];
}
export default class PageAuthMethodsComponent extends Component<Args> {
@service declare readonly api: ApiService;
@service declare readonly flashMessages: FlashMessageService;
@service declare readonly router: RouterService;
@service declare readonly wizard: WizardService;
@tracked authMethodOptions = [];
@tracked selectedAuthType: string | null = null;
@tracked selectedAuthName: string | null = null;
@tracked methodToDisable: AuthMethodResource | null = null;
@tracked shouldRenderIntroModal = false;
wizardId = WIZARD_ID_MAP.authMethods;
// list returned by getter is sorted in template
get authMethodList() {
const { methods } = this.args.model;
// return an options list to filter by engine type, ex: 'kv'
if (this.selectedAuthType) {
// check first if the user has also filtered by name.
// names are individualized across type so you can't have the same name for an aws auth method and userpass.
// this means it's fine to filter by first type and then name or just name.
if (this.selectedAuthName) {
return methods.filter((method) => this.selectedAuthName === method.id);
}
// otherwise filter by auth type
return methods.filter((method) => this.selectedAuthType === method.type);
}
// return an options list to filter by auth name, ex: 'my-userpass'
if (this.selectedAuthName) {
return methods.filter((method) => this.selectedAuthName === method.id);
}
// no filters, return full list
return methods;
}
get authMethodArrayByType() {
const arrayOfAllAuthTypes = this.authMethodList.map((modelObject) => modelObject.type);
// filter out repeated auth types (e.g. [userpass, userpass] => [userpass])
const arrayOfUniqueAuthTypes = [...new Set(arrayOfAllAuthTypes)];
return arrayOfUniqueAuthTypes.map((authType) => ({
name: authType,
id: authType,
}));
}
get authMethodArrayByName() {
return this.authMethodList.map((modelObject) => ({
name: modelObject.id,
id: modelObject.id,
}));
}
get hasOnlyDefaultMethods() {
return this.args.model.methods.length === 1;
}
get showContent() {
// Show when the 1) wizard is not shown OR 2) wizard intro modal is shown
// This ensures the wizard intro modal is shown on top of the list view and the background content is not blank behind the modal
return !this.showWizard || (this.shouldRenderIntroModal && this.wizard.isIntroVisible(this.wizardId));
}
get showIntroButton() {
return this.showContent && this.hasOnlyDefaultMethods;
}
get showWizard() {
return !this.wizard.isDismissed(this.wizardId) && this.hasOnlyDefaultMethods;
}
get showPageHeader() {
return !this.showWizard || this.wizard.isIntroVisible(this.wizardId);
}
@action
filterAuthType([type]: [string]) {
this.selectedAuthType = type;
}
@action
filterAuthName([name]: [string]) {
this.selectedAuthName = name;
}
@action
showIntroPage() {
// Reset the wizard dismissal state to allow re-entering the wizard
this.wizard.reset(this.wizardId);
this.shouldRenderIntroModal = true;
}
@action
async refreshMethodsList() {
this.router.refresh('vault.cluster.access.methods');
}
@dropTask
*disableMethod(method: AuthMethodResource) {
const { type, path } = method;
try {
yield this.api.sys.authDisableMethod(path);
this.flashMessages.success(`The ${type} Auth Method at ${path} has been disabled.`);
this.refreshMethodsList();
} catch (err) {
const { message } = yield this.api.parseError(err);
this.flashMessages.danger(`There was an error disabling Auth Method at ${path}: ${message}.`);
} finally {
this.methodToDisable = null;
}
}
// template helper
sortMethods = (methods: AuthMethodResource[]) => {
// make sure there are methods to sort otherwise slice with throw an error
if (!Array.isArray(methods) || methods.length === 0) return [];
return sortObjects(methods.slice(), 'path');
};
}