From f58990677f5fd57feddc11ce1d5649ef14f234d2 Mon Sep 17 00:00:00 2001 From: claire bontempo <68122737+hellobontempo@users.noreply.github.com> Date: Fri, 18 Nov 2022 17:29:04 -0800 Subject: [PATCH] UI: Implement new policy SS + modal designs (#17749) * refactor ss+modal to accept multiple models * create policy form * cleanup and fix test * add tabs to policy modal form * add search select with modal to entity form * update group form; * allow modal to fit-content * add changelog * add check for policy create ability * add id so tests pass * filter out root option * fix test * add cleanup method * add ACL policy link * cleanup from comments * refactor sending action to parent * refactor, data down actions up! * cleanup comments * form field refactor * add ternary to options * update tests * Remodel component structure for clearer logic Includes fixing the wizard * address comments * cleanup args * refactor inline oidc assignment form * add line break * cleanup comments * fix tests * add policy template to ss+modal test * cleanup =true from test * final cleanup!!!!!! * actual final cleanup * fix typo, please be done Co-authored-by: Chelsea Shaw <82459713+hashishaw@users.noreply.github.com> --- changelog/17749.txt | 3 + ui/app/components/modal-form/FYI.md | 3 + .../modal-form/oidc-assignment-template.hbs | 1 + .../modal-form/oidc-assignment-template.js | 36 +++ .../components/modal-form/policy-template.hbs | 77 +++++ .../components/modal-form/policy-template.js | 82 ++++++ ui/app/components/oidc/assignment-form.js | 7 +- ui/app/components/oidc/client-form.js | 8 +- ui/app/components/policy-form.hbs | 109 +++++++ ui/app/components/policy-form.js | 69 +++++ ui/app/components/ui-wizard.js | 2 + .../vault/cluster/policies/create.js | 20 -- .../controllers/vault/cluster/policy/edit.js | 27 +- ui/app/mixins/policy-edit-controller.js | 49 ---- ui/app/models/identity/entity.js | 8 +- ui/app/models/identity/group.js | 8 +- ui/app/routes/vault/cluster/policy/edit.js | 11 +- ui/app/routes/vault/cluster/policy/show.js | 7 + ui/app/styles/components/modal.scss | 1 + .../components/identity/edit-form.hbs | 29 +- .../components/oidc/assignment-form.hbs | 29 -- .../templates/components/oidc/client-form.hbs | 4 +- ui/app/templates/components/ui-wizard.hbs | 1 + .../components/wizard/policies-delete.hbs | 6 +- .../components/wizard/policies-details.hbs | 2 +- .../oidc/assignments/assignment/edit.hbs | 19 ++ .../access/oidc/assignments/create.hbs | 19 ++ .../vault/cluster/policies/create.hbs | 72 +---- .../templates/vault/cluster/policy/edit.hbs | 47 +-- ui/lib/core/addon/components/form-field.hbs | 26 +- ui/lib/core/addon/components/form-field.js | 23 +- .../components/search-select-with-modal.hbs | 53 ++-- .../components/search-select-with-modal.js | 253 ++++++++--------- .../core/addon/components/search-select.hbs | 6 +- .../addon/templates/components/select.hbs | 1 + .../oidc-config/clients-assignments-test.js | 4 +- ui/tests/acceptance/policies-acl-old-test.js | 7 +- .../components/oidc/assignment-form-test.js | 10 +- .../components/oidc/client-form-test.js | 5 +- .../components/policy-form-test.js | 204 +++++++++++++ .../search-select-with-modal-test.js | 268 ++++++++++++------ 41 files changed, 1120 insertions(+), 496 deletions(-) create mode 100644 changelog/17749.txt create mode 100644 ui/app/components/modal-form/FYI.md create mode 100644 ui/app/components/modal-form/oidc-assignment-template.hbs create mode 100644 ui/app/components/modal-form/oidc-assignment-template.js create mode 100644 ui/app/components/modal-form/policy-template.hbs create mode 100644 ui/app/components/modal-form/policy-template.js create mode 100644 ui/app/components/policy-form.hbs create mode 100644 ui/app/components/policy-form.js delete mode 100644 ui/app/controllers/vault/cluster/policies/create.js delete mode 100644 ui/app/mixins/policy-edit-controller.js create mode 100644 ui/tests/integration/components/policy-form-test.js diff --git a/changelog/17749.txt b/changelog/17749.txt new file mode 100644 index 000000000..54c88a800 --- /dev/null +++ b/changelog/17749.txt @@ -0,0 +1,3 @@ +```release-note:feature +ui: Add inline policy creation when creating an identity entity or group +``` diff --git a/ui/app/components/modal-form/FYI.md b/ui/app/components/modal-form/FYI.md new file mode 100644 index 000000000..35b65b1b4 --- /dev/null +++ b/ui/app/components/modal-form/FYI.md @@ -0,0 +1,3 @@ +These templates parent form components that render within a modal to create inline items via SearchSelectWithModal. +The modal opens when a user searches for an item that doesn't exist and clicks 'No results found for "${term}". Click here to create it.' +The templates are rendered using the {{component}} helper in 'search-select-with-modal.hbs' and are responsible for creating the model passed to the form. diff --git a/ui/app/components/modal-form/oidc-assignment-template.hbs b/ui/app/components/modal-form/oidc-assignment-template.hbs new file mode 100644 index 000000000..8af71a03f --- /dev/null +++ b/ui/app/components/modal-form/oidc-assignment-template.hbs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ui/app/components/modal-form/oidc-assignment-template.js b/ui/app/components/modal-form/oidc-assignment-template.js new file mode 100644 index 000000000..f99bbbd62 --- /dev/null +++ b/ui/app/components/modal-form/oidc-assignment-template.js @@ -0,0 +1,36 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; +import { inject as service } from '@ember/service'; +import { tracked } from '@glimmer/tracking'; + +/** + * @module ModalForm::OidcAssignmentTemplate + * ModalForm::OidcAssignmentTemplate components render within a modal and create a model using the input from the search select. The model is passed to the oidc/assignment-form. + * + * @example + * + * ``` + * @callback onCancel - callback triggered when cancel button is clicked + * @callback onSave - callback triggered when save button is clicked + * @param {string} nameInput - the name of the newly created assignment + */ + +export default class OidcAssignmentTemplate extends Component { + @service store; + @tracked assignment = null; // model record passed to oidc/assignment-form + + constructor() { + super(...arguments); + this.assignment = this.store.createRecord('oidc/assignment', { name: this.args.nameInput }); + } + + @action onSave(assignmentModel) { + this.args.onSave(assignmentModel); + // Reset component assignment for next use + this.assignment = null; + } +} diff --git a/ui/app/components/modal-form/policy-template.hbs b/ui/app/components/modal-form/policy-template.hbs new file mode 100644 index 000000000..7c752a5ab --- /dev/null +++ b/ui/app/components/modal-form/policy-template.hbs @@ -0,0 +1,77 @@ +{{#if this.policy.policyType}} + +{{/if}} +{{#if this.showExamplePolicy}} +
+ {{#if (eq this.policy.policyType "acl")}} +

+ ACL Policies are written in Hashicorp Configuration Language ( + HCL + ) or JSON and describe which paths in Vault a user or machine is allowed to access. Here is an example policy: +

+ {{else}} +

+ Role Governing Policies (RGPs) are tied to client tokens or identities which is similar to + ACL policies. + They use + Sentinel + as a language framework to enable fine-grained policy decisions. +

+

+ Here is an example policy that uses RGP to restrict access to the + admin + policy such that a user named James or has the + Team Lead + role can manage the + admin + policy: +

+ {{/if}} +
+ +{{else}} + + + + {{/if}} +
+ {{#if @model.isNew}} + + + +
+
+ + +
+
+
+ {{#if this.showFileUpload}} + + {{else}} + + {{/if}} + {{else}} + {{! EDITING - no file upload toggle}} + + {{/if}} +
+ {{#each @model.additionalAttrs as |attr|}} + + {{/each}} + +
+

+ More information about + {{uppercase @model.policyType}} + policies can be found + + here. + +

+
+
+
+ + +
+
+ \ No newline at end of file diff --git a/ui/app/components/policy-form.js b/ui/app/components/policy-form.js new file mode 100644 index 000000000..6b367cea1 --- /dev/null +++ b/ui/app/components/policy-form.js @@ -0,0 +1,69 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; +import { inject as service } from '@ember/service'; +import { task } from 'ember-concurrency'; +import trimRight from 'vault/utils/trim-right'; +import { tracked } from '@glimmer/tracking'; + +/** + * @module PolicyForm + * PolicyForm components are the forms to create and edit all types of policies. This is only the form, not the outlying layout, and expects that the form model is passed from the parent. + * + * @example + * + * ``` + * @callback onCancel - callback triggered when cancel button is clicked + * @callback onSave - callback triggered when save button is clicked. Passes saved model + * @param {object} model - ember data model from createRecord + */ + +export default class PolicyFormComponent extends Component { + @service flashMessages; + + @tracked errorBanner = ''; + @tracked file = null; + @tracked showFileUpload = false; + + @task + *save(event) { + event.preventDefault(); + try { + const { name, policyType, isNew } = this.args.model; + yield this.args.model.save(); + this.flashMessages.success( + `${policyType.toUpperCase()} policy "${name}" was successfully ${isNew ? 'created' : 'updated'}.` + ); + this.args.onSave(this.args.model); + } catch (error) { + const message = error.errors ? error.errors.join('. ') : error.message; + this.errorBanner = message; + } + } + + @action + setModelName({ target }) { + this.args.model.name = target.value.toLowerCase(); + } + + @action + setPolicyFromFile(index, fileInfo) { + const { value, fileName } = fileInfo; + this.args.model.policy = value; + if (!this.args.model.name) { + const trimmedFileName = trimRight(fileName, ['.json', '.txt', '.hcl', '.policy']); + this.args.model.name = trimmedFileName.toLowerCase(); + } + this.showFileUpload = false; + } + + @action + cancel() { + const method = this.args.model.isNew ? 'unloadRecord' : 'rollbackAttributes'; + this.args.model[method](); + this.args.onCancel(); + } +} diff --git a/ui/app/components/ui-wizard.js b/ui/app/components/ui-wizard.js index 7a7341f05..009654952 100644 --- a/ui/app/components/ui-wizard.js +++ b/ui/app/components/ui-wizard.js @@ -7,6 +7,7 @@ export default Component.extend({ classNames: ['ui-wizard-container'], wizard: service(), auth: service(), + router: service(), shouldRender: or('auth.currentToken', 'wizard.showWhenUnauthenticated'), currentState: alias('wizard.currentState'), @@ -16,6 +17,7 @@ export default Component.extend({ componentState: alias('wizard.componentState'), nextFeature: alias('wizard.nextFeature'), nextStep: alias('wizard.nextStep'), + currentRouteName: alias('router.currentRouteName'), actions: { dismissWizard() { diff --git a/ui/app/controllers/vault/cluster/policies/create.js b/ui/app/controllers/vault/cluster/policies/create.js deleted file mode 100644 index 69e22f68f..000000000 --- a/ui/app/controllers/vault/cluster/policies/create.js +++ /dev/null @@ -1,20 +0,0 @@ -import Controller from '@ember/controller'; -import trimRight from 'vault/utils/trim-right'; -import PolicyEditController from 'vault/mixins/policy-edit-controller'; - -export default Controller.extend(PolicyEditController, { - showFileUpload: false, - file: null, - actions: { - setPolicyFromFile(index, fileInfo) { - const { value, fileName } = fileInfo; - const model = this.model; - model.set('policy', value); - if (!model.get('name')) { - const trimmedFileName = trimRight(fileName, ['.json', '.txt', '.hcl', '.policy']); - model.set('name', trimmedFileName); - } - this.set('showFileUpload', false); - }, - }, -}); diff --git a/ui/app/controllers/vault/cluster/policy/edit.js b/ui/app/controllers/vault/cluster/policy/edit.js index 8a14b3c90..927e70ea4 100644 --- a/ui/app/controllers/vault/cluster/policy/edit.js +++ b/ui/app/controllers/vault/cluster/policy/edit.js @@ -1,4 +1,27 @@ import Controller from '@ember/controller'; -import PolicyEditController from 'vault/mixins/policy-edit-controller'; +import { action } from '@ember/object'; +import { inject as service } from '@ember/service'; -export default Controller.extend(PolicyEditController); +export default class PolicyEditController extends Controller { + @service router; + @service flashMessages; + @service wizard; + + @action + async deletePolicy() { + const { policyType, name } = this.model; + try { + await this.model.destroyRecord(); + this.flashMessages.success(`${policyType.toUpperCase()} policy "${name}" was successfully deleted.`); + this.router.transitionTo('vault.cluster.policies', policyType); + if (this.wizard.featureState === 'delete') { + this.wizard.transitionFeatureMachine('delete', 'CONTINUE', policyType); + } + } catch (error) { + this.model.rollbackAttributes(); + const errors = error.errors ? error.errors.join('. ') : error.message; + const message = `There was an error deleting the ${policyType.toUpperCase()} policy "${name}": ${errors}.`; + this.flashMessages.danger(message); + } + } +} diff --git a/ui/app/mixins/policy-edit-controller.js b/ui/app/mixins/policy-edit-controller.js deleted file mode 100644 index e56d6a318..000000000 --- a/ui/app/mixins/policy-edit-controller.js +++ /dev/null @@ -1,49 +0,0 @@ -import { inject as service } from '@ember/service'; -import Mixin from '@ember/object/mixin'; - -export default Mixin.create({ - flashMessages: service(), - wizard: service(), - actions: { - deletePolicy(model) { - const policyType = model.get('policyType'); - const name = model.get('name'); - const flash = this.flashMessages; - model - .destroyRecord() - .then(() => { - flash.success(`${policyType.toUpperCase()} policy "${name}" was successfully deleted.`); - return this.transitionToRoute('vault.cluster.policies', policyType); - }) - .catch((e) => { - const errors = e.errors ? e.errors.join('') : e.message; - flash.danger( - `There was an error deleting the ${policyType.toUpperCase()} policy "${name}": ${errors}.` - ); - }); - }, - - savePolicy(model) { - const flash = this.flashMessages; - const policyType = model.get('policyType'); - const name = model.get('name'); - model - .save() - .then((m) => { - flash.success(`${policyType.toUpperCase()} policy "${name}" was successfully saved.`); - if (this.wizard.featureState === 'create') { - this.wizard.transitionFeatureMachine('create', 'CONTINUE', policyType); - } - return this.transitionToRoute('vault.cluster.policy.show', m.get('policyType'), m.get('name')); - }) - .catch(() => { - // swallow error -- model.errors set by Adapter - return; - }); - }, - - setModelName(model, e) { - model.set('name', e.target.value.toLowerCase()); - }, - }, -}); diff --git a/ui/app/models/identity/entity.js b/ui/app/models/identity/entity.js index 0a73af737..d56fde95e 100644 --- a/ui/app/models/identity/entity.js +++ b/ui/app/models/identity/entity.js @@ -4,6 +4,7 @@ import { alias } from '@ember/object/computed'; import IdentityModel from './_base'; import apiPath from 'vault/utils/api-path'; import attachCapabilities from 'vault/lib/attach-capabilities'; +import lazyCapabilities from 'vault/macros/lazy-capabilities'; const Model = IdentityModel.extend({ formFields: computed(function () { @@ -20,11 +21,8 @@ const Model = IdentityModel.extend({ editType: 'kv', }), policies: attr({ - label: 'Policies', - editType: 'searchSelect', + editType: 'yield', isSectionHeader: true, - fallbackComponent: 'string-list', - models: ['policy/acl', 'policy/rgp'], }), creationTime: attr('string', { readOnly: true, @@ -46,6 +44,8 @@ const Model = IdentityModel.extend({ canEdit: alias('updatePath.canUpdate'), canRead: alias('updatePath.canRead'), canAddAlias: alias('aliasPath.canCreate'), + policyPath: lazyCapabilities(apiPath`sys/policies`), + canCreatePolicies: alias('policyPath.canCreate'), }); export default attachCapabilities(Model, { diff --git a/ui/app/models/identity/group.js b/ui/app/models/identity/group.js index 9f51db140..42da7de7f 100644 --- a/ui/app/models/identity/group.js +++ b/ui/app/models/identity/group.js @@ -34,11 +34,8 @@ export default IdentityModel.extend({ editType: 'kv', }), policies: attr({ - label: 'Policies', - editType: 'searchSelect', + editType: 'yield', isSectionHeader: true, - fallbackComponent: 'string-list', - models: ['policy/acl', 'policy/rgp'], }), memberGroupIds: attr({ label: 'Member Group IDs', @@ -73,7 +70,8 @@ export default IdentityModel.extend({ return numEntities + numGroups > 0; } ), - + policyPath: lazyCapabilities(apiPath`sys/policies`), + canCreatePolicies: alias('policyPath.canCreate'), alias: belongsTo('identity/group-alias', { async: false, readOnly: true }), updatePath: identityCapabilities(), canDelete: alias('updatePath.canDelete'), diff --git a/ui/app/routes/vault/cluster/policy/edit.js b/ui/app/routes/vault/cluster/policy/edit.js index c0743fc75..4b22d1d2f 100644 --- a/ui/app/routes/vault/cluster/policy/edit.js +++ b/ui/app/routes/vault/cluster/policy/edit.js @@ -1,4 +1,13 @@ import UnsavedModelRoute from 'vault/mixins/unsaved-model-route'; import ShowRoute from './show'; +import { inject as service } from '@ember/service'; -export default ShowRoute.extend(UnsavedModelRoute); +export default ShowRoute.extend(UnsavedModelRoute, { + wizard: service(), + + activate() { + if (this.wizard.featureState === 'details') { + this.wizard.transitionFeatureMachine('details', 'CONTINUE', this.policyType()); + } + }, +}); diff --git a/ui/app/routes/vault/cluster/policy/show.js b/ui/app/routes/vault/cluster/policy/show.js index e6d1e9ac2..89c27a2b2 100644 --- a/ui/app/routes/vault/cluster/policy/show.js +++ b/ui/app/routes/vault/cluster/policy/show.js @@ -5,6 +5,13 @@ import { inject as service } from '@ember/service'; export default Route.extend(UnloadModelRoute, { store: service(), + wizard: service(), + + activate() { + if (this.wizard.featureState === 'create') { + this.wizard.transitionFeatureMachine('create', 'CONTINUE', this.policyType()); + } + }, beforeModel() { const params = this.paramsFor(this.routeName); diff --git a/ui/app/styles/components/modal.scss b/ui/app/styles/components/modal.scss index 0b8aeb061..61b8ca436 100644 --- a/ui/app/styles/components/modal.scss +++ b/ui/app/styles/components/modal.scss @@ -7,6 +7,7 @@ border: 1px solid $grey-light; max-height: calc(100vh - 70px); margin-top: 60px; + min-width: calc(100vw * 0.3); &-head { border-radius: 0; diff --git a/ui/app/templates/components/identity/edit-form.hbs b/ui/app/templates/components/identity/edit-form.hbs index 869fc3cd7..469e8251d 100644 --- a/ui/app/templates/components/identity/edit-form.hbs +++ b/ui/app/templates/components/identity/edit-form.hbs @@ -24,7 +24,34 @@ /> {{/if}} {{#each this.model.fields as |attr|}} - + +
+ {{#if this.model.canCreatePolicies}} + + {{else}} + + {{/if}} +
+
{{/each}} diff --git a/ui/app/templates/components/oidc/assignment-form.hbs b/ui/app/templates/components/oidc/assignment-form.hbs index 48ced294b..6f4d2734c 100644 --- a/ui/app/templates/components/oidc/assignment-form.hbs +++ b/ui/app/templates/components/oidc/assignment-form.hbs @@ -1,32 +1,3 @@ -{{#unless @isInline}} - - - - - -

- {{if @model.isNew "Create" "Edit"}} - assignment -

-
-
-{{/unless}}
diff --git a/ui/app/templates/components/oidc/client-form.hbs b/ui/app/templates/components/oidc/client-form.hbs index 893ff199a..2023a5eb3 100644 --- a/ui/app/templates/components/oidc/client-form.hbs +++ b/ui/app/templates/components/oidc/client-form.hbs @@ -60,12 +60,12 @@ @id="assignments" @label="Assignment name" @subText="Search for an existing assignment, or type a new name to create it." - @model="oidc/assignment" + @models={{array "oidc/assignment"}} @inputValue={{this.modelAssignments}} @onChange={{this.handleAssignmentSelection}} @excludeOptions={{array "allow_all"}} @fallbackComponent="string-list" - @modalFormComponent="oidc/assignment-form" + @modalFormTemplate="modal-form/oidc-assignment-template" @modalSubtext="Use assignment to specify which Vault entities and groups are allowed to authenticate." /> {{/if}} diff --git a/ui/app/templates/components/ui-wizard.hbs b/ui/app/templates/components/ui-wizard.hbs index f846cf0c9..90d8b3183 100644 --- a/ui/app/templates/components/ui-wizard.hbs +++ b/ui/app/templates/components/ui-wizard.hbs @@ -16,6 +16,7 @@ onRepeat=(action "repeatStep") onReset=(action "resetFeature") onAdvance=(action "advanceFeature") + currentRouteName=this.currentRouteName }} {{/component}} {{/if}} \ No newline at end of file diff --git a/ui/app/templates/components/wizard/policies-delete.hbs b/ui/app/templates/components/wizard/policies-delete.hbs index d0430edb8..3bc9183da 100644 --- a/ui/app/templates/components/wizard/policies-delete.hbs +++ b/ui/app/templates/components/wizard/policies-delete.hbs @@ -7,7 +7,11 @@ @instructions='Click on "Delete" to remove the policy that you created.' >

- You can delete your test policy by clicking the "..." icon to the right of the policy name. + {{#if (eq @currentRouteName "vault.cluster.policies.index")}} + You can delete your test policy by clicking the "..." icon to the right of the policy name. + {{else}} + You can delete your test policy by clicking "Delete" in the toolbar. + {{/if}}

\ No newline at end of file diff --git a/ui/app/templates/components/wizard/policies-details.hbs b/ui/app/templates/components/wizard/policies-details.hbs index a2cdab12e..d6eb2b15a 100644 --- a/ui/app/templates/components/wizard/policies-details.hbs +++ b/ui/app/templates/components/wizard/policies-details.hbs @@ -7,7 +7,7 @@ @instructions='Click on "ACL Policies" in the sidebar to go back to the list of policies.' >

- Good job! Here you can see your new policy. If you'd like to edit it, you'd just click the "Edit" toggle. + Good job! Here you can see your new policy. If you'd like to edit it, you'd just click "Edit policy" in the toolbar.

\ No newline at end of file diff --git a/ui/app/templates/vault/cluster/access/oidc/assignments/assignment/edit.hbs b/ui/app/templates/vault/cluster/access/oidc/assignments/assignment/edit.hbs index 1c302ffa9..5ffb72175 100644 --- a/ui/app/templates/vault/cluster/access/oidc/assignments/assignment/edit.hbs +++ b/ui/app/templates/vault/cluster/access/oidc/assignments/assignment/edit.hbs @@ -1,3 +1,22 @@ + + + + + +

+ Edit assignment +

+
+
+ + + + +

+ Create assignment +

+
+ - -
- - -
- -
- -
-
-
- - - -
-
- - -
-
-
- {{#if this.showFileUpload}} - - {{else}} - - {{/if}} -
- {{#each this.model.additionalAttrs as |attr|}} - - {{/each}} -
-
-
- -
-
- - Cancel - -
-
- \ No newline at end of file + \ No newline at end of file diff --git a/ui/app/templates/vault/cluster/policy/edit.hbs b/ui/app/templates/vault/cluster/policy/edit.hbs index 526b72dcc..bd057e4e9 100644 --- a/ui/app/templates/vault/cluster/policy/edit.hbs +++ b/ui/app/templates/vault/cluster/policy/edit.hbs @@ -28,7 +28,7 @@ Delete @@ -41,42 +41,9 @@ {{/if}} -
-
- - -
- -
-

- You can use Alt+Tab (Option+Tab on MacOS) in the code editor to skip to the next field -

-
-
- {{#each this.model.additionalAttrs as |attr|}} - - {{/each}} -
-
- {{#if this.capabilities.canUpdate}} -
- -
- {{/if}} -
- - Cancel - -
-
-
-
-
\ No newline at end of file + + \ No newline at end of file diff --git a/ui/lib/core/addon/components/form-field.hbs b/ui/lib/core/addon/components/form-field.hbs index fd5228b79..151fafe28 100644 --- a/ui/lib/core/addon/components/form-field.hbs +++ b/ui/lib/core/addon/components/form-field.hbs @@ -1,23 +1,13 @@ {{! template-lint-configure simple-unless "warn" }}
- {{#unless - (or - (eq @attr.type "boolean") - (includes - @attr.options.editType - (array "boolean" "optionalText" "searchSelect" "mountAccessor" "kv" "file" "ttl" "stringArray" "json" "regex") - ) - ) - }} - {{#if (not (eq @attr.type "object"))}} - - {{/if}} + {{#unless this.hideLabel}} + {{/unless}} {{#if @attr.options.possibleValues}} {{#if (eq @attr.options.editType "radio")}} diff --git a/ui/lib/core/addon/components/form-field.js b/ui/lib/core/addon/components/form-field.js index 7ddf1e47d..5c2b5d47e 100644 --- a/ui/lib/core/addon/components/form-field.js +++ b/ui/lib/core/addon/components/form-field.js @@ -42,9 +42,21 @@ import { dasherize } from 'vault/helpers/dasherize'; */ export default class FormFieldComponent extends Component { + emptyData = '{\n}'; + shouldHideLabel = [ + 'boolean', + 'file', + 'json', + 'kv', + 'mountAccessor', + 'optionalText', + 'regex', + 'searchSelect', + 'stringArray', + 'ttl', + ]; @tracked showInput = false; @tracked file = { value: '' }; // used by the pgp-file component when an attr is editType of 'file' - emptyData = '{\n}'; constructor() { super(...arguments); @@ -54,6 +66,15 @@ export default class FormFieldComponent extends Component { this.showInput = !!modelValue; } + get hideLabel() { + const { type, options } = this.args.attr; + if (type === 'boolean' || type === 'object' || options?.isSectionHeader) { + return true; + } + // falsey values render a + return this.shouldHideLabel.includes(options?.editType); + } + get disabled() { return this.args.disabled || false; } diff --git a/ui/lib/core/addon/components/search-select-with-modal.hbs b/ui/lib/core/addon/components/search-select-with-modal.hbs index 37a7f4401..efe6247bd 100644 --- a/ui/lib/core/addon/components/search-select-with-modal.hbs +++ b/ui/lib/core/addon/components/search-select-with-modal.hbs @@ -1,4 +1,10 @@ -
+
{{#if this.shouldUseFallback}} {{component @fallbackComponent @@ -12,7 +18,7 @@ }} {{else}} {{#if @label}} -