mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-03 20:17:59 +00:00 
			
		
		
		
	* replace confirm-action dropdown with button+modal * add modal frame to sidebar * fix weird paragraph indent * pass button text as arg * add warning color to rotate modals * update seal action and config ssh * cleanup confirm action * edit form * add dropdown arg * put back seal text * put back confirm button text * fix toolbar stylinggp * popup member group * move up title * finish popup- components * keymgmt * fix modal button logic * remaining app template components * add period for angel * vault cluster items * add button text assertion * remaining instances * remove arg for passing confirm text * contextual confirm action components * delete old components * update docs * ammend dropdown loading states, add getter for confirm button color * address feedback * remove @disabled arg and add @disabledMessage * add changelog; * mfa tests * update test selectors * lol cleanup selectors * start confirm action tests WIP * move dropdown class directly to component * add default color of isInDropdown * final cleanup * add tests * remove @buttonColor as arg for dropdown * update confirm action tests * updae modals with disabled message * refactor provider edit test
		
			
				
	
	
		
			389 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Handlebars
		
	
	
	
	
	
			
		
		
	
	
			389 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Handlebars
		
	
	
	
	
	
{{!
 | 
						||
  Copyright (c) HashiCorp, Inc.
 | 
						||
  SPDX-License-Identifier: BUSL-1.1
 | 
						||
~}}
 | 
						||
 | 
						||
<PageHeader as |p|>
 | 
						||
  <p.top>
 | 
						||
    <KeyValueHeader @path="vault.cluster.secrets.backend.show" @mode={{this.mode}} @root={{@root}} @showCurrent={{true}} />
 | 
						||
  </p.top>
 | 
						||
  <p.levelLeft>
 | 
						||
    <h1 class="title is-3" data-test-secret-header="true">
 | 
						||
      {{#if (eq @mode "create")}}
 | 
						||
        Create Connection
 | 
						||
      {{else if (eq @mode "edit")}}
 | 
						||
        Edit Connection
 | 
						||
      {{else}}
 | 
						||
        {{@model.id}}
 | 
						||
      {{/if}}
 | 
						||
    </h1>
 | 
						||
  </p.levelLeft>
 | 
						||
</PageHeader>
 | 
						||
 | 
						||
{{#if @model.isAvailablePlugin}}
 | 
						||
  {{#if (eq @mode "show")}}
 | 
						||
    <Toolbar>
 | 
						||
      <ToolbarActions>
 | 
						||
        {{#if @model.canDelete}}
 | 
						||
          <Hds::Button
 | 
						||
            @text="Delete connection"
 | 
						||
            @color="secondary"
 | 
						||
            class="toolbar-button"
 | 
						||
            {{on "click" (action (mut this.isDeleteModalActive) true)}}
 | 
						||
            data-test-database-connection-delete
 | 
						||
          />
 | 
						||
        {{/if}}
 | 
						||
        {{#if @model.canReset}}
 | 
						||
          <ConfirmAction
 | 
						||
            @buttonText="Reset connection"
 | 
						||
            class="toolbar-button"
 | 
						||
            @buttonColor="secondary"
 | 
						||
            @onConfirmAction={{action "reset"}}
 | 
						||
            @confirmTitle="Reset connection?"
 | 
						||
            @confirmMessage="This will close the connection and its underlying plugin and restart it with the configuration stored in the barrier."
 | 
						||
            data-test-database-connection-reset
 | 
						||
          />
 | 
						||
        {{/if}}
 | 
						||
        {{#if (or @model.canReset @model.canDelete)}}
 | 
						||
          <div class="toolbar-separator"></div>
 | 
						||
        {{/if}}
 | 
						||
        {{#if @model.canRotateRoot}}
 | 
						||
          {{! template-lint-disable quotes }}
 | 
						||
          <ConfirmAction
 | 
						||
            @buttonText="Rotate root credentials"
 | 
						||
            class="toolbar-button"
 | 
						||
            @buttonColor="secondary"
 | 
						||
            @onConfirmAction={{this.rotate}}
 | 
						||
            @confirmTitle="Rotate credentials?"
 | 
						||
            @confirmMessage='This will rotate the "root" user credentials stored for the database connection. The password will not be accessible once rotated.'
 | 
						||
            @modalColor="warning"
 | 
						||
            data-test-database-connection-rotate
 | 
						||
          />
 | 
						||
          {{! template-lint-enable }}
 | 
						||
        {{/if}}
 | 
						||
        {{#if @model.canAddRole}}
 | 
						||
          <ToolbarSecretLink
 | 
						||
            @secret=""
 | 
						||
            @mode="create"
 | 
						||
            @type="add"
 | 
						||
            @queryParams={{hash initialKey=@model.name itemType="role"}}
 | 
						||
            data-test-secret-create={{true}}
 | 
						||
          >
 | 
						||
            Add role
 | 
						||
          </ToolbarSecretLink>
 | 
						||
        {{/if}}
 | 
						||
        {{#if @model.canEdit}}
 | 
						||
          <ToolbarSecretLink @secret={{@model.id}} @mode="edit" data-test-edit-link={{true}} @replace={{true}}>
 | 
						||
            Edit configuration
 | 
						||
          </ToolbarSecretLink>
 | 
						||
        {{/if}}
 | 
						||
      </ToolbarActions>
 | 
						||
    </Toolbar>
 | 
						||
  {{/if}}
 | 
						||
{{/if}}
 | 
						||
 | 
						||
{{#if (eq @mode "create")}}
 | 
						||
 | 
						||
  {{#if (eq @model.plugin_name "vault-plugin-database-oracle")}}
 | 
						||
    <Hds::Alert @type="inline" @color="warning" class="has-bottom-margin-s" data-test-database-oracle-alert as |A|>
 | 
						||
      <A.Title>Warning</A.Title>
 | 
						||
      <A.Description>
 | 
						||
        Please ensure that your Oracle plugin has the default name of
 | 
						||
        <strong>vault-plugin-database-oracle</strong>. Custom naming is not supported in the UI at this time. If the plugin
 | 
						||
        is already named vault-plugin-database-oracle, disregard this warning.
 | 
						||
      </A.Description>
 | 
						||
    </Hds::Alert>
 | 
						||
  {{/if}}
 | 
						||
 | 
						||
  <form {{on "submit" this.handleCreateConnection}} aria-label="create connection form">
 | 
						||
    {{#each @model.fieldAttrs as |attr|}}
 | 
						||
      {{#if (not-eq attr.options.readOnly true)}}
 | 
						||
        <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
      {{/if}}
 | 
						||
    {{/each}}
 | 
						||
 | 
						||
    {{! Plugin Config Section }}
 | 
						||
    <div class="form-section box is-shadowless is-fullwidth">
 | 
						||
      <fieldset class="form-fieldset">
 | 
						||
        <legend class="title is-5">Plugin config</legend>
 | 
						||
        {{#if @model.pluginFieldGroups}}
 | 
						||
          {{#each @model.pluginFieldGroups as |fieldGroup|}}
 | 
						||
            {{#each-in fieldGroup as |group fields|}}
 | 
						||
              {{#if (eq group "default")}}
 | 
						||
                <div class="columns is-desktop is-multiline">
 | 
						||
                  {{#each fields as |attr|}}
 | 
						||
                    {{#if
 | 
						||
                      (includes attr.name (array "max_open_connections" "max_idle_connections" "max_connection_lifetime"))
 | 
						||
                    }}
 | 
						||
                      <div class="column is-one-third">
 | 
						||
                        <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
                      </div>
 | 
						||
                    {{else}}
 | 
						||
                      <div class="column is-full">
 | 
						||
                        <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
                      </div>
 | 
						||
                    {{/if}}
 | 
						||
                  {{/each}}
 | 
						||
                </div>
 | 
						||
              {{else}}
 | 
						||
                {{#let (camelize (concat "show" group)) as |prop|}}
 | 
						||
                  <ToggleButton
 | 
						||
                    @isOpen={{get this prop}}
 | 
						||
                    @openLabel={{concat "Hide " group}}
 | 
						||
                    @closedLabel={{group}}
 | 
						||
                    @onClick={{fn (mut (get this prop))}}
 | 
						||
                    class="is-block"
 | 
						||
                    data-test-toggle-group={{group}}
 | 
						||
                  />
 | 
						||
                  {{#if (get this prop)}}
 | 
						||
                    <div class="box is-marginless">
 | 
						||
                      {{#each fields as |attr|}}
 | 
						||
                        <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
                      {{/each}}
 | 
						||
                    </div>
 | 
						||
                  {{/if}}
 | 
						||
                {{/let}}
 | 
						||
              {{/if}}
 | 
						||
            {{/each-in}}
 | 
						||
          {{/each}}
 | 
						||
        {{else}}
 | 
						||
          <EmptyState @title="No plugin selected" @message="Select a plugin type to be able to configure it." />
 | 
						||
        {{/if}}
 | 
						||
      </fieldset>
 | 
						||
    </div>
 | 
						||
 | 
						||
    {{! Statements Section }}
 | 
						||
    {{! template-lint-configure simple-unless "warn"  }}
 | 
						||
    {{#unless (and @model.plugin_name (not @model.statementFields))}}
 | 
						||
      <div class="form-section box is-shadowless is-fullwidth">
 | 
						||
        <h3 class="title is-5">Statements</h3>
 | 
						||
        {{#if (eq @model.statementFields null)}}
 | 
						||
          <EmptyState @title="No plugin selected" @message="Select a plugin type to be able to configure it." />
 | 
						||
        {{else}}
 | 
						||
          {{#each @model.statementFields as |attr|}}
 | 
						||
            <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
          {{/each}}
 | 
						||
        {{/if}}
 | 
						||
      </div>
 | 
						||
    {{/unless}}
 | 
						||
 | 
						||
    <div class="field is-grouped is-grouped-split is-fullwidth box is-bottomless">
 | 
						||
      <div class="field is-grouped">
 | 
						||
        <Hds::ButtonSet>
 | 
						||
          <Hds::Button @text="Create database" type="submit" data-test-secret-save />
 | 
						||
          <Hds::Button
 | 
						||
            @text="Cancel"
 | 
						||
            @color="secondary"
 | 
						||
            @route="vault.cluster.secrets.backend.list-root"
 | 
						||
            @model={{@model.backend}}
 | 
						||
          />
 | 
						||
        </Hds::ButtonSet>
 | 
						||
      </div>
 | 
						||
    </div>
 | 
						||
  </form>
 | 
						||
{{else if (and (eq @mode "edit") @model.isAvailablePlugin)}}
 | 
						||
  <form {{on "submit" this.handleUpdateConnection}} aria-label="plugin config form">
 | 
						||
    {{#each @model.fieldAttrs as |attr|}}
 | 
						||
      {{#if (or (eq attr.name "name") (eq attr.name "plugin_name"))}}
 | 
						||
        <ReadonlyFormField @attr={{attr}} @value={{get @model attr.name}} />
 | 
						||
      {{else if (not-eq attr.options.readOnly true)}}
 | 
						||
        <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
      {{/if}}
 | 
						||
    {{/each}}
 | 
						||
 | 
						||
    {{! Plugin Config Edit }}
 | 
						||
    <div class="form-section box is-shadowless is-fullwidth">
 | 
						||
      <fieldset class="form-fieldset">
 | 
						||
        <legend class="title is-5">Plugin config</legend>
 | 
						||
        {{#each @model.pluginFieldGroups as |fieldGroup|}}
 | 
						||
          {{#each-in fieldGroup as |group fields|}}
 | 
						||
            {{#if (eq group "default")}}
 | 
						||
              <div class="columns is-desktop is-multiline">
 | 
						||
                {{#each fields as |attr|}}
 | 
						||
                  {{#if
 | 
						||
                    (includes attr.name (array "max_open_connections" "max_idle_connections" "max_connection_lifetime"))
 | 
						||
                  }}
 | 
						||
                    <div class="column is-one-third">
 | 
						||
                      <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
                    </div>
 | 
						||
                  {{else if (eq attr.name "password")}}
 | 
						||
                    <div class="column is-full">
 | 
						||
                      <label for={{attr.name}} class="is-label">
 | 
						||
                        {{capitalize (or attr.options.label attr.name)}}
 | 
						||
                      </label>
 | 
						||
                      <div class="field">
 | 
						||
                        <Toggle
 | 
						||
                          @name="show-{{attr.name}}"
 | 
						||
                          @onChange={{fn this.updateShowPassword (not this.showPasswordField)}}
 | 
						||
                          @checked={{this.showPasswordField}}
 | 
						||
                          data-test-toggle={{attr.name}}
 | 
						||
                        >
 | 
						||
                          <span class="ttl-picker-label has-text-grey">Update password</span><br />
 | 
						||
                          <div class="description has-text-grey">
 | 
						||
                            <span>
 | 
						||
                              {{if
 | 
						||
                                this.showPasswordField
 | 
						||
                                "The new password that will be used when connecting to the database"
 | 
						||
                                "Vault will use the existing password"
 | 
						||
                              }}
 | 
						||
                            </span>
 | 
						||
                          </div>
 | 
						||
                          {{#if this.showPasswordField}}
 | 
						||
                            <Input
 | 
						||
                              {{on "change" (fn this.updatePassword attr.name)}}
 | 
						||
                              @type="password"
 | 
						||
                              @value={{get @model attr.name}}
 | 
						||
                              name={{attr.name}}
 | 
						||
                              class="input"
 | 
						||
                              {{! Prevents browsers from auto-filling }}
 | 
						||
                              autocomplete="new-password"
 | 
						||
                              spellcheck="false"
 | 
						||
                            />
 | 
						||
                          {{/if}}
 | 
						||
                        </Toggle>
 | 
						||
                      </div>
 | 
						||
                    </div>
 | 
						||
                  {{else}}
 | 
						||
                    <div class="column is-full">
 | 
						||
                      <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
                    </div>
 | 
						||
                  {{/if}}
 | 
						||
                {{/each}}
 | 
						||
              </div>
 | 
						||
            {{else}}
 | 
						||
              {{#let (camelize (concat "show" group)) as |prop|}}
 | 
						||
                <ToggleButton
 | 
						||
                  @isOpen={{get this prop}}
 | 
						||
                  @openLabel={{concat "Hide " group}}
 | 
						||
                  @closedLabel={{group}}
 | 
						||
                  @onClick={{fn (mut (get this prop))}}
 | 
						||
                  class="is-block"
 | 
						||
                  data-test-toggle-group={{group}}
 | 
						||
                />
 | 
						||
                {{#if (get this prop)}}
 | 
						||
                  <div class="box is-marginless">
 | 
						||
                    {{#each fields as |attr|}}
 | 
						||
                      <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
                    {{/each}}
 | 
						||
                  </div>
 | 
						||
                {{/if}}
 | 
						||
              {{/let}}
 | 
						||
            {{/if}}
 | 
						||
          {{/each-in}}
 | 
						||
        {{/each}}
 | 
						||
      </fieldset>
 | 
						||
    </div>
 | 
						||
 | 
						||
    {{! Statements Edit Section }}
 | 
						||
    {{#if (not (and @model.plugin_name (not @model.statementFields)))}}
 | 
						||
      <div class="form-section box is-shadowless is-fullwidth">
 | 
						||
        <fieldset class="form-fieldset">
 | 
						||
          <legend class="title is-5">Statements</legend>
 | 
						||
          {{#each @model.statementFields as |attr|}}
 | 
						||
            <FormField data-test-field={{true}} @attr={{attr}} @model={{@model}} />
 | 
						||
          {{/each}}
 | 
						||
        </fieldset>
 | 
						||
      </div>
 | 
						||
    {{/if}}
 | 
						||
 | 
						||
    <div class="field is-grouped is-grouped-split is-fullwidth box is-bottomless">
 | 
						||
      <div class="field is-grouped">
 | 
						||
        <Hds::ButtonSet>
 | 
						||
          <Hds::Button @text="Save" type="submit" data-test-secret-save />
 | 
						||
          <Hds::Button
 | 
						||
            @text="Cancel"
 | 
						||
            @color="secondary"
 | 
						||
            @route="vault.cluster.secrets.backend.list-root"
 | 
						||
            @model={{@model.backend}}
 | 
						||
          />
 | 
						||
        </Hds::ButtonSet>
 | 
						||
      </div>
 | 
						||
    </div>
 | 
						||
  </form>
 | 
						||
{{else if (eq @model.isAvailablePlugin false)}}
 | 
						||
  <EmptyState
 | 
						||
    @title="Database type unavailable"
 | 
						||
    @subTitle="Not supported in the UI"
 | 
						||
    @icon="skip"
 | 
						||
    @message="This database type cannot be viewed in the UI. You will have to use the API or CLI to perform actions here."
 | 
						||
    @bottomBorder={{true}}
 | 
						||
  >
 | 
						||
    <LinkTo @route="vault.cluster.secrets.backend.list-root" class="link">
 | 
						||
      <Chevron @direction="left" />
 | 
						||
      Go back
 | 
						||
    </LinkTo>
 | 
						||
    <DocLink @path="/api/secret/databases">Documentation</DocLink>
 | 
						||
  </EmptyState>
 | 
						||
{{else}}
 | 
						||
  {{#each @model.showAttrs as |attr|}}
 | 
						||
    {{#let attr.options.defaultShown as |defaultDisplay|}}
 | 
						||
      {{#if (eq attr.type "object")}}
 | 
						||
        <InfoTableRow
 | 
						||
          @alwaysRender={{not (is-empty-value (get @model attr.name) hasDefault=defaultDisplay)}}
 | 
						||
          @defaultShown={{defaultDisplay}}
 | 
						||
          @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
 | 
						||
          @value={{stringify (get @model attr.name)}}
 | 
						||
        />
 | 
						||
      {{else if (eq attr.type "array")}}
 | 
						||
        <InfoTableRow
 | 
						||
          @alwaysRender={{not (is-empty-value (get @model attr.name) hasDefault=defaultDisplay)}}
 | 
						||
          @defaultShown={{defaultDisplay}}
 | 
						||
          @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
 | 
						||
          @value={{get @model attr.name}}
 | 
						||
          @isLink={{true}}
 | 
						||
          @queryParam="role"
 | 
						||
          @type={{attr.type}}
 | 
						||
        />
 | 
						||
      {{else}}
 | 
						||
        <InfoTableRow
 | 
						||
          @alwaysRender={{not (is-empty-value (get @model attr.name) hasDefault=defaultDisplay)}}
 | 
						||
          @defaultShown={{defaultDisplay}}
 | 
						||
          @label={{capitalize (or attr.options.label (humanize (dasherize attr.name)))}}
 | 
						||
          @value={{if (eq attr.name "connection_url") (decode-uri (get @model attr.name)) (get @model attr.name)}}
 | 
						||
        />
 | 
						||
      {{/if}}
 | 
						||
    {{/let}}
 | 
						||
  {{/each}}
 | 
						||
{{/if}}
 | 
						||
 | 
						||
{{#if this.showSaveModal}}
 | 
						||
  <Hds::Modal id="rotate-credentials-modal" @onClose={{this.continueWithoutRotate}} as |M|>
 | 
						||
    <M.Header @icon="info" data-test-db-connection-modal-title>
 | 
						||
      Rotate your root credentials?
 | 
						||
    </M.Header>
 | 
						||
    <M.Body>
 | 
						||
      <p class="has-bottom-margin-s">
 | 
						||
        It’s best practice to rotate the root credential immediately after the initial configuration of each database. Once
 | 
						||
        rotated,
 | 
						||
        <strong>only Vault knows the new root password</strong>.
 | 
						||
      </p>
 | 
						||
      <p>Would you like to rotate your new credentials? You can also do this later.</p>
 | 
						||
    </M.Body>
 | 
						||
    <M.Footer>
 | 
						||
      <Hds::ButtonSet>
 | 
						||
        <Hds::Button @text="Rotate and enable" {{on "click" this.continueWithRotate}} data-test-enable-rotate-connection />
 | 
						||
        <Hds::Button
 | 
						||
          @text="Enable without rotating"
 | 
						||
          @color="secondary"
 | 
						||
          {{on "click" this.continueWithoutRotate}}
 | 
						||
          data-test-enable-connection
 | 
						||
        />
 | 
						||
      </Hds::ButtonSet>
 | 
						||
    </M.Footer>
 | 
						||
  </Hds::Modal>
 | 
						||
{{/if}}
 | 
						||
 | 
						||
<ConfirmationModal
 | 
						||
  @title="Delete connection?"
 | 
						||
  @onClose={{action (mut this.isDeleteModalActive) false}}
 | 
						||
  @isActive={{this.isDeleteModalActive}}
 | 
						||
  @confirmText={{@model.name}}
 | 
						||
  @toConfirmMsg="deleting the connection"
 | 
						||
  @onConfirm={{action "delete"}}
 | 
						||
>
 | 
						||
  <p>
 | 
						||
    Deleting the connection means that any associated roles won't be able to generate credentials until the connection is
 | 
						||
    reconfigured.
 | 
						||
  </p>
 | 
						||
  <MessageError @model={{this.model}} @errorMessage={{this.error}} />
 | 
						||
</ConfirmationModal> |