Jordan Reimer d8ecd066b8
Copy [UI] Ember Data Migration - Auth Method Configs into main (#9000) (#9099)
* updates auth method options route to use form and api client

* updates auth method config and section routes to use api client and open api form

* updates display attrs for auth method configs

* fixes plugin identity util fields tests

* fixes js lint error

* updates enable-tune-form tests

* hides specific form field for jwt/oidc auth config types

* Revert "updates display attrs for auth method configs"

This reverts commit 5d382f79276f56b3fdbe64fcbc9c8365c5f4b421.

* Revert "fixes plugin identity util fields tests"

This reverts commit 6d4acbe3228c796745f2dea6279c1540bb053c62.

* fixes config section test

* bumps api client version

* updates auth config form options component to use proper endpoint

* fixes enable tune form tests

* fixes auth config form options tests

* fixes type errors in snapshot-manage component

* updates recover_source_path arg to undefined so it is not included in the query params

* fixes remaining test failures related to user_lockout_config

---------

Co-authored-by: Vault Automation <github-team-secure-vault-core@hashicorp.com>
2025-09-03 17:11:41 -07:00
..

Background

The Form class was created as a replacement for form related functionality that previously lived in Ember Data models. Given that the FormField component was designed around the metadata that was defined on model attributes, it was imperative to preserve this pattern while moving the functionality to a dependency-free native javascript solution.

Usage

The Form class is intended to be extended by a class that represents a particular form in the application.

export default class MyForm extends Form {
  declare data: MyFormData;

  // define form fields
  name = new FormField('name', 'string');
  secret = new FormField('secret', 'string', {
    editType: 'kv',
    keyPlaceholder: 'Secret key',
    valuePlaceholder: 'Secret value',
    label: 'Secret (kv pairs)',
    isSingleRow: true,
    allowWhiteSpace: true,
  });

  // define validations
  validations: Validations = {
    name: [{ type: 'presence', message: 'Name is required.' }],
  };

  // if serialization is needed override toJSON method
  toJSON() {
    const trimmedName = this.data.name.trim();
    return super.toJSON({ ...this.data, name: trimmedName });
  }
}

Form data is set to the data object on the class and can be initialized with defaults or server data when editing by passing an object into the constructor.

// create route
model() {
  return new MyForm({ name: 'Default name' });
}

// edit route
async model() {
  const data = await this.api.fetchSomeData();
  return new MyForm(data);
}

The route model (MyForm instance) can be passed into the form component in the same manner as an Ember Data model and the formFields can be looped to render FormField components.

{{#each @form.formFields as |field|}}
  <FormField @attr={{field}} @model={{@form}} @modelValidations={{this.validations}} />
{{/each}}

To validate the form and access the data use the toJSON method.

// save method of form component
async save() {
  try {
    const { isValid, state, invalidFormMessage, data } = this.args.form.toJSON();
    this.validations = isValid ? null : state;
    this.invalidFormMessage = invalidFormMessage;

    if (isValid) {
      await this.api.saveTheForm(data);
      this.flashMessages.success('It worked');
      this.router.transitionTo('another.route');
    }
  } catch(error) {
    const { message } = await this.api.parseError(error);
    this.errorMessage = message;
  }
}