mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-22 07:01:09 +02:00
415 lines
16 KiB
Handlebars
415 lines
16 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"
|
||
@backend={{@model.backend}}
|
||
@type="add"
|
||
@queryParams={{hash initialKey=@model.name itemType="role"}}
|
||
data-test-add-role
|
||
>
|
||
Add role
|
||
</ToolbarSecretLink>
|
||
{{/if}}
|
||
{{#if @model.canEdit}}
|
||
<ToolbarSecretLink
|
||
@secret={{@model.id}}
|
||
@mode="edit"
|
||
@backend={{@model.backend}}
|
||
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" (perform 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-button={{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
|
||
@icon={{if this.handleCreateConnection.isRunning "loading"}}
|
||
@text="Create database"
|
||
type="submit"
|
||
data-test-submit
|
||
/>
|
||
<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-button={{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-submit />
|
||
<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}}
|
||
>
|
||
<Hds::Link::Standalone @icon="chevron-left" @text="Go back" @route="vault.cluster.secrets.backend.list-root" />
|
||
<Hds::Link::Standalone
|
||
@icon="docs-link"
|
||
@iconPosition="trailing"
|
||
@text="Database API docs"
|
||
@href={{doc-link "/vault/api-docs/secret/databases"}}
|
||
/>
|
||
</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 if (eq attr.name "skip_static_role_rotation_import")}}
|
||
<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={{not (get @model attr.name)}}
|
||
/>
|
||
{{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={{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
|
||
@icon={{if this.continueWithRotate.isRunning "loading"}}
|
||
@text="Rotate and enable"
|
||
{{on "click" (perform 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> |