open-vault/ui/app/templates/components/secret-edit.hbs
Angel Garbarino d99742c6c5
Implement ember-cp-validations on KV secret engine (#11785)
* initial setup

* initial validation setup for empty path object.

* removal console logs

* validation on keyup for kv

* in progress

* making some progress

* more progress

* closer

* done with create page now to fix edit page that I broke

* fix secret edit display on create

* test and final touches

* cleanup mountbackendform

* cleanup

* add changelog

* address pr comments

* address styling pr comment
2021-06-15 09:21:54 -06:00

271 lines
9.3 KiB
Handlebars

<PageHeader as |p|>
<p.top>
<KeyValueHeader @baseKey={{baseKey}} @path="vault.cluster.secrets.backend.list" @mode={{mode}} @root={{root}} @showCurrent={{true}} />
</p.top>
<p.levelLeft>
<h1 class="title is-3">
{{#if (eq mode "create") }}
Create secret
{{else if (and isV2 (eq mode 'edit'))}}
Create new version
{{else if (eq mode 'edit')}}
Edit secret
{{else}}
{{key.id}}
{{/if}}
</h1>
</p.levelLeft>
</PageHeader>
<Toolbar>
{{#unless (and (eq mode 'show') isWriteWithoutRead)}}
<ToolbarFilters>
<Toggle
@name="json"
@status="success"
@size="small"
@disabled={{and (eq mode 'show') secretDataIsAdvanced}}
@checked={{showAdvancedMode}}
@onChange={{action "toggleAdvanced"}}
>
<span class="has-text-grey">JSON</span>
</Toggle>
</ToolbarFilters>
{{/unless}}
<ToolbarActions>
{{#if (eq mode 'show')}}
<SecretDeleteMenu
@modelForData={{this.modelForData}}
@model={{this.model}}
@navToNearestAncestor={{this.navToNearestAncestor}}
@isV2={{isV2}}
@refresh={{action 'refresh'}}
/>
{{/if}}
{{#if (and (eq mode 'show') (or canEditV2Secret canEdit))}}
{{#let (concat 'vault.cluster.secrets.backend.' (if (eq mode 'show') 'edit' 'show')) as |targetRoute|}}
{{#unless (and isV2 (or isWriteWithoutRead modelForData.destroyed modelForData.deleted))}}
<BasicDropdown
@class="popup-menu"
@horizontalPosition="auto-right"
@verticalPosition="below"
@onClose={{action "clearWrappedData"}}
as |D|
>
<D.trigger
data-test-popup-menu-trigger="true"
@class={{concat "toolbar-link" (if D.isOpen " is-active")}}
@tagName="button"
>
Copy
<Chevron @direction="down" @isButton={{true}} />
</D.trigger>
<D.content @class="popup-menu-content is-wide">
<nav class="box menu">
<ul class="menu-list">
<li class="action">
<CopyButton
@class="link link-plain has-text-weight-semibold is-ghost"
@clipboardText={{codemirrorString}}
@success={{action (set-flash-message "JSON Copied!")}}
data-test-copy-button
>
Copy JSON
</CopyButton>
</li>
<li class="action">
{{#if showWrapButton}}
<button
class="link link-plain has-text-weight-semibold is-ghost {{if isWrapping "is-loading"}}"
type="button"
{{action "handleWrapClick"}}
data-test-wrap-button
disabled={{isWrapping}}
>
Wrap secret
</button>
{{else}}
<MaskedInput
@class="has-padding"
@displayOnly={{true}}
@allowCopy={{true}}
@value={{wrappedData}}
@success={{action "handleCopySuccess"}}
@error={{action "handleCopyError"}}
/>
{{/if}}
</li>
</ul>
</nav>
</D.content>
</BasicDropdown>
{{/unless}}
{{/let}}
{{/if}}
{{#if (and (eq @mode "show") this.isV2 (not @model.failedServerRead))}}
<SecretVersionMenu
@version={{this.modelForData}}
@onRefresh={{action 'refresh'}}
@model={{this.model}}
/>
{{/if}}
{{#if (and (eq mode 'show') (or canEditV2Secret canEdit))}}
{{#let (concat 'vault.cluster.secrets.backend.' (if (eq mode 'show') 'edit' 'show')) as |targetRoute|}}
{{#if isV2}}
<ToolbarLink
@params={{array targetRoute model.id (query-params version=this.modelForData.version)}}
@data-test-secret-edit="true"
@replace={{true}}
@type="add"
>
Create new version
</ToolbarLink>
{{else}}
<ToolbarLink
@params={{array targetRoute model.id}}
@data-test-secret-edit="true"
@replace={{true}}
>
Edit secret
</ToolbarLink>
{{/if}}
{{/let}}
{{/if}}
</ToolbarActions>
</Toolbar>
{{#if (eq mode "create")}}
<form class="{{if showAdvancedMode 'advanced-edit' 'simple-edit'}}" onsubmit={{action "createOrUpdateKey" "create"}}>
<div class="field box is-fullwidth is-sideless is-marginless">
<NamespaceReminder @mode="create" @noun="secret" />
<MessageError @model={{modelForData}} @errorMessage={{error}} />
<label class="is-label" for="kv-key">Path for this secret</label>
<p class="control is-expanded">
<Input
@autocomplete="off"
@spellcheck="false"
data-test-secret-path="true"
@id="kv-key"
class="input {{if (get validationMessages 'path') "has-error-border"}}"
@value={{get modelForData modelForData.pathAttr}}
onkeyup={{perform waitForKeyUp "path" value="target.value"}}
/>
</p>
{{#if (get validationMessages 'path')}}
<AlertInline
@type="danger"
@message={{get validationMessages 'path'}}
@paddingTop=true
@isMarginless=true
/>
{{/if}}
{{#if modelForData.isFolder}}
<p class="help is-danger">
The secret path may not end in <code>/</code>
</p>
{{/if}}
</div>
<SecretEditDisplay
@showAdvancedMode={{showAdvancedMode}}
@codemirrorString={{codemirrorString}}
@secretData={{secretData}}
@isV2={{isV2}}
@model={{model}}
@canEditV2Secret={{canEditV2Secret}}
@editActions={{hash
codemirrorUpdated=(action "codemirrorUpdated")
formatJSON=(action "formatJSON")
handleKeyDown=(action "handleKeyDown")
handleChange=(action "handleChange")
deleteRow=(action "deleteRow")
addRow=(action "addRow")
}}
@onKeyUp={{perform waitForKeyUp}}
@validationMessages={{validationMessages}}
/>
<div class="field is-grouped box is-fullwidth is-bottomless">
<div class="control">
<button
type="submit"
disabled={{or buttonDisabled validationErrorCount}}
class="button is-primary"
data-test-secret-save=true
>
Save
</button>
</div>
<div class="control">
<SecretLink @mode="list" @secret={{model.parentKey}} @class="button">
Cancel
</SecretLink>
</div>
</div>
</form>
{{else if (eq mode "edit")}}
<form onsubmit={{action "createOrUpdateKey" "update"}}>
<div class="box is-sideless is-fullwidth is-marginless is-paddingless">
<MessageError @model={{modelForData}} @errorMessage={{error}} />
<NamespaceReminder @mode="edit" @noun="secret" />
{{#if (and (not model.failedServerRead) (not model.selectedVersion.failedServerRead) (not-eq model.selectedVersion.version model.currentVersion))}}
<div class="form-section">
<AlertBanner
@type="warning"
@class="is-marginless"
@message="You are creating a new version based on data from Version {{model.selectedVersion.version}}. The current version for {{model.id}} is Version {{model.currentVersion}}."
/>
</div>
{{/if}}
<SecretEditDisplay
@showAdvancedMode={{showAdvancedMode}}
@codemirrorString={{codemirrorString}}
@secretData={{secretData}}
@isV2={{isV2}}
@canEditV2Secret={{canEditV2Secret}}
@showWriteWithoutReadWarning={{isWriteWithoutRead}}
@model={{model}}
@editActions={{hash
codemirrorUpdated=(action "codemirrorUpdated")
formatJSON=(action "formatJSON")
handleKeyDown=(action "handleKeyDown")
handleChange=(action "handleChange")
deleteRow=(action "deleteRow")
addRow=(action "addRow")
}}
@onKeyUp={{perform waitForKeyUp}}
@validationMessages={{validationMessages}}
/>
</div>
<div class="field is-grouped is-grouped-split is-fullwidth box is-bottomless">
<div class="field is-grouped">
<div class="control">
<button
data-test-secret-save
type="submit"
disabled={{or buttonDisabled validationErrorCount}}
class="button is-primary"
>
Save
</button>
</div>
<div class="control">
<SecretLink @mode="show" @secret={{model.id}} @class="button" @queryParams={{query-params version=this.modelForData.version}}>
Cancel
</SecretLink>
</div>
</div>
</div>
</form>
{{else if (eq mode "show")}}
<SecretFormShow
@isV2={{isV2}}
@modelForData={{modelForData}}
@isWriteWithoutRead={{isWriteWithoutRead}}
@showAdvancedMode={{showAdvancedMode}}
/>
{{else}}
<EmptyState
@title="No secret view was selected"
/>
{{/if}}